Python Golfing: HackerEarth Edition

Nishant Arora 18/Jul/2014
Facebook
Twitter
LinkedIn
Reddit

I was going through my hackerearth profile and in the recomended problem section I came accross this problem named Minimal Combinatorial. The problem in itself is very simple, you just need to calculate nCr (BTW, nCr = n!/(r!*(n-r)!), combinatorics 101), but the catch is, you need to write a code (in your favourite language, of course!) which takes the minimum number of characters. The score of a code is calculated as:

score = (1000 - characters) * 10

Simply put, the source code with character count == 0, has score 100, which is impossible. The highest score I could locate was 92.6 (Ruby), which means the entire code was written in 74 characters (pretty impressive I say). But I do not speak ruby, let's try with Python.

Initial Code (Just for understanding)[216 chars]:

def factorial(num):
  if num == 1:
    return 1
  return num * factorial(num - 1)

cases = int(raw_input())
for i in xrange(cases):
  n,r = map(int, raw_input().split())
  print factorial(n)/(factorial(r) * factorial(n-r))

Initial Iteration (original submission)[152 chars]:

Just using the standard libraries instead of custom function and getting rid of long names and spaces.

def f(n):
 import math
 return math.factorial(n)
c = int(raw_input())
for i in xrange(c):
 n,r = map(int, raw_input().split())
 print f(n)/(f(r)*f(n-r))

2nd Iteration [152 chars]:

No character improvements, but using lambda function

def f(n):return reduce(lambda x,y:x*y,[1]+range(1,n+1))
for i in xrange(int(raw_input())):
 n,r=map(int,raw_input().split())
 print (f(n)/(f(r)*f(n-r)))

3rd Iteration [150 chars]:

re-writing the 1st iteration

def f(n,r):
 import math
 z=math.factorial
 return z(n)/z(r)/z(n-r)
for i in xrange(int(raw_input())):
 n,r=map(int,raw_input().split())
 print f(n,r)

4th Iteration [148 chars]:

tweaking the for loop

def f(n,r):
 import math
 z=math.factorial
 return z(n)/z(r)/z(n-r)
for i in [1]*(int(raw_input())):
 n,r=map(int,raw_input().split())
 print f(n,r)

5th Iteration [138 chars]:

getting rid of empty lines for good.

def f(n,r):import math;z=math.factorial;return z(n)/z(r)/z(n-r)
for i in[1]*int(raw_input()):n,r=map(int,raw_input().split());print f(n,r)

6th Iteration [113 chars]:

merging the function in the loop.

for i in[1]*int(raw_input()):n,r=map(int,raw_input().split());import math;z=math.factorial;print z(n)/z(r)/z(n-r)

7th Iteration [109 chars]:

the raw_input for i is not actually needed, just input() can be used, as there would be just one integer to be read.

for i in[1]*int(input()):n,r=map(int,raw_input().split());import math;z=math.factorial;print z(n)/z(r)/z(n-r)

8th Iteration [107 chars]:

the math module was just too messy. Using lambda function instead. however, it won't deal when number=0. But we do not need that anyways.

for i in[1]*int(input()):n,r=map(int,raw_input().split());z=lambda n:n<2 or n*z(n-1);print z(n)/z(r)/z(n-r)

9th Iteration [106 chars]:

minor iterations with the writing style, (check the 'or'), still the for loop takes a lot of space. :(

for i in[1]*int(input()):n,r=map(int,raw_input().split());z=lambda n:n<2or n*z(n-1);print z(n)/z(r)/z(n-r)

10th Iteration [101 chars]:

I can of course assign raw_input to a variable and use it instead. Also, the entire statement can be put inside the exec() and multiplied by the cases, a neat implementation of for loop.

p=raw_input;exec"n,r=map(int,p().split());z=lambda n:n<2or n*z(n-1);print z(n)/z(r)/z(n-r);"*int(p())

So, Finally, my score: 89.90

The best I could achieve is 101 characters with python. But the other guy has it 74 characters in ruby. Maybe ruby is more concise, but this is the most Pythonic solution I could achieve. Please drop in your comments and help me make it even more concise. (If Possible.. :P)

Cheers!

Happy Hacking