Rewrite the recursion function with loop - python

To rewrite the function without using recursion.
def func(num):
if num < 2:
return 1
else:
return func(num - 1) + func(num - 2)
# TODOļ¼što rewrite the func using 'loop' instead of 'recursion'.
Below may be a solution, but i do not think it is a good way as i am using the convience of 'list'.
def func(num):
"""
I use a list to simulate a queue,
it is initialized with the param 'num' passed in,
and then judge it, if it ge 2, pop it and append the two nums 'num - 1', 'num - 2'.
And repeat it, if the number is lt 2, the index move to right by 1.
When the index is equal to the 'length - 1' of the queue, the queue if fulled with '0' and '1',
because 'func(0) = 1', 'func(1) = 1', the result is the length of the queue.
"""
index = 0
queue = [num]
while True:
value = queue[index]
if value >= 2:
queue.pop(index)
queue.append(value - 1)
queue.append(value - 2)
else:
if index == len(queue) - 1:
break
index += 1
return len(queue)

The task was interesting for me to solve, I cope with it the following way:
def f(num):
if num < 2: # margin condition
return 1
start_list = [num] # create initial list
while True:
new_list = [] # list to store new elements
changes = 0 # check if there was elements >=2
for element in start_list:
if element >= 2:
new_list.append(element - 1)
new_list.append(element - 2)
changes += 1
else:
new_list.append(element)
start_list = new_list # change start_list for new run
print(start_list)
if changes == 0:
return len(start_list)
I made performance check num = 25
my solution speed: 0.14056860000000002
recursion speed: 0.03910620000000001
your not recursion solution: 1.6991333
So it is 10 times faster.
Thank you for the task!

Related

Remove triplets of adjacent numbers from the list [duplicate]

