how to understand this recursion algorithm - python

def sum(a):
if a==1:
s=1
else:
s=1+2*sum(a-1)
return s
function:calculate the sum of the sequence of number. Its common ratio is 2, last term is 2^( a-1) and first term is 1.
Why does it use s=1+2*sum(a-1) to implement the function?

def sum1(a):
if a==1:
s=1
else:
s=1+2*sum1(a-1)
return s
What this function does, let's take a=4.
(1) s = 1 + 2*sum1(4-1) = 1 + 2*sum1(3) = 1 + 2*s2
(2) s2 = 1 + 2*sum1(3-1) = 1 + 2*sum1(2) = 1 + 2*s3
(3) s3 = 1 + 2*sum(2-1) = 1 + 2*sum(1) = 1 + 2*s4 = 1+2 = 3
Going BackWard : (3 * 2 + 1 ) * 2 + 1 = (7) * 2 + 1 = 15
Do it for bigger numbers, you will notice that this is the formula of 2^a - 1.
Print 2^a and 2^a - 1
Difference: (4, 3)
Difference: (8, 7)
Difference: (16, 15)
Difference: (32, 31)
Difference: (64, 63)
Difference: (128, 127)
Difference: (256, 255)

#Zhongyi I'm understanding this question as asking "how does recursion work."
Recursion exists in Python, but I find it a little difficult to explain how it works in Python. Instead I'll show how this works in Racket (a Lisp dialect).
First, I'lll rewrite yoursum provided above into mysum:
def yoursum(a):
if a==1:
s=1
else:
s=1+2*yoursum(a-1)
return s
def mysum(a):
if a == 1:
return 1
return 1 + (2 * mysum(a - 1))
for i in range(1, 11):
print(mysum(i), yoursum(i))
They are functionally the same:
# Output
1 1
3 3
7 7
15 15
31 31
63 63
127 127
255 255
511 511
1023 1023
In Racket, mysum looks like this:
#lang racket
(define (mysum a)
(cond
((eqv? a 1) 1)
(else (+ 1 (* 2 (mysum (sub1 a)))))))
But we can use language features called quasiquoting and unquoting to show what the recursion is doing:
#lang racket
(define (mysum a)
(cond
((eqv? a 1) 1)
(else `(+ 1 (* 2 ,(mysum (sub1 a))))))) ; Notice the ` and ,
Here is what this does for several outputs:
> (mysum 1)
1
> (mysum 2)
'(+ 1 (* 2 1))
> (mysum 3)
'(+ 1 (* 2 (+ 1 (* 2 1))))
> (mysum 4)
'(+ 1 (* 2 (+ 1 (* 2 (+ 1 (* 2 1))))))
> (mysum 5)
'(+ 1 (* 2 (+ 1 (* 2 (+ 1 (* 2 (+ 1 (* 2 1))))))))
You can view the recursive step as substituting the expression (1 + 2 * rest-of-the-computation)
Please comment or ask for clarification if there are parts that still do not make sense.

Formula Explanation
1+2*(sumOf(n-1))
This is not a generic formula for Geometric Progression.
this formula is only valid for the case when ratio is 2 and first term is 1
So how it is working.
The Geometric Progression with first term = 1 and r = 2 will be
1,2,4,6,8,16,32,64
FACT 1
Here you can clearly see nth term is always equals to sumOf(n-1) terms + 1
Let declare an equation from fact 1
n = sumOf(n-1) + 1 =======> Eq1.
Let put our equation to test
put n = 2 in Eq1
2 = sumOf(2-1) + 1
we know that sumOf(1) is 1 then
2 = 2 ==> proved
so if n = sumOf(n-1)+1 then
FACT 2
Sum of n term is n term + sum(n-1) terms
Lets declare an Equation from FACT 2
sumOf(n) = sumOf(n-1) + n ==> eq2
let us put eq1 in eq2 i.e. n = sumOf(n-1) + 1
sumOf(n) = sumOf(n-1) + sumOf(n-1) + 1 ==> eq3
Simplifying
sumOf(n) = 2 * sumOf(n-1) + 1
Rearranging
sumOf(n) = 1 + 2 * sumOf(n-1) ==> final Equation
Now Code this equation
we know sumOf 1st term is alway 1 so, this is our base case.
def sumOf(a):
if a==1:
return 1
so now sum of first n terms will be 1 + 2 * sumOf(n-1) ==> From final Equation
put this equation in else part
def sumOf(a):
if a==1:
return 1
else:
return 1 + 2 * sumOf(a-1)

Related

I am .5 off when trying to figure this out

x = 1 / 2 + 3 // 3 + 4 ** 2 # Why is this equivalent to 17?
y = 1 / 2 + 3 # This is equivalent to 3.5
z = 1 / 2 + 3 // 3 # This should be equivalent to 3.5 // 3
t = 3.5 // 3 + 4 ** 2 # Why is this 17 but the original statement is 17.5?
Why are the expressions for t and x providing different results? Are they not equivalent?
(Original image)
It's 17.5 because your statement is as follows:
1/2 - this is evaluated to 0.5
3 // 3 - this is evaluated to 1
4 ** 2 - this is evaluated to 16
16 + 1 + 0.5 = 17.5
You need to understand the order of operations in your initial statement:
1 / 2 + 3 // 3 + 4 ** 2
This can be bracketed according to standard order of operations (BODMAS or some variant):
(1 / 2) + (3 // 3) + (4 ** 2)
Which then evaluates as above. Your confusion stems from the fact that 1 / 2 + 3 // 3 is not equivalent to (1/2 + 3) // 3, but instead equivalent to (1/2) + (3 // 3) - they're both division, so they'll both take precedence over the addition operator.

Order of operations for Python 2.7

Teaching myself coding, what is the order of operations for this line of code?
print 3 + 2 + 1 - 5 + 4 % 2 - 1 / 4 + 6
I attempted to do remainder and division first so I got 3 + 2 + 1 - 5 + 0 - 0.25 / 4 + 6. Then I completed AS from left to right and got 0.075. Totally wrong because LPTHW puts it at 7. Please offer detailed operation order.
I Googled Python order of operation, but results are not too instructively detailed.
print 3 + 2 + 1 - 5 + 4 % 2 - 1 / 4 + 6
Expected result is 7, but obtained 0.075
It depends on which Python version you are using.
In Python 2, the / operator defaults to integer division, so 1 / 4 == 0.
On the other hand, in Python 3, the / operator defaults to true division, so 1 / 4 == 0.25. You must use // to achieve integer division in Python 3.
Regardless, Python still follows the classical PEMDAS order of operations, so the modulus and division still happen first, followed by addition and subtraction from left to right.
Here's how the problem reduces after you do the modulus and division in both versions:
Python 2
(3 + 2 + 1 - 5 + 0 - 0 + 6) == 7
Python 3
(3 + 2 + 1 - 5 + 0 - 0.25 + 6) == 6.75
*, /, //, % have higher precedence than + and -. So you should first calculate 4 % 2 = 0 and 1 / 4 = 0 (in Python 2.7), and then do the rest of the calculation from left to right.
In Python 2, / uses integer division if both its arguments are integers. That means that 1/4 == 0, since integer division will round down. Then:
= 3 + 2 + 1 - 5 + 4 % 2 - 1 / 4 + 6 
= 3 + 2 + 1 - 5 + 0 - 0 + 6
= 7
To get 6.75 in Python 2 (the expected answer when done on paper), make one of the operands a float:
>> 3 + 2 + 1 - 5 + 4 % 2 - 1.0 / 4 + 6
# ^
>> 6.75
This isnt necessary in Python 3 because / defaults to returning a float.

Control of the combinatorial aspects of a dynamic programming solution

I am exploring how a Dynamic Programming design approach relates to the underlying combinatorial properties of problems.
For this, I am looking at the canonical instance of the coin exchange problem: Let S = [d_1, d_2, ..., d_m] and n > 0 be a requested amount. In how many ways can we add up to n using nothing but the elements in S?
If we follow a Dynamic Programming approach to design an algorithm for this problem that would allow for a solution with polynomial complexity, we would start by looking at the problem and how it is related to smaller and simpler sub-problems. This would yield a recursive relation describing an inductive step representing the problem in terms of the solutions to its related subproblems. We can then implement either a memoization technique or a tabulation technique to efficiently implement this recursive relation in a top-down or a bottom-up manner, respectively.
A recursive relation could be the following (Python 3.6 syntax and 0-based indexing):
def C(S, m, n):
if n < 0:
return 0
if n == 0:
return 1
if m <= 0:
return 0
count_wout_high_coin = C(S, m - 1, n)
count_with_high_coin = C(S, m, n - S[m - 1])
return count_wout_high_coin + count_with_high_coin
However, when drawing the sub-problem DAG, one can see that any DP-based algorithm implementing this recursive relation would yield a correct amount of solutions but disregarding the order.
For example, for S = [1, 2, 6] and n = 6, one can identify the following ways (assumming order matters):
1 + 1 + 1 + 1 + 1 + 1
2 + 1 + 1 + 1 + 1
1 + 2 + 1 + 1 + 1
1 + 1 + 2 + 1 + 1
1 + 1 + 1 + 2 + 1
1 + 1 + 1 + 1 + 2
2 + 2 + 1 + 1
1 + 2 + 2 + 1
1 + 1 + 2 + 2
2 + 1 + 2 + 1
1 + 2 + 1 + 2
2 + 1 + 1 + 2
2 + 2 + 2
6
Assumming order does not matter, we could count the following solutions:
1 + 1 + 1 + 1 + 1 + 1
2 + 1 + 1 + 1 + 1
2 + 2 + 1 + 1
2 + 2 + 2
6
When approaching a problem solution from the Dynamic Programming standpoint, how can I control the order? Specifically, how could I write functions:
count_with_order()
count_wout_order()
?
Could it be that the need for order mattering implies choosing pruned backtracking over a Dynamic Programming approach?
Each problem is idiosyncratic, although there may be some problems that could be grouped together. For your particular example, a count where order matters could be implemented (either recursed or tabulated) by considering that the number of solutions for n is equal to the total of solutions achievable from each lower achievable number, that is n - coin for each denomination.
Python code:
def f(n, coins):
if n < 0:
return 0
if n == 0:
return 1
return sum([f(n - coin, coins) for coin in coins])
# => f(6, [1, 2, 6]) # 14

Efficient way to find sum of digits of an entire sequence

In the following code snippet I am finding the sum of digits of all odd number between the interval [a,b]
def SumOfDigits(a, b):
s = 0
if a%2 == 0:
a+=1
if b%2 == 0:
b-=1
for k in range(a,b+1,2):
s+= sum(int(i) for i in list(str(k)))
return s
Is there an efficient way to accomplish the same?
Any patterns, which is leading to a clear cut formula.
I did search in https://oeis.org
Avoid all the overhead of conversion to and from strings and work directly with the numbers themselves:
def SumOfDigits(a, b):
result = 0
for i in range(a + (not a % 2), b + 1, 2):
while i:
result += i % 10
i //= 10
return result
Of course there is a pattern. Let's look at the problem of summing up the digitsums of all – odd and even – numbers between a and b inclusively.
For example: 17 to 33
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
The middle section gives you the sum of all digits from 0 to 9 (45) plus ten times 2. The left section is 7 + 8 + 9 plus three times 1 and the right the sum of 0 + 1 + 2 + 3 plus four times 3.
The middle section can comprise several blocks of ten, for example if you calculate the range between 17 and 63, you get 40 times 45 plus ten simes the the digitsums from 2 to 5.
This gives you a recursive algorithm:
def ssum(n):
return n * (n + 1) // 2
def dsum(a, b):
res = 0
if a == b:
while a:
res += a % 10
a //= 10
elif a < b:
aa = a // 10
bb = b // 10
ra = a % 10
rb = b % 10
if aa == bb:
res += ssum(rb) - ssum(ra - 1)
res += (rb - ra + 1) * dsum(aa, bb)
else:
if ra > 0:
res += 45 - ssum(ra - 1)
res += (10 - ra) * dsum(aa, aa)
aa += 1
if rb < 9:
res += ssum(rb)
res += (rb + 1) * dsum(bb, bb)
bb -= 1
if aa <= bb:
res += 45 * (bb - aa + 1)
res += 10 * dsum(aa, bb)
return res
Now let's extend this to include only odd numbers. Adkust a so that it is even and b so that it is odd. Your sum of digit sums now runs over pairs of even and odd numbers, where even + 1 == odd. That means that the digitsum of the odd number id one more than the even number, because all except the last digits are the same and the last odd digit is one more than the even digit.
Therefore:
dsum(a, b) == oddsum + evensum
and:
oddsum - evensum == (b - a + 1) // 2
The function to sum the digitsums of all odd numbers is then:
def oddsum(a, b):
if a % 2: a -= 1
if b % 2 == 0: b -= 1
d = (b - a + 1) // 2
return (dsum(a, b) + d) // 2
When I looked at your comment about OEIS, I've noticed that the algorithm can probably be simplified by writing a function to sum the digits from all numbers from zero to n and then calculate the difference dsum(b) - dsum(a). There are probably more opportunities for optimisation.

Python: what's wrong with my nested loop?

Using the while loop, I wrote a procedure that takes as input a positive whole number, and prints out a multiplication table showing all the whole number multiplications up to and including the input number. The order in which the equations are printed matters.
for example, print_multiplication_table(2) gives:
1 * 1
1 * 2
2 * 1
2 * 2
This is my code:
def print_multiplication_table(n):
a = 1
b = 1
while a <= n:
while b <= n:
print str(a) + " * " + str(b)
b = b + 1
a = a + 1
However, this doesn't seem to work as it only print out
1 * 1
1 * 2
Does anyone know why? thanks!
You need to initialize counter for inner loop before its execution
def print_multiplication_table(n):
a = 1
b = 1 # won't do harm, but doesn't really need now
while a <= n:
b = 1 # <-- note
while b <= n:
print str(a) + " * " + str(b)
b = b + 1
a = a + 1
Consider using for in place of while:
def print_multiplication_table(n):
for a in range(1, n+1):
for b in range(1, n+1):
print str(a) + " * " + str(b)
which gives:
1 * 1
1 * 2
2 * 1
2 * 2
Using for will automatically keep track of your counter variables and avoid the type of error you encountered (this of course doesn't mean you can't make errors with for-loops, but it's easier to avoid the type of error you had)
Easier still with a Python comprehension:
>>> print '\n'.join('{} * {}'.format(a,b) for a in range(1,6) for b in range(1,6))
1 * 1
1 * 2
1 * 3
1 * 4
1 * 5
2 * 1
# etc...
Or, if you want the terminal new line:
>>> gen=('{} * {}'.format(a,b) for a in range(1,6) for b in range(1,6))
>>> print '\n'.join(gen),'\n'
I used a separate gen expression just to more clear about the print with the comma. This also works:
>>> print '\n'.join('{} * {}'.format(a,b) for a in range(1,6) for b in range(1,6)),'\n'
There is no reason to do an explicit call to str in your code. If you don't, you can still use a and b as integers:
>>> gen=('{} * {} = {:2}'.format(a,b,a*b) for a in range(1,3) for b in range(1,4))
>>> print '\n'.join(gen),'\n'
1 * 1 = 1
1 * 2 = 2
1 * 3 = 3
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6

Categories

Resources