Python Recursion (Tower of Hanoi) - python

I'm new to python and experienced a problem that ist probably really easy to solve.
def req_steps(num_disks):
# implement this function
if num_disks == 0:
return 1
return 2 * req_steps(num_disks-1)
print("For moving {} disks, {} steps are required.".format(3, req_steps(3)))
The function should be (2^n)-1 and I can't get the -1 to work... It has to be a recursive function.
Thanks in advance.
Edit:
The ultimate formula is = (2^(num_of_disks))-1
this means, num_of_disks = 3 should give 7 which is (2*2*2-1) moves.

You may give the final answer f(n) = 2^n-1, which is a general fomula, while the question requests you to use the recurrence formula f(n) = f(n-1) + 1 + f(n-1) when n > 1.
def req_steps(num_disks):
if num_disks == 1:
return 1
else:
return 1 + 2 * req_steps(num_disks - 1)
print("For moving {} disks, {} steps are required.".format(3, req_steps(3)))
which outputs:
For moving 3 disks, 7 steps are required.
The below recurrence fomula means when you want to move n disks from A to C (Suppose the 3 rods placing disks are named A, B and C), you can:
move n-1 disks from A to B, which takes f(n-1) steps
move the nth disk from A to C, which takes 1 step
move the n-1 disks from B to C, which takes f(n-1) steps

It turns out the calculation is an upside down binary representation of the formula.
This code:
def req_steps(num_disks):
if num_disks <= 1:
return 1
return 2 * req_steps(num_disks - 1) + 1
for n in range(2,7):
print(n, req_steps(n))
produces:
2 3
3 7
4 15
5 31
6 63
The base case of num_disks==1 returns 1, but the previous recursion multiplies this by two, and adds 1. So as the recursion unfolds again it is producing a binary 1 in each binary digit place according to num_disks passed in by the original caller.

Related

Python: How can I divide a number completely by 2 and 3 and return -1 if not possible