This question already has answers here:
Write a function lines(a) that determines how many balls will be destroyed
(6 answers)
Closed 2 years ago.
Here is the problem. The input is a list of integers. If three adjacent numbers appear next to each other they should be dropped and the operation goes again. Iphone app with the balls of the same colors. The output should be the count of the balls that will be destroyed.
Example:
input = [3,3,4,4,4,3,4]
1st iteration
output: [3,3,3,4]
Final output:
6
4,4,4 on the first iteration, so three balls. and 3,3,3 on the second. Overall six.
My code is below. It will remove the 4,4,4 but will fail after, because list index will quickly go out of range.
def balls(a):
curr_index = 0
removed_count = 0
while len(a) > 2:
if (a[curr_index] == a[curr_index+1]) and (a[curr_index] == a[curr_index+2]):
a.remove(a[curr_index])
a.remove(a[curr_index+1])
a.remove(a[curr_index+2])
curr_index += 1
removed_count += 3
return removed_count
a = [3, 3, 4, 4, 4, 3, 4]
print(balls(a)) # should print 6
Any ideas?
input_values = [3,3,4,4,4,3,4]
values = input_values
while len(values) >= 3:
for x in range(0,len(values)-2):
# if we find 3 values in ar row
if values[x] == values[x+1] and values[x] == values[x+2]:
# update values by cutting out the series
values = values[:x] + values[x+3:]
# break this for loop
break
else:
# for loops can have an else statement
# this means that we came at the end of the for loop
# this if we didn't break the loop (and didn't found a valid triple)
# then we brea
break
#result - amount of removed balls
values, len(input_values) - len(values)
A more generic approach where you can define N
(it will find exact N values)
input_values = [3,3,4,4,4,4,3,3,4]
# amount of neighbours
N = 4
values = input_values
# keep looping as long as we've N values
while len(values) >= N:
# we need this if we break the inner loop
stop = False
# loop over values from left to right
# 3 -> 3 -> 4 -> 4 -> ... until -N + 1
# because that is the last spot that we've N values left
for x in range(0, len(values) - N + 1):
# scout for the next numbers (x+1 x+2 x+3 ....)
# this goes from, x+1 until the end of the serie
# also start counting from 2 - because
# if we've a single match, 2 numbers are equal
for e, y in enumerate(range(x+1, len(values)), start=2):
# if x and y are different, the stop this scouting
# remember y = x+1 x+2 x+3 ....
if values[x] != values[y]:
break
# if we reached this stage, we know that
# x and x+1 x+2 ... are equal
# but also check if we've enough matches
if e == N:
# update values by cutting out the series
values = values[:x] + values[y+1:]
stop = True
break
if stop:
break
else:
# for loops can have an else statement
# this means that we came at the end of the for loop
# this if we didn't break the loop (and didn't found a valid triple)
# then we brea
break
values, len(input_values) - len(values)
Here is one way to do it:
your_list=[3, 3, 4, 4, 4, 3, 4]
def remove_one(l):
if len(l)>2:
for i in range(len(l)-2):
if l[i]==l[i+1]==l[i+2]:
res.extend(l[i:i+3])
l=l[:i]+l[i+3:]
return l
return []
res=[]
while len(your_list)>2:
your_list=remove_one(your_list)
print(len(res))
Output:
6
An approach with a minimal threshold
input_values = [3,3,4,4,4,4,4,3,3,4]
# threshold
N = 3
values = input_values
while len(values) >= N:
# we need this if we break the inner loop
stop = False
# loop over values
for x in range(0, len(values) - N + 1):
# scout for the next numbers (x+1 x+2 x+3 ....)
for e, y in enumerate(range(x+1, len(values)), start=2):
# check if the values of x and x+1 (x+2 x+3 ...) are different
if values[x] != values[y]:
# if so, check if we've reached our threshold of N
if e >= N:
# if this is the case update values by cutting out the series
values = values[:x] + values[y:]
stop = True
break
# if x+n != x then we break this scouting loop
break
# stop is True, this means, that we found N neibouring numbers
# thus we can break this loop, and start over with a new* value
if stop:
break
else:
# for loops can have an else statement
# this means that we came at the end of the for loop
# thus if we didn't break the loop (and didn't found a valid triple)
# then we break
break
values, len(input_values) - len(values)
There are a couple of issues with your code.
The first is you're trying to iterate over the list a single time, but that won't work for your example.
The second is you're assuming the list will always reduce to less than 3, which won't be the case if you have more numbers.
There are also some places you can simplify the syntax, for example:
if (a[curr_index] == a[curr_index+1]) and (a[curr_index] == a[curr_index+2]):
is equivalent to:
if a[curr_index] == a[curr_index + 1] == a[curr_index + 2]:
And
a.remove(a[curr_index])
a.remove(a[curr_index+1])
a.remove(a[curr_index+2])
is equivalent to:
del a[curr_index: curr_index + 3]
So here is one way to accomplish this, thought there are more efficient ways.
def balls(a):
removed = 0
complete = False
# Run until complete is set or the list is too short for a match
while not complete and len(a) >= 3:
for idx, val in enumerate(a):
if val == a[idx + 1] == a[idx + 2]:
del a[idx: idx + 3]
removed += 3
break # Restart every time we find a match
# If it's the last possible match, set complete
if idx == len(a) - 3:
complete = True
break
return removed
I'm little bit late, but my idea is to do the processing in one pass. The idea is that when you drop a tripple, go back two positions to re-check if a new tripple has been created by that change.
Example:
3 3 4 4 4 3
^--- tripple found here, remove it
3 3 3
^--- move the cursor 2 positions left and continue checking
The code:
def drop3(lst):
# drop3 destroys the lst, make a copy if you want to keep it
dropped = 0
cursor = 0
limit = len(lst) - 2
while cursor < limit:
if lst[cursor] == lst[cursor+1] == lst[cursor+2]:
del lst[cursor:cursor+3]
cursor = max(0, cursor-2)
limit -= 3
dropped += 3
else:
cursor += 1
return dropped
A linear-tme solution:
def balls(a):
b = []
for x in a:
b.append(x)
if b[-3:] == [x] * 3:
del b[-3:]
return len(a) - len(b)

Heap's Algorithm - Non Recursive Method in Python to generate permutations

