Programming Challenges
Welcome to the programming.dev challenge community!
Three challenges will be posted every week to complete
- Tuesday (Easy)
- Thursday (Medium)
- Saturday (Hard)
Easy challenges will give 1 point, medium will give 2, and hard will give 3. If you have the fastest time or use the least amount of characters you will get a bonus point (in ties everyone gets the bonus point)
Exact duplicate solutions are not allowed and will not give you any points. Submissions on a challenge will be open for a week.
A leaderboard will be posted every month showing the top people for that month
- 8/8 test cases passed
- Time: 0.005s
- Characters: 530
C: gcc -O2 easy.c
In case formatting is messed up
#include
#include
void bail(char const *msg)
{
fputs(msg, stderr);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
int count = 0;
char *p, c = 0;
if (argc != 2) {
bail("Improper invocation.\n");
}
for (c = *(p = argv[1]); *p; p++) {
if (c == *p) {
count++;
} else {
printf("%c%d", c, count);
c = *p;
count = 1;
}
}
if (count) {
printf("%c%d", c, count);
}
putchar('\n');
return 0;
}
- 8/8 test cases passed
- Time taken: 0.003s
- Characters: 487
A true C hax0r puts everything in one line, and doesn't peform any sanity checks!
#include
int main(int argc, char **argv)
{
int count = 1, t;
char *p, c = 0;
for (char c = *(p = argv[1]); *p; p++, t=(c==*p), ((!t) ? printf("%c%d",c,count):0), count = t ? (count+1) : 1, c=t?c:*p);
return 0;
}
My broken brain just goes "but how would a decompressor know if '3101' was originally '30' or 101 '3's in a row?"
Bun, technically prints it to the console: throw[...Bun.argv[2].matchAll(/(.)+?(?!\1)/g)].map(([a,c])=>c+a.length).join("")
Breaks if there are more than 9 repeats or if you don't supply an argument.
- 8/8 test cases passed
- no runtime stats since I couldnt use the solution checker to check it (had to do manually)
- Characters: 84
Factor:
(command-line) last [ ] group-by [ length 48 + swap ] assoc-map "" concat-as print
Python:
import sys
input_string = sys.argv[1]
compressed_string = ''
last_letter = ''
letter_count = 0
for letter in input_string:
if letter != last_letter:
if last_letter != '':
compressed_string += last_letter + str(letter_count)
letter_count = 0
last_letter = letter
letter_count += 1
compressed_string += last_letter + str(letter_count)
print(compressed_string)
- 8/8 test cases passed
- time taken: 0.011s
- characters: 385
JavaScript (~~Deno~~Bun): bun easy.js aaabbhhhh33aaa
Golf attempt using RegExp to match homogenous substrings.
Original version
console.log(Deno.args[0].replace(/(.)\1*/g,a=>a[0]+(a.length+'')))
Slightly optimised by removing the frivolous conversion to string. I also made a somewhat silly opitmisation of using Bun.argv
instead of Deno.args
to save a character.
console.log(Bun.argv[2].replace(/(.)\1*/g,a=>a[0]+a.length))
- 8/8 test cases passed
- Time taken: 0.01s
- Characters: 60
Factor:
USING: kernel strings command-line namespaces math.parser sequences io ;
IN: l
: c ( s -- C )
"" swap
[ dup empty? not ] [
dup dup dup first '[ _ = not ] find drop
dup not [ drop length ] [ nip ] if
2dup tail
[ number>string [ first 1string ] dip append append ] dip
] while drop
;
MAIN: [ command-line get first c print ]
Benchmark using compiled binary:
$ hyperfine "./compress/compress aaabbhhhh33aaa"
Benchmark 1: ./compress/compress aaabbhhhh33aaa
Time (mean ± σ): 3.6 ms ± 0.4 ms [User: 1.4 ms, System: 2.2 ms]
Range (min … max): 3.0 ms … 6.0 ms 575 runs
- 8/8 test cases passed
- Time taken: 0.163 seconds
- Characters: 359
I ran it using factor.com -run (path to file)
If theres a better way let me know, first time using factor
Thanks! Yeah to use the optimized compiler to create a faster runnable binary, I've put instructions on the first challenge: https://programming.dev/comment/1980496
new time taken: 0.053 seconds
My solution (runs in O(n) time, but so do all the other solutions so far as far as I can tell):
from itertools import pairwise
def main(s: str) -> str:
characters = [None] + list(s) + [None]
transitions = []
for (_, left), (right_idx, right) in pairwise(enumerate(characters)):
if left != right:
transitions.append((right_idx, right))
repeats = [(stop - start, char) for (start, char), (stop, _) in pairwise(transitions)]
return ''.join(f'{char}{length}' for length, char in repeats)
if __name__ == '__main__':
from argparse import ArgumentParser
parser = ArgumentParser()
parser.add_argument('s')
print(main(parser.parse_args().s))
Runthrough:
'aaabb'
-> [None, 'a', 'a', 'a', 'b', 'b', None]
-> [(1, 'a'), (4, 'b'), (6, None)]
-> [(4 - 1, 'a'), (6 - 4, 'b')]
Golfed (just for fun, not a submission):
import sys
from itertools import pairwise as p
print(''.join(c+str(b-a)for(a,c),(b,_)in p([(i,r)for i,(l,r)in enumerate(p([None,*sys.argv[1],None]))if l!=r])))
- 8/8 test cases passed
- time taken: 0.191s
- characters: 566
Ruby, just because I wanted a bit more practice. Again, I went to lowering character count, so it is ugly. I'm just using a anchor-runner pointer strategy to do the work. I tried to think of a regex to do the work for me, but couldn't think of one that would work.
i=ARGV[0]
o=''
a=r=0
l=i.length
while l>a
r+=1
if r>l||i[a]!=i[r] then
o+=i[a]+(r-a).to_s
a=r
end
end
puts o