I want to make a function where given a number like 7 I want to factorise the number by as many 3s and 2s. If left with a remainder then return -1.
Note: Through further examples it seems any number can be made up of the addition of multiples of 3s and 2s so -1 for remainder not needed. Goal is to get as many multiples of 3 before having to add multiples of 2 to factorise completely
For example given the number 11 I want the function to return 3:3 and 2:1 as 3 fits into 11 3 times and 2 once ie. 3+2+2=7, 3+3+3+2=11, 3+3+3+2+2=13. The preference should be being able to fit as many 3s first.
This is part of a wider problem:
from collections import Counter
#Choose two packages of the same weight
#Choose three packages of the same weight
#Minimum number of trips to complete all the deliveries else return -1
def getMinimumTrips(weights):
weights_counted = Counter(weights)
minimum_trips = 0
print(weights_counted)
for i in weights_counted:
if weights_counted[i]==1:
return -1
elif weights_counted[i]%3==0:
minimum_trips += (weights_counted[i]//3)
elif weights_counted[i]%2==0:
minimum_trips += (weights_counted[i]//2)
return minimum_trips
print(getMinimumTrips([2, 4, 6, 6, 4, 2, 4]))
Possible solution:
#Looking at inputs that are not a multiple of 3 or 2 eg, 5, 7, 11, 13
def get_components(n):
f3 = 0
f2 = 0
if n%3==1:
f3 = (n//3)-1
f2 = 2
elif n%3==2:
f3 = (n//3)
f2=1
return f"3:{f3}, 2:{f2}"
If we are given some integer value x we have 3 different cases:
x == 3 * n, solution: return 3 n times. The easiest case.
x == 3 * n + 1, solution: return 3 n - 1 times, then return 2 2 times, Note that we can put 3 * n + 1 == 3 * (n - 1) + 2 + 2
x == 3 * n + 2, solution: return 3 n times, then return 2.
As one can see in cases #1 and #3 solutions ever exist; in case #2 there's no solution for x = 1 (we can't return 3 -1 times). So far so good if x <= 1 we return -1 (no solutions), otherwise we perform integer division // and obtain n, then find remainder % and get the case (remainder 0 stands for case #1, 1 for case #2, 2 for case #3). Since the problem looks like a homework let me leave the rest (i.e. exact code) for you to implement.
This will return 0 if you can completely factorise the number, or -1 if 1 is remaining:
return -(i % 3 % 2)
If this helps?
Try this method using math.floor()
import math
def get_components(n: int) -> str:
q3 = math.floor(n / 3)
q2 = math.floor(q3 / 2)
if not (q3 and q2):
return '-1' # returning '-1' as a string here for consistency
return f'3:{q3}, 2:{q2}'

Improving performance of finding out how many possible triangles can be made with a given stick

I am doing an assessment that is asking by the given "n" as input which is a length of a stick; how many triangles can you make? (3 < n < 1,000,000)
For example:
input: N=8
output: 1
explanation:
(3,3,2)
input: N=12
output: 3
explanation:
(4,4,4) (4,5,3) (5,5,2)
Now the codes I wrote are returning 33 % accuracy as the web assessment is throwing time limit error.
ans = 0
n = int(input())
for a in range(1, n + 1):
for b in range(a, n - a + 1):
c = n - a - b
if a + b > c >= b:
ans += 1
print(ans)
code b:
ans = 0
n = int(input())
for i in range(1,n):
for j in range(i,n):
for c in range(j,n):
if(i+j+c==n and i+j>c):
ans+=1
print(ans)
How can this be made faster?
This is an intuitive O(n) algorithm I came up with:
def main():
n = int(input())
if n < 3:
print(0)
return
ans = n % 2
for a in range(2, n//2+1):
diff = n - a
if diff // 2 < a:
break
if diff % 2 == 0:
b = diff // 2
else:
b = diff // 2 + 1
b = max(b - a // 2, a)
c = n - b - a
if abs(b - c) >= a:
b += 1
c -= 1
ans += abs(b-c)//2 + 1
print(ans)
main()
I find the upper bound and lower bound for b and c and count the values in that range.
I thought of a completely different way to do it:
We take the smallest side and call it a. It can never be more than n/3, otherwise a different side would be the smallest.
We try to figure out what is the next smallest side (b):
We see what's left after reducing our a.
We divide it by 2 in order to find the middle where we'll start advancing from
We'll see how far we can get before the difference between the lengths is a (or the difference from the middle is a/2) as that's the minimum b side length that is possible and satisfies a+b>c. Basically, the second smallest side is a/2 less than the middle.
The smallest side is the maximum between our calculation or a, in caseb==a. b can never be lower than a as it violates our first rule that a is the smallest.
We figure out the difference from the middle and the smallest side. That's how many possible solutions we have for the other 2 sides.
Add everything together for every a and that's our solution.
The floor, ceil and % are fixes for when a is odd, the middle is .5, or +1 in case b+c is even, cause b==c is then possible.
Code:
import math
n = int(input("Enter a number: "))
total = 0
# a is the shortest side
for a in range(1, (n//3)+1):
length_left = n-a
middle_number = length_left/2
# Shortest potential side b where the distance between b and c is smaller than a (c-b < a)
b = middle_number-(math.ceil(a/2)-1)-((length_left % 2)/2)
# We calculate how far it is from the middle
max_distance_from_middle = middle_number - max(b, a)
# Add another 1 if the length is even, in case b==c
adding = math.floor(max_distance_from_middle) + (1 if length_left % 2 == 0 else 0)
total += adding
print(total)
Or in an ugly one-liner:
n = int(input("Enter a number: "))
print(sum(math.floor((n-a)/2 - max((n-a)/2 - math.ceil(a/2) + 1 - (((n-a) % 2)/2), a)) + 1 - ((n-a) % 2) for a in range(1, (n//3)+1)))
Alcuin's sequence expansion: O(1)
Alcuin's sequence [See: https://en.wikipedia.org/wiki/Alcuin%27s_sequence] is a series expansion of the polynomial below, where the nth coefficient corresponds to the nth answer, that is, the maximum amount of unique integer triangles with perimeter n.
The algorithmic implementation of this is simply a formula. The Online Encyclopaedia of Integer Sequences (OEIS) provides many formulas that achieve this, the simplest of which is:
round(n^2 / 48) (Even)
round((n+3)^2 / 48) (Odd)
[See: https://oeis.org/A005044]
This evidently has a constant time complexity, given that the only functions required are modulo 2, integer squared and round, each of which are constant time (under certain definitions).
Implementation
Expanded:
def triangles(n):
if n % 2 == 0:
return round(n ** 2 / 48)
else:
return round((n + 3) ** 2 / 48)
1-Liner:
def triangles(n): return round(n ** 2 / 48) if n%2==0 else round((n + 3) ** 2 / 48)
Or even:
def triangles(n): return round((n + 3 * n%2) ** 2 / 48)
Extra
No imports are needed.
As the OP questioned, why do we divide by 48? While I can't answer that explicitly, let's get an intuitive understanding. We are squaring numbers, so it is evidently going to expand greatly. By the time we get to 5, that would give 64 (8^2). So, there must be a constant (albeit a reciprocal) to restrict the growth of the parabola, thus the / 48.
When we graph the OP's method, it gives an alternating parabola. This explains why there is a back-and-forth with the +3 and +0.
https://mathworld.wolfram.com/AlcuinsSequence.html
import math
n = int(input())
print(round(n ** 2 / 48)) if n % 2 == 0 else print(round((n + 3)** 2 / 48))

Is ther any other way to get sum 1 to 100 with recursion?

I'm studing recursive function and i faced question of
"Print sum of 1 to n with no 'for' or 'while' "
ex ) n = 10
answer =
55
n = 100
answer = 5050
so i coded
import sys
sys.setrecursionlimit(1000000)
sum = 0
def count(n):
global sum
sum += n
if n!=0:
count(n-1)
count(n = int(input()))
print(sum)
I know it's not good way to get right answer, but there was a solution
n=int(input())
def f(x) :
if x==1 :
return 1
else :
return ((x+1)//2)*((x+1)//2)+f(x//2)*2
print(f(n))
and it works super well , but i really don't know how can human think that logic and i have no idea how it works.
Can you guys explain how does it works?
Even if i'm looking that formula but i don't know why he(or she) used like that
And i wonder there is another solution too (I think it's reall important to me)
I'm really noob of python and code so i need you guys help, thank you for watching this
Here is a recursive solution.
def rsum(n):
if n == 1: # BASE CASE
return 1
else: # RECURSIVE CASE
return n + rsum(n-1)
You can also use range and sum to do so.
n = 100
sum_1_to_n = sum(range(n+1))
you can try this:
def f(n):
if n == 1:
return 1
return n + f(n - 1)
print(f(10))
this function basically goes from n to 1 and each time it adds the current n, in the end, it returns the sum of n + n - 1 + ... + 1
In order to get at a recursive solution, you have to (re)define your problems in terms of finding the answer based on the result of a smaller version of the same problem.
In this case you can think of the result sumUpTo(n) as adding n to the result of sumUpTo(n-1). In other words: sumUpTo(n) = n + sumUpTo(n-1).
This only leaves the problem of finding a value of n for which you know the answer without relying on your sumUpTo function. For example sumUpTo(0) = 0. That is called your base condition.
Translating this to Python code, you get:
def sumUpTo(n): return 0 if n==0 else n + sumUpTo(n-1)
Recursive solutions are often very elegant but require a different way of approaching problems. All recursive solutions can be converted to non-recursive (aka iterative) and are generally slower than their iterative counterpart.
The second solution is based on the formula ∑1..n = n*(n+1)/2. To understand this formula, take a number (let's say 7) and pair up the sequence up to that number in increasing order with the same sequence in decreasing order, then add up each pair:
1 2 3 4 5 6 7 = 28
7 6 5 4 3 2 1  = 28
-- -- -- -- -- -- -- --
8 8 8 8 8 8 8 = 56
Every pair will add up to n+1 (8 in this case) and you have n (7) of those pairs. If you add them all up you get n*(n+1) = 56 which correspond to adding the sequence twice. So the sum of the sequence is half of that total n*(n+1)/2 = 28.
The recursion in the second solution reduces the number of iterations but is a bit artificial as it serves only to compensate for the error introduced by propagating the integer division by 2 to each term instead of doing it on the result of n*(n+1). Obviously n//2 * (n+1)//2 isn't the same as n*(n+1)//2 since one of the terms will lose its remainder before the multiplication takes place. But given that the formula to obtain the result mathematically is part of the solution doing more than 1 iteration is pointless.
There are 2 ways to find the answer
1. Recursion
def sum(n):
if n == 1:
return 1
if n <= 0:
return 0
else:
return n + sum(n-1)
print(sum(100))
This is a simple recursion code snippet when you try to apply the recurrent function
F_n = n + F_(n-1) to find the answer
2. Formula
Let S = 1 + 2 + 3 + ... + n
Then let's do something like this
S = 1 + 2 + 3 + ... + n
S = n + (n - 1) + (n - 2) + ... + 1
Let's combine them and we get
2S = (n + 1) + (n + 1) + ... + (n + 1) - n times
From that you get
S = ((n + 1) * n) / 2
So for n = 100, you get
S = 101 * 100 / 2 = 5050
So in python, you will get something like
sum = lambda n: ( (n + 1) * n) / 2
print(sum(100))

Algorithm to give shortest expression for one number in terms of another number

Heads up: apologies for my poor style, inefficient code, and general stupidity. I'm doing this purely out of interest. I have no delusions that I will become a professional programmer.
How would solve this problem (assuming it can be solved). To be clear you want to take in an int x and an int y and return some expression in terms of y that equals x. For example if I passed in 9 and 2 one of the shortest solutions (I'm pretty sure) would be ((2+2)x2)+(2/2) with 4 total operators. You can assume positive integers because that's what I'm doing for the most part.
I have found a fastish partial solution that returns a solution for whatever numbers, but usually not the smallest one. Here it is coded in python:
def re_express(n, a, expression):
if n==0:
print(expression)
else:
if a**a < n:
n -= a**a
expression += "+" + str(a) + "^" +str(a)
re_express(n, a, expression)
elif a*a < n:
n -= a*a
expression += "+" + str(a) + "*" + str(a)
re_express(n, a, expression)
elif a < n:
n -= a
expression += "+" + str(a)
re_express(n, a, expression)
else:
n -= 1
expression += "+" + str(a) + "/" + str(a)
re_express(n, a, expression)
I have also think I have one that returns a pretty small solution, but it is not guaranteed to be the smallest solution. I hand simulated it and it got the 2 and 9 example correct, whereas my first algorithm produced a 5 operator solution: 2^2+2^2+2/2. But it gets slow quickly for large n's. I wrote it down in pseudocode.
function re_express(n, a, children, root, solutions):
input: n, number to build
a, number to build with
children, an empty array
root, a node
solutions, an empty dictionary
if not root:
root.value = a
if the number of layers in the tree is greater than the size of the shortest solution, return the shortest solution
run through each mathematical operator and create a child node of root as long as the child will have a unique value
each child.value = operator(root, a)
for each child: child.parent = root
for each child: child.operator = operator as a string
loop through all children and check to see what number you need to produce n with each operator, if that number is in the list of children
when you find something like that then you have paths back up the tree, use the following loop for both children (obviously a child with only i
i = 0
while child != root:
expression += “(“ + str(a) + child.operator
child = child.parent
expression += str(a)
for in range(i):
expression += “)”
then you combine the expressions and you have one possible solution to add up to n and you have one possible answer
store the solution in solutions with the key as the number of operators used and the value as the expression in string form
re_express(n, a, children, root, solutions)
As you can tell the big-O for that algorithm is garbage and it doesn't even give a guaranteed solution, so there must be a better way.
We can use a variation of Dijkstra's algorithm to find the result. However, we don't really have a graph. If we consider numbers as nodes of the graph, then edges would start at a pair of nodes and an operation and end at another number. But this is just a detail that does not prevent Dijkstra's idea.
The idea is the following: We start with y and explore more and more numbers that we can express using a set of pre-defined operations. For every number, we store how many operations we need to express it. If we find a number that we have already seen (but the previous expression takes more operations), we update the number's attributes (this is the path length in Dijktra's terms).
Let's do the example x = 9, y = 2.
Initially, we can represent 2 with zero operations. So, we put that in our number list:
2: 0 operations
From this list, we now need to find the number with the least number of operations. This is essential because it guarantees that we never need to visit this number again. So we take 2. We fix it and explore new numbers that we can express using 2 and all other fixed numbers. Right now, we only have 2, so we can express (using + - * /):
2: 0 operations, fixed
0: 1 operation (2 - 2)
1: 1 operation (2 / 2)
4: 1 operation (2 + 2 or 2 * 2)
On we go. Take the next number with the least number of operations (does not matter which one). I'll take 0. We can't really express new numbers with zero, so:
2: 0 operations, fixed
0: 1 operation (2 - 2), fixed
1: 1 operation (2 / 2)
4: 1 operation (2 + 2 or 2 * 2)
Now let's take 1. The number of operations for new numbers will be the sum of the input numbers' number of operations plus 1. So, using 1, we could
2 + 1 = 3 with 0 + 1 + 1 = 2 operations (2 + (2 / 2))
0 + 1 = 1 with 3 operations --> the existing number of operations for `0` is better, so we do not update
1 + 1 = 2 with 3 operations
2 - 1 = 1 with 2 operations
0 - 1 = -1 with 3 operations *new*
1 - 2 = -1 with 2 operations *update*
1 - 0 = 1 with 3 operations
1 - 1 = 0 with 3 operations
2 * 1 = 2 with 2 operations
0 * 1 = 0 with 3 operations
1 * 1 = 1 with 3 operations
2 / 1 = 2 with 2 operations
0 / 1 = 0 with 3 operations
1 / 2 = invalid if you only want to consider integers, use it otherwise
1 / 0 = invalid
1 / 1 = 1 with 3 operations
So, our list is now:
2: 0 operations, fixed
0: 1 operation (2 - 2), fixed
1: 1 operation (2 / 2), fixed
3: 2 operations (2 + 2/2)
4: 1 operation (2 + 2 or 2 * 2)
-1: 2 operations (2/2 - 2)
Go on and take 4 and so on. Once you've reached your target number x, you are done in the smallest possible way.
In pseudo code:
L = create a new list with pairs of numbers and their number of operations
put (y, 0) into the list
while there are unfixed entries in the list:
c = take the unfixed entry with the least number of operations
fix c
if c = x:
finish
for each available operation o:
for each fixed number f in L:
newNumber = o(c, f)
operations = c.numberOfOperations + f.numberOfOperations + 1
if newNumber not in L:
add (newNumber, operations) to L
else if operations < L[newNumber].numberOfOperations:
update L[newNumber].numberOfOperations = operations
repeat for o(f, c)
If you store the operation list with the numbers (or their predecessors), you can reconstruct the expression at the end.
Instead of using a simple list, a priority queue will make the retrieval of unfixed entries with the minimum number of operations fast.
Here is my code for this problem which I don't think is the fastest and the most optimal algorithm, but it should always find the best answer.
First, let's assume we don't have parentheses and solve the subproblem for finding the minimum number of operations to convert a to n with these operations ['+', '*', '/', '-']. For solving this problem we use BFS. First we define an equation class:
class equation:
def __init__(self, constant, level=0, equation_list=None):
self.constant = constant
if equation_list != None:
self.equation_list = equation_list
else:
self.equation_list = [constant]
self.level = level
def possible_results(self):
return recursive_possible_results(self.equation_list)
def get_child(self, operation):
child_equation_list = self.equation_list + [operation]
child_equation_list += [self.constant]
child_level = self.level + 1
return equation(self.constant, child_level, child_equation_list)
The constructor gets a constant which is the constant in our expressions (here is a) and a level which indicates the number of operations used in this equation, and an equation_list which is a list representation of equation expression. For the first node, ( root ) our level is 0, and our equation_list has only the constant.
Now let's calculate all possible ways to parentheses an equation. We use a recursive function which returns a list of all possible results and their expressions:
calculated_expr = {}
def is_operation(symbol):
return (symbol in operations)
def recursive_possible_results(equation_list):
results = []
if len(equation_list) == 1:
return [{'val': equation_list[0], 'expr': str(equation_list[0])}]
key = ''
for i in range(len(equation_list)):
if is_operation(equation_list[i]):
key += equation_list[i]
if key in calculated_expr.keys():
return calculated_expr[key]
for i in range(len(equation_list)):
current_symbol = equation_list[i]
if is_operation(current_symbol):
left_results = recursive_possible_results(equation_list[:i])
right_results = recursive_possible_results(equation_list[i+1:])
for left_res in left_results:
for right_res in right_results:
try:
res_val = eval(str(left_res['val']) + current_symbol + str(right_res['val']))
res_expr = '(' + left_res['expr'] + ')' + current_symbol + '(' + right_res['expr'] + ')'
results.append({'val': res_val, 'expr': res_expr})
except ZeroDivisionError:
pass
calculated_expr[key] = results
return results
(I think this is the part of the code that needs to be more optimized since we are calculating a bunch of equations more than once. Maybe a good dynamic programming algorithm ...)
For Breadth-First-Search we don't need to explore the whole tree from the root. For example for converting 2 to 197, we need at least 7 operations since our biggest number with 6 operations is 128 and is still less than 197. So, we can search the tree from level 7. Here is a code to create our first level's nodes (equations):
import math
import itertools
def create_first_level(n, constant):
level_exprs = []
level_number = int(math.log(n, constant)) - 1
level_operations = list(itertools.product(operations, repeat=level_number))
for opt_list in level_operations:
equation_list = [constant]
for opt in opt_list:
equation_list.append(opt)
equation_list.append(constant)
level_exprs.append(equation(constant, level_number, equation_list))
return level_exprs
In the end, we call our BFS and get the result:
def re_express(n, a):
visit = set()
queue = []
# root = equation(a)
# queue.append(root)
# Skip levels
queue = create_first_level(n, a)
while queue:
curr_node = queue.pop(0)
for operation in operations:
queue.append(curr_node.get_child(operation))
possible_results = curr_node.possible_results()
for pr in possible_results:
if pr['val'] == n:
print(pr['expr'])
print('Number of operations: %d' % curr_node.level)
queue = []
break
re_express(9, 2)
Here is the output:
(((2)+(2))*(2))+((2)/(2))
Number of operations: 4

a function to count the step reaching 0

Given a binary number, I need to write a function to count the total steps reaching zero. The rules are:
If the number is even, divide it by 2
If the number is odd, subtract 1 from it
for example, it takes six iterations for "1110" (14) to become 0:
14 / 2 = 7
7 - 1 = 6
6 / 2 = 3
3 - 1 = 2
2 / 2 = 1
1 - 1 = 0
I have come up with a naive solution that does calculations, but this algorithm cannot handle numbers that are very large.
def test(x):
a = int(x,2)
steps = 0
while a != 0:
if a % 2 == 0:
a = a // 2
else:
a = a - 1
steps += 1
return steps
test("1000")
Out[65]: 4
test("101")
Out[66]: 4
test("001")
Out[67]: 1
test("0010010001")
Out[68]: 10
test("001001")
Out[69]: 5
what I need to know: How can I avoid doing the calculation and have an algorithm that is fast / can handle big numbers?
Assuming your code is correct and the rule is:
test(0) = 0
test(n) = 1 + test(n / 2) if n is even;
              1 + test(n − 1) otherwise
the important thing to notice is that:
an even number ends with a binary 0
dividing by 2 removes the 0 from the end (and nothing else)
an odd number ends with a binary 1
subtracting 1 turns the last 1 to a 0 (and nothing else)
So every 1 bit except for the first one adds 2 steps, and every significant 0 bit adds 1 step. That means for inputs that start with 1, you can write:
def test(x):
return x.count('1') + len(x) - 1
Now you just need to account for leading zeros, or just the specific case of "0" if leading zeros aren’t possible.
I had this question on a coding test today, I had 40 mins to complete the test. Unfortunately, I only came up with a good solution after the timer had reached the limit.
You do not need to calculate the divisions and the subtractions(!). You can iterate over the characters of S, if the character is a 1, two steps are required, if the character is a 0, only one step is required.
If there is a 1 at the end, you will subtract 1
If there is a 0 at the end, you can divide by two and the number will shift to the right.
The first character is an exception (S[0])
Here is the solution:
def iterate_string(S: str):
acc = 0
for c in S:
if c == "0":
acc += 1
else:
acc += 2
acc -= 1 # the very first 1 is only + 1, thus - 1
return acc
Here is an example:
1001 (17) - 1 = 1000 (16)
1000 (16) / 2 = 100 (8)
100 (8) / 2 = 10 (4)
10 (4) / 2 = 1
1 - 1 = 0
# First digit, requires two steps:
|
1001
# Second digit, requires one step:
|
1001
# Third digit, requires one step:
|
1001
# S[0] is 1, but requires only one step:
|
1001
=> total of 5 steps:
0: 1001 # (-1)
1: 1000 # (/2)
2: 100 # (/2)
3: 10 # (/2)
4: 1 # (-1)
5: 0
Good luck to the next person who is having the same challenge! :)
Here is the naive solution that can't handle big numbers:
def do_calculations(S: str):
decimal_value = int(S, 2)
iterations = 0
while decimal_value > 0:
if decimal_value % 2 == 1:
decimal_value = decimal_value - 1
else:
decimal_value = decimal_value / 2
iterations += 1
return iterations
Your algorithm isn't correct for odd numbers. You are only dividing when the number is even, which is not how you described the "steps."
you want
def test(x, 2):
x_int = int(x)
steps = 0
while x_int <= 0:
x_int //= 2
x -= 1
steps += 1
You should clarify your algorithm, because the way you described it, you're not guaranteed to converge to 0 for all inputs. The way you described it is an infinite loop for odd numbers. Just try 1:
#test(1)
1 // 2 = 0
0 - 1 = -1
...
Now you will never get to 0, which is why you should check for x_int <= 0.
I suggest you reconsider why you want to do this anyway. I'm fairly certain that you don't even need an iterative algorithm to know how many "steps" are required anyway, there should just be a mathematical formula for this.
You could also use a recursive approach:
def stepsToZero(N):
return N if N < 2 else 2 + stepsToZero(N//2-1)
This will get you results up to N = 2**993 (which is quite a big number) with a very concise (and imho more elegant) function.
What would run much faster would be to solve this mathematically
For example:
import math
def steps2Zero(N):
if N < 2: return N
d = int(math.log(N+2,2))-1
s = int(N >= 3*2**d-2)
return 2*d+s
Note that, for N=2^900, the mathematical solution is a hundred times faster than the recursion. On the other hand, the recursive function responds in well under a second and is a lot more readable. So, depending on how this would be used and on what size numbers, performance considerations are likely pointless
If the input number is in binary (or convert the input number to binary) then implement this function simply
def solution(s): # 's' should be a binary input (011100)
while s[0] == "0":
s = s[1:]
ones = s.count('1')
zeros = s.count('0')
return ones*2+zeros-1

Categories