I am a newbie to programming. I am working on Heap's Algorithm, specifically non-recursive method. There is not so much explanation available on internet, to how the algorithm works. I found this piece of work from Bernardo Sulzbach but he doesn't explain how his algorithm works. I am stuck on it from days, tried everything couldn't figure it out. I have added comments after each line to make myself understand -- what's happening here? but I still couldn't make it work. Am I doing something wrong? Please help.
# Heap's Algorithm (Non Recursive)
# function to swap values in python
def swap(elements, i, j):
elements[i], elements[j] = elements[j], elements[i]
# function to generate permutation
def generate_permutations(elements, n):
# Passing two parameters of elements and n to function "generate_permutations".
c = [0] * n
# c is a new list and its value set to an array literal with value 0, n times.
# Example - [a] * 3 ==> ['a', 'a', 'a', 'a']
yield elements
# "yield" statement is used to define generators, while "return" statement causes a function to exit.
# "yield" replacing the return of a function to provide a result to its caller without destroying
# local variables. Unlike a function, where on each call it starts with new sets of variables, a generator
# will resume the execution where it left off.
i = 0
# i is a new variable and its value is set to 0. It can also be used to count the number of loop runs.
while i < n:
# while loop ==> while i is less than n, do following:
if c[i] < i:
# if statement ==> while i is less than n and if any element from 'c' list is less than i,
# then do following:
if i % 2 == 0:
# if statement ==> while i is less than n, and if any element in 'c' list is less than i, and
# i is an even number, then do following:
swap(elements, 0, i)
# calling swap function and passing following arguments: elements, '0' and 'i'
else:
# else, if all three conditions above are not true then do following:
swap(elements, c[i], i)
# calling swap funtions and passing following arguments: elements, an item from 'c' list and 'i'
yield elements
# ??? yield elements
c[i] += 1
# after that, increment c[i] by 1.
i = 0
# set the value of i to 0
else:
# else, if c[i] < i is not true the do the following.
c[i] = 0
# set the value of c[i] to 0
i += 1
# and increment i by 1
def permutations(elements):
return generate_permutations(elements, len(elements))
# Driver Code
# c = ?
# n = ?
# i = ?
print(permutations(['abc']))
Just cleaning up your code (too many comments):
# Heap's Algorithm (Non Recursive)
# https://en.wikipedia.org/wiki/Heap%27s_algorithm
def swap(seq, i, j):
seq[i], seq[j] = seq[j], seq[i]
def generate_permutations(seq, seqLen, resLen):
c = [0] * seqLen
yield seq[:resLen]
i = 0
while i < seqLen:
if c[i] < i:
if i % 2 == 0:
swap(seq, 0, i)
else:
swap(seq, c[i], i)
yield seq[:resLen]
c[i] += 1
i = 0
else:
c[i] = 0
i += 1
def permutations(seq, resLen=None):
if not resLen: resLen = len(seq)
return generate_permutations(seq, len(seq), resLen)
for p in permutations([1,2,3]): print(p)
for p in permutations([1,2,3],2): print(p)

Use a while loop to keep count of even integers that a user inputs into a list?

