def geo():
start = int(input()) # starting number
multiplier = int(input()) # the multiplier
length = int(input()) # how long the list should be
for i in range(length):
x = start * multiplier ** i
print(x, "", end = "")
print()
I need to create a recursive geometric function based off user input. I know how to approach it non-recursively but how do I approach it recursively? Thanks in advance.
i.e: if the user inputs
start = 1
multiplier = 2
length = 5
Output: 1, 2, 4, 8, 16
Edit: thanks for all the examples guys, I understand how recursion a lot better now.
Remove the for loop.
Instead of it call the function recursively with a decrement in the argument.
Create a function with an integer as parameter and call it every time until a condition is met.
def geo(start, multiplier, length, i=0):
if length <= 0:
exit() #or use a return statement
x = start * multiplier ** i
print(x, "", end = "")
print()
geo(start, multiplier, length-1, i+1)
start = int(input())
multiplier = int(input())
length = int(input())
i=0
geo(start, multiplier, length, i)
Assuming you have a loop that you want to turn into a recursive function:
for i in range(length):
x = start * multiplier ** i
what you need to do is:
have a stop condition (i < length)
if stop condition is not met -> call again with the next value
do this before the function, because you'll need this value
length = int(input()) # how long the list should be
start = int(input()) # starting number
multiplier = int(input()) # the multiplier
def recursive_geo(i):
# stop condition
if i == length:
return 1 # since the value will be multiplied by the previous values, you don't want to use 0 or any other value
else:
print(x, "", end = "")
print()
return start * multiplier ** i * recursive_geo(i+1)
With any recursive function you need a base case and a general (recursion) case.
Let's start with your current code to get the inputs, but instead of calculating the value immediately we'll call a recursive function.
def geo():
start = int(input()) # starting number
multiplier = int(input()) # the multiplier
length = int(input()) # how long the list should be
result = geo_rec(start, multiplier, length)
print(result)
def geo_rec(start, multiplier, length):
print(start) # As per your current program
# Base case check
if length = 0:
return start
# Recursive case
else:
start = start * multiplier
length = length - 1
geo_rec(start, multiplier, length)
Now consider, if length is 0 what will we get? We will just get start - that's good. If length = 1, we'll recurse one level, and then return start (which by this point will be our original start * multiplier) - also good.
Notice with each run of the recursive case we work our way progressively to the base case?
Related
I am trying to solve a problem where recursion is a must. The tasks is: Write a function that takes in an integer n and returns the highest integer in the corresponding Collatz sequence.
My solution is this:
collatz = []
def max_collatz(num):
collatz.append(num)
if num == 1:
return max(collatz)
else:
return max_collatz(num / 2) if num%2 == 0 else max_collatz((3 * num) + 1)
However, I need to find a way to solve it without using a list outside of the function. I really couldn't find a solution, is there any?
It's either the current number or the largest in the rest of the sequence.
def max_collatz(n):
if n == 1:
return 1
elif n % 2:
return max_collatz(3 * n + 1)
else:
return max(n, max_collatz(n // 2))
I want to check if a given number can be formed by another number say b and reverse(b). For example 12 == 6+6, 22 == 11 + 11 and 121 == 29+92. One thing I have figured out is if the number is multiple of 11 or it is an even number less than 20, then it can be formed. I tried to implement this below:
num = 121
if num%11==0:
print('Yes')
else:
if num%2==0 and num<20:
print('Yes')
else:
for j in range(11,(int(num)//2)+1):
if j+int(str(j)[::-1])==num:
print('Yes')
break
However, if the condition goes into the for loop, it gives TLE. Can any other conditions be given?
Update: If the reversed number has trailing zeroes, it should be removed and then added. For example: 101 == 100+1. I am looking for an optimized form of my code. Or I think I am missing some conditions which can take O(1) time, similar to the condition if num%11==0: print('Yes')
All the previous answers are not really a check. It's more a brute force try and error.
So let's do it a little bit smarter.
We start with a number, for example 246808642. we can reduce the problem to the outer 2 place values at the end and start of the number. Let us call this values A and B at the front and Y and Z on the back. the rest, in the middle, is Π. So our number looks now ABΠYZ with A = 2, B = 4, Π = 68086, Y = 4 and Z = 2. (one possible pair of numbers to sum up for this is 123404321). Is A equal to 1, this is only possible for a sum greater 10 (An assumption, but i guess it works, some proof would be nice!).
so if it is a one, we know that the second last number is one greater by the carry over. So we ignore A for the moment and compare B to Z, because they should be the same because both are the result of the addition of the same two numbers. if so, we take the remaining part Π and reduce Y by one (the carry over from the outer addition), and can start again at the top of this chart with Π(Y-1). Only a carry over can make B one bigger than Z, if it's so, we can replace B by one and start with 1Π(Y-1) at the top. B-1!=Z and B!=Z, we can stop, this isnt possible for such a number which is the sum of a number and its reversed.
If A != 1, we do everything similiar as before but now we use A instead of B. (I cut this here. The answer is long enough.)
The code:
import time
def timing(f):
def wrap(*args, **kwargs):
time1 = time.time()
ret = f(*args, **kwargs)
time2 = time.time()
print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))
return ret
return wrap
#timing
def check(num):
num = str(num)
if (int(num) < 20 and int(num)%2 == 0) or (len(num) ==2 and int(num)%11 == 0):
return print('yes')
if len(num) <= 2 and int(num)%2 != 0:
return print('no')
# get the important place values of the number x
A = num[0]
B = num[1]
remaining = num[2:-2]
Y = num[-2]
Z = num[-1]
# check if A = 1
if A == '1':
# A = 1
# check if B == Z
if B == Z:
# so the outest addition matches perfectly and no carry over from inner place values is involved
# reduce the last digit about one and check again.
check(remaining + (str(int(Y)-1) if Y != '0' else '9'))
elif int(B)-1 == int(Z):
# so the outest addition matches needs a carry over from inner place values to match, so we add to
# to the remaining part of the number a leading one
# we modify the last digit of the remaining place values, because the outest had a carry over
check('1' + remaining + (str(int(Y)-1) if Y != '0' else '9'))
else:
print("Not able to formed by a sum of a number and its reversed.")
else:
# A != 1
# check if A == Z
if A == Z:
# so the outest addition matches perfectly and no carry over from inner place values is involved
check(B + remaining + Y)
elif int(A) - 1 == int(Z):
# so the outest addition matches needs a carry over from inner place values to match, so we add to
# to the remaining part of the number a leading one
# we modify the last digit of the remaining place values, because the outest had a carry over
check('1' + B + remaining + Y)
else:
print("Not able to formed by a sum of a number and its reversed.")
#timing
def loop_check(x):
for i in range(x + 1):
if i == int(str(x - i)[::-1]) and not str(x - i).endswith("0"):
print('yes, by brute force')
break
loop_check(246808642)
check(246808642)
Result:
yes, by brute force
loop_check function took 29209.069 ms
Yes
check function took 0.000 ms
And another time we see the power of math. Hope this work for you!
You can brute force it like this:
def reverse_digits(n):
return int(str(n)[::-1])
def sum_of_reversed_numbers(num):
for i in range(num + 1):
if i == reverse_digits(num - i):
return i, num - i
return None
print("Yes" if sum_of_reversed_numbers(num) else "No")
Can you provide the constraints of the problem?
Here is something you can try:
i = 0
j = num
poss = 0
while(i<=j):
if(str(i)==str(j)[::-1]):
poss = 1
break
i+=1
j-=1
if(poss):
print("Yes")
else:
print("No")
You can do it without str slicing:
def reverse(n):
r = 0
while n != 0:
r = r*10 + int(n%10)
n = int(n/10)
return r
def f(n):
for i in range(n + 1):
if i + reverse(i) == n:
return True
return False
print('Yes' if f(101) else 'No')
#Yes
The basic idea of my solution is that you first generate a mapping of digits to the digits that could make them up, so 0 can be made by either 0+0 or 1+9, 2+8 etc. (but in that case there's a carried 1 you have to keep in mind on the next step). Then you start at the smallest digit, and use that code to check each possible way to form the first digit (this gives you candidates for the first and last digit of the number that sums with its reverse to give you the input number). Then you move on the second digit and try those. This code could be greatly improved by checking both the last and the first digit together, but it's complicated by the carried 1.
import math
candidates = {}
for a in range(10):
for b in range(10):
# a, b, carry
candidates.setdefault((a + b) % 10, []).append((a, b, (a + b) // 10))
def sum_of_reversed_numbers(num):
# We reverse the digits because Arabic numerals come from Arabic, which is
# written right-to-left, whereas English text and arrays are written left-to-right
digits = [int(d) for d in str(num)[::-1]]
# result, carry, digit_index
test_cases = [([None] * len(digits), 0, 0)]
if len(digits) > 1 and str(num).startswith("1"):
test_cases.append(([None] * (len(digits) - 1), 0, 0))
results = []
while test_cases:
result, carry, digit_index = test_cases.pop(0)
if None in result:
# % 10 because if the current digit is a 0 but we have a carry from
# the previous digit, it means that the result and its reverse need
# to actually sum to 9 here so that the +1 carry turns it into a 0
cur_digit = (digits[digit_index] - carry) % 10
for a, b, new_carry in candidates[cur_digit]:
new_result = result[::]
new_result[digit_index] = a
new_result[-(digit_index + 1)] = b
test_cases.append((new_result, new_carry, digit_index + 1))
else:
if result[-1] == 0 and num != 0: # forbid 050 + 050 == 100
continue
i = "".join(str(x) for x in result)
i, j = int(i), int(i[::-1])
if i + j == num:
results.append((min(i, j), max(i, j)))
return results if results else None
We can check the above code by pre-calculating the sums of all numbers from 0 to 10ⁿ and their reverse and storing them in a dict of lists called correct (a list because there's many ways to form the same number, eg. 11+11 == 02 + 20), which means we have the correct answers for 10ⁿ⁻¹ we can use to check the above function. Btw, if you're doing this a lot with small numbers, this pre-calculating approach is faster at the expense of memory.
If this code prints nothing it means it works (or your terminal is broken :) )
correct = {}
for num in range(1000000):
backwards = int(str(num)[::-1])
components = min(num, backwards), max(num, backwards)
summed = num + backwards
correct.setdefault(summed, []).append(components)
for i in range(100000):
try:
test = sum_of_reversed_numbers(i)
except Exception as e:
raise Exception(i) from e
if test is None:
if i in correct:
print(i, test, correct.get(i))
elif sorted(test) != sorted(correct[i]):
print(i, test, correct.get(i))
Stole the idea from #Doluk. I was asked this question in a test today. I couldn't solve it then. With Doluk's idea and thinking seriously on it below is a decision tree kind for one level of recursion. I might be wrong as I haven't ran this algorithm.
Let n be the number, we want to check if special
case 1: leading number is not 1
case 1a: no carry over from inner addition
abcdefgh
hgfedcba
x x => (a+h) < 10
if both ends are same in n, strip both sides by one digit and recurse
case 1b: carry over from inner addition
1
abcdefgh
hgfedcba
(x+1)......(x) => (a+h+1) < 10
if left end is 1 greater than right end in n, strip both sides by one digit, add digit 1 on the left and recurse
case 2: leading number is 1
case 2a: no carry over from inner addition
1 1
abcdefgh
hgfedcba
1x x => (a+h) >= 10
strip - if second and last digit are same, strip two digits from left and one from right, from the remaining number minus 1 and recurse.
case 2b: carry over from inner addition
case 2bi: a+h = 9
11
abcdefgh
hgfedcba
10......9
strip - two from left and one from right and recurse.
case 2bj: a+h >= 10
11 1
abcdefgh
hgfedcba
1(x+1)......x
strip - two from left and one from right and subtract 1 from number and recurse.
In my question, they gave me an array of numbers and they asked me to find numbers which of them are special (Which can be formed by the sum and reverse of that number).
My brute force solution was to iterate from 0 to 1000000 and insert them into the set and last check for each element in the set.
Time Complexity: O(n)
Space Complexity: O(n)
where n is the highest number allowed.
Please help, I cannot figure out why this code does not work. I think the first loop runs forever but I don't know why!
def NTN():
list1 = []
count = 0
number = 0
Start = input('Type Start Number')
while number != Start:
count = count + 1
number = number + count
Stop = input('Type Stop Number')
while number != Stop:
count = count + 1
number = number + count
if number != Stop:
(list1).append(number)
return (list1)
print(NTN())
You are increasing number by increasing amounts in every iteration. Here's an idea of how it is increasing. Assume Start = 4
After 1 loop, count = 1 and number = 1, increase of 1
After 2 loops, count = 2 and number = 3, increase of 2
After 3 loops, count = 3 and number = 6, increase of 3
Since number is never really equal to 4, the loop never ends. What you need probably is while number <= Start. That would terminate the loop after 3 iterations when number is past 4.
change "number != Start" and "number != Stop" to "number < Start" and "number < Stop" in all places, and it should work.
What went wrong: if Start is 2, then in the first iteration of the while loop, count becomes 0+1=1 and number becomes 0+1=1; in the second iteration, count becomes 1+1=2 and number becomes 1+2=3, which bypasses 2. Since your while loop only ends when number is equal to Start, it never ends.
A couple of side-points:
By convention Python variable and function names are lower-case.
input() returns a string; if you want a number you have to convert it ie with int() or float(). (Note: if you are using Python 2.x input() calls eval() which is really awful design - you should be using int(raw_input()) instead.)
so,
# This code assumes Python 3.x
from math import ceil, sqrt
def get_int(prompt):
"""
Prompt until an integer value is entered
"""
while True:
try:
return int(input(prompt))
except ValueError:
print("Please enter an integer!")
def tri(n):
"""
Return triangular number n,
ie the sum of (1 + 2 + ... + n)
"""
# using Gaussian sum
return n * (n + 1) // 2
def reverse_tri(t):
"""
For positive integer t,
return the least positive integer n
such that t <= tri(n)
"""
# derived by quadratic formula from
# n * (n + 1) // 2 >= t
return int(ceil(((sqrt(8 * t + 1) - 1) / 2)))
def ntn(start, stop):
"""
Return a list of triangular numbers
such that start <= tri < stop
"""
a = reverse_tri(start)
b = reverse_tri(stop)
return [tri(n) for n in range(a, b)]
def main():
start = get_int('Enter a start number: ')
stop = get_int('Enter a stop number: ')
lst = ntn(start, stop + 1) # include stop number in output
print(lst)
if __name__ == "__main__":
main()
I want to define a function, sumAll(n) that sums all numbers from 1 to n.
For example, when I call sumAll(10) should return the answer 55...
Because:
1+2+3+4+5+6+7+8+9+10 = 55
The function sumAll needs to use a for loop to carry out this summation, and it will have to use a sum variable that increases in value over each iteration of the for loop.
I have a working function that does not use a for loop, but I need to know how to use a for loop to accomplish this as well.
Here is the working program:
def sumAll(n):
if n == 0:
return 0
return n + sumAll(n - 1)
number = int(raw_input("Please enter a number: \n"))
print ("The answer is: ") + str(sumAll(number))
How do I use a "for" loop to accomplish this?
Am I right in assuming the "for loop" should be nested in the "sumAll" function?
I have tried many times to do this using a for loop and I keep getting a infinite result and errors...
Here is my code:
def sumAll(n):
y = n + sumAll(n -1)
return y
num = int(raw_input("Please enter a number")
for n in range(num):
num = sumAll(num)
print num
By for loop
def sumAll(n):
sum_all = 0
for i in range(1, n+1):
sum_all = sum_all + i
return sum_all
number = int(raw_input("Please enter a number: \n"))
print ("The answer is: ") + str(sumAll(number))
Output:
Please enter a number:
10
The answer is: 55
You can also use list Comprehension:
print sum([i for i in range(number+1)])
Output:
55
You can also use a mathematical series formula:
def sumAll(n):
return n * (n + 1) / 2
you can even do it without a loop:
def sumAll(n):
return sum(range(1,n+1))
print(sumAll(10)) # -> 55
if you insist on using a loop:
def sumAll(n):
s = 0
for i in range(1,n+1):
s += i
return s
but the mathematical solution is simply:
def sumAll(n):
return n * (n + 1) / 2
# in python 3:
# return n * (n + 1) // 2
(there are n elements with an average value of (n+1)/2; this will always be an integer since either n or n+1 is even; the proof by induction is often the first example when math students learn about induction...).
You will get an error with sum(1, 2, 3, 4)
TypeError: sum expected at most 2 arguments, got 4
sum((1, 2, 3, 4)) # works cuz tuple inside
sum([1, 2, 3, 4]) # works cuz list inside
so the func will need to gather elements into a tuple, e.g.
numbers = 1, 2, 3, 4
print(sum(numbers)) # already a tuple so works
use * with your parameter to gather the caller's args into a tuple.
* enabbles any-number of args to be supplied by caller and they are converted into a tuple parameter.
def sumall(*args):
return sum(args)
print(sumall(1))
print(sumall(1, 2))
print(sumall(1, 2, 3))
print(sumall(1, 2, 3, 4))
produces the expected answers. Credit: author Downey asks for this exercises solution in chapter 12 of Think Python (2016)
I am trying to create a program that takes a user integer input, creates a list and then
using recursion adds the list. The problem is when I put in 6 it comes up with 15 and the
answer should be (0+1+2+3+4+5+6) = 21. Why is the math wrong? I think it must be somewhere in the indexing because if you leave off the 6 you do get 15.
#Program which accepts a number from the user
#take the numbers 0 to the number input
#and gives a total of the numbers
def main():
#Get the number from the user to define upper end of range
num = int(input('Enter a non-negative integer: '))
#Create the list of numbers
numbers = list(range(0,num, 1))
#Get the sum of the list of numbers
my_sum = range_sum(numbers, 0, - 1)
#Display the total
print('The sum of 0 to', num, 'is: ', my_sum)
def range_sum(num_list, start, end):
if start < end:
return 0
else:
return sum(num_list)
#call the main function
main()
Using tail recursion:
def range_sum(nums, sum=0):
if not nums:
return sum
sum += nums.pop()
return range_sum(nums, sum)
There is no recursive call in the code. You are using the sum function, which comes defined in Python.
This is a relatively simple function to implement either recursively:
def recursive(n):
if n == 1:
return n
return n + recursive(n - 1)
or iteratively:
def iterative(n):
return sum(range(n + 1)) # note n + 1 - range excludes the stop argument
which is equivalent to:
def iterative_longhand(n):
total = 0
for i in range(n + 1):
total += i
return total
or, if a list is a necessity:
def recursive_list_sum(nums):
if nums:
return nums[0] + recursive_list_sum(nums[1:])
return 0
recursive_list_sum(list(range(n + 1)))
Your title says "using recursion", but none of your functions call themselves. You are using recursion neither to build the list nor to add up its contents. This function:
def range_sum(num_list, start, end):
if start < end:
return 0
else:
return sum(num_list)
called like:
range_sum(numbers, 0, - 1)
is just sum(num_list), as start > end. It is not clear what you are trying to achieve - if it should be recursive, there should be a call to range_sum inside it.