myList = []
size = int(input("How many integers do you want in your list? "))
for list in range(size):
element = int(input("Enter an integer to add to your list: "))
myList.append(element)
print(myList)
#a function that keeps count of all even integers using while loop
def count_evens_while(alist):
evenIntegers = 0
while range <= size:
for element in range(size):
if element % 2 == 0:
evenIntegers = evenIntegers + 1
print(evenIntegers)
This is what I have so far. I can't figure out what I need to do! (I'm a beginner, so sorry if this question seems so simple/easy to fix)
def count_evens_while(alist):
evenIntegers = 0
idx = 0
while idx < len(alist):
if alist[idx] % 2 == 0:
evenIntegers = evenIntegers + 1
idx += 1
print(evenIntegers)
Using a for loop would be much simpler though:
def count_evens_while(alist):
evenIntegers = 0
for el in alist:
if el % 2 == 0:
evenIntegers = evenIntegers + 1
print(evenIntegers)
And even simpler using some list comprehension:
def count_evens_while(alist):
evenIntegers = sum(1 for x in alist if (x%2 == 0))
print(evenIntegers)
Problem
You have several problems here:
You never define size in the head of the while loop.
You're using the range builtin class as an integer value which doesn't make sense.
You never use alist in your function.
You don't need a for loop in your while because you are not trying to find the amount of even numbers for each number between 1 to element, your trying to find all the even numbers in alist (presumably).
Here is what the above fixes would look like:
def count_evens_while(alist):
evenIntegers = 0
size = 0
while size < len(alist):
if alist[size] % 2 == 0:
evenIntegers = evenIntegers + 1
size = size + 1
print(evenIntegers)
In the first part of the while loop:
size < len(alist)
We are telling Python to comparse the value of size to the length of alist each time we loop. We then incrmenet size by one each time in the loop:
size = size + 1
This basically means that each iteration of the loop, the value of size will correspond to an index of alist. The loop will stop when size reaches the last index of alist. Here's a visual example to help explain. Assume alist is [1, 2, 3] and size initially equals 0:
First iteration
alist = [1, 2, 3]
^
|
+--- size = 0
Second iteration
alist = [1, 2, 3]
^
|
+--- size = 1
Third (and last) iteration
alist = [1, 2, 3]
^
|
+--- size = 2
The next important part:
alist[size] % 2 == 0
Means we are indexing the list alist. When you index a list, you use an integer to get a value from the position that the integer corresponds to. In this case, alist[size] means that we are getting the value of the integer at position of the value of size. The last part:
% 2 == 0
Means that we are testing if the integer at position size in alist is even. If it is, we increment the count of even numbers, if not we do nothing.
Improvements
There are some improvements you can make to your current solution
Use a for loop instead of a while loop. It would be the more natural solution here.
You don't need to do evenIntegers = evenIntegers + 1. You an use the increment operator, +=, instead.
Here are the improvements from above applied to your code:
def count_evens_while(alist):
evenIntegers = 0
for element in alist:
if element % 2 == 0:
evenIntegers += 1
print(evenIntegers)
However, this can be improved more! You don't need a for loop. You can use a generator comprehension combined with the sum() builtin function to count all of the elements in alist that are even:
def count_evens_while(alist):
return sum(1 for el in alist if el % 2)
Stylistic improvements
The last thing I would critique on your code would be to use better variable names. Use names that accurately describe what the variable represents.For example, the variable myList would be better renamed to user_input_numbers.
You do not need a while loop at all:
myList = []
size = int(input("How many integers do you want in your list? "))
for list in range(size):
element = int(input("Enter an integer to add to your list: "))
myList.append(element)
print(myList)
#a function that keeps count of all even integers using while loop
def count_evens_while(alist):
evenIntegers = 0
for element in alist:
if element % 2 == 0:
evenIntegers = evenIntegers + 1
return evenIntegers
print(count_evens_while(myList))
If you need to stop a for loop early, you can use the break statement to break out of the loop. Otherwise, it will stop by itself once it reaches the end of the list. It does not need an ending condition to be given manually.
This is very unlike your program but I hope to teach you something with it... First of all if all you need is to "keep count" you don't really have to save the integers themselves in a list. Which means that all you really need is something like this:
count = 0
while True:
element = int(input("Enter an integer to add to your list: "))
if element % 2 == 0:
count += 1 # which is the same as count = count + 1
elif element == 9999:
break # user could enter 9999 to exit the loop
print('I have counted ' + str(count) + ' even numbers so far')
I hope in this just to show you that you don't have to complicate simple things

Python: while loop inside else

def is_prime(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
my_list = is_prime(18)
def prime(x):
my_list2 = []
for number in my_list:
if number <= 2:
my_list2.append(number)
else:
count = 2
while count < number:
if number % count == 0:
break
else:
my_list2.append(number)
count += 1
return my_list2
print prime(18)
Just started out with Python. I have a very simple question.
This prints: [9, 3, 2].
Can someone please tell me why the loop inside my else stops at count = 2? In other words, the loop inside my loop doesn't seem to loop. If I can get my loop to work, hopefully this should print [2, 3]. Any insight is appreciated!
Assuming that my_list2 (not a very nice name for a list) is supposed to contain only the primes from my_list, you need to change your logic a little bit. At the moment, 9 is being added to the list because 9 % 2 != 0. Then 9 % 3 is tested and the loop breaks but 9 has already been added to the list.
You need to ensure that each number has no factors before adding it to the list.
There are much neater ways to do this but they involve things that you may potentially find confusing if you're new to python. This way is pretty close to your original attempt. Note that I've changed your variable names! I have also made use of the x that you are passing to get_prime_factors (in your question you were passing it to the function but not using it). Instead of using the global my_list I have called the function get_factors from within get_prime_factors. Alternatively you could pass in a list - I have shown the changes this would require in comments.
def get_factors(x):
count = 1
my_list = []
while count > 0 and count < x:
if x % count == 0:
my_list.append(x/count)
count += 1
return my_list
# Passing in the number # Passing in a list instead
def get_prime_factors(x): # get_prime_factors(factors):
prime_factors = []
for number in get_factors(x): # for number in factors:
if number <= 2:
prime_factors.append(number)
else:
count = 2
prime = True
while count < number:
if number % count == 0:
prime = False
count += 1
if prime:
prime_factors.append(number)
return prime_factors
print get_prime_factors(18)
output:
[3, 2]
Just to give you a taste of some of the more advanced ways you could go about doing this, get_prime_factors could be reduced to something like this:
def get_prime_factors(x):
prime_factors = []
for n in get_factors(x):
if n <= 2 or all(n % count != 0 for count in xrange(2, n)):
prime_factors.append(n)
return prime_factors
all is a built-in function which would be very useful here. It returns true if everything it iterates through is true. xrange (range on python 3) allows you to iterate through a list of values without manually specifying a counter. You could go further than this too:
def get_prime_factors(x):
return [n for n in get_factors(x) if n <= 2 or all(n % c != 0 for c in xrange(2, n))]

Fast way to get N Min or Max elements from a list in Python

I currently have a long list which is being sorted using a lambda function f. I then choose a random element from the first five elements. Something like:
f = lambda x: some_function_of(x, local_variable)
my_list.sort(key=f)
foo = choice(my_list[:4])
This is a bottleneck in my program, according to the profiler. How can I speed things up? Is there a fast, inbuilt way to retrieve the elements I want (in theory shouldn't need to sort the whole list). Thanks.
Use heapq.nlargest or heapq.nsmallest.
For example:
import heapq
elements = heapq.nsmallest(4, my_list, key=f)
foo = choice(elements)
This will take O(N+KlogN) time (where K is the number of elements returned, and N is the list size), which is faster than O(NlogN) for normal sort when K is small relative to N.
It's actually possible in linear time (O(N)) on average.
You need a partition algorithm:
def partition(seq, pred, start=0, end=-1):
if end == -1: end = len(seq)
while True:
while True:
if start == end: return start
if not pred(seq[start]): break
start += 1
while True:
if pred(seq[end-1]): break
end -= 1
if start == end: return start
seq[start], seq[end-1] = seq[end-1], seq[start]
start += 1
end -= 1
which can be used by an nth_element algorithm:
def nth_element(seq_in, n, key=lambda x:x):
start, end = 0, len(seq_in)
seq = [(x, key(x)) for x in seq_in]
def partition_pred(x): return x[1] < seq[end-1][1]
while start != end:
pivot = (end + start) // 2
seq[pivot], seq[end - 1] = seq[end - 1], seq[pivot]
pivot = partition(seq, partition_pred, start, end)
seq[pivot], seq[end - 1] = seq[end - 1], seq[pivot]
if pivot == n: break
if pivot < n: start = pivot + 1
else: end = pivot
seq_in[:] = (x for x, k in seq)
Given these, just replace your second (sort) line with:
nth_element(my_list, 4, key=f)

Categories