I am supposed to create a function to generate a Tribonacci sequence in Python. This function must be RECURSIVE. Based on this, I have this code so far:
def TribRec(n) :
if (n == 0 or n == 1 or n == 2) :
return []
elif (n == 3) :
return [0,1][:n]
else :
sequence = TribRec(n-1)
sequence.append(sequence[len(sequence)-1] +
sequence[len(sequence)-2] + sequence[len(sequence)-3])
return sequence
def Trib(n) :
for i in range(1, n) :
print( TribRec(i) , " ", end = "")
# Driver code
n = 10
Trib(n)
When I run this code, I get the following output:
[] [] [0, 1] [0, 1, 2] [0, 1, 2, 3] [0, 1, 2, 3, 6] [0, 1, 2, 3, 6, 11] [0, 1,2, 3, 6, 11, 20] [0, 1, 2, 3, 6, 11, 20, 37]
Instead, I want the output of length = n which is 10 here in the form of:
[0, 1, 2, 3, 6, 11, 20, 37, 68, 125]
How do I fix my current code?
Your code can be written more succinctly as follows.
def TribRec(n) :
if n in {0, 1, 2}:
return n
else :
return TribRec(n-1) + TribRec(n-2) + TribRec(n-3)
def Trib(n) :
for i in range(0, n) :
yield TribRec(i)
res = list(Trib(10))
# [0, 1, 2, 3, 6, 11, 20, 37, 68, 125]
Explanation
As per #czr's solution, you can sum the last 3 calls to TribRec recursively.
Return n if it belongs to the set {0, 1, 2}.
For Trib(n), use a generator to remove boilerplate code (list instantiation, appending to list).
Instead of returning a list in every recursive call, return the nth element and aggregate the list on the Trib function:
def TribRec(n) :
if n == 0:
return 0
elif n == 1:
return 1
elif n == 2:
return 2
else :
return TribRec(n-1) + TribRec(n-2) + TribRec(n-3)
def Trib(n) :
l = []
for i in range(0, n) :
l.append(TribRec(i))
return l
# Driver code
n = 10
Trib(n)
This is much more simple:
def trib(n):
if n < 3:
return n
return trib(n-1) + trib(n-2) + trib(n-3)
def tri(n):
result = []
for i in range(0,n):
result.append(trib(n))
return result
Related
I am trying to make a function that counts the number of cycles within a permutated list.
I do sometimes get the right answer when running the code, but most times I receive an error message - and I am unable to figure out why.
My code is as follows:
def count_cycles(n):
cycle_count = 0
copy_list = []
for element in n:
copy_list.append(element)
while len(copy_list) != 0:
ran_num = random.choice(copy_list)
while True:
if n[ran_num] == ran_num:
cycle_count = circle_count + 1
if int(ran_num) in copy_list:
copy_list.remove(ran_num)
break
else:
n.insert(ran_num, ran_num)
print(n, ran_num, copy_list)
ran_num = n[ran_num + 1]
print(ran_num)
copy_list.remove(ran_num)
n.remove(ran_num)
continue
return print(cycle_count, n)
What I use is that I test with this permutated list with 3 cycles [2, 6, 0, 3, 1, 4, 5].
Picture of output from a correct and incorrect run
I used print(n, ran_num, copy_list) to assess the output as per the picture.
Here is one possibility:
p = [2, 6, 0, 3, 1, 4, 5]
cycles = set()
elts = set(range(len(p)))
while elts:
cycle = []
x0 = elts.pop()
cycle.append(x0)
x = p[x0]
while x != x0:
cycle.append(x)
x = p[x]
elts -= set(cycle)
cycles.add(tuple(cycle))
print(cycles)
It gives:
{(0, 2), (1, 6, 5, 4), (3,)}
Then to get the number of cycles you can use len(cycles).
In addition to the existing answer, sympy provides some functionality to work with permutations. In this case, you could use the following:
from sympy.combinatorics import Permutation
p = Permutation([2, 6, 0, 3, 1, 4, 5])
num_cycles = p.cycles # 3
I have a problem with this algorithm- I have to find pairs in list:
[4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
which are equal to 12. The thing is that after making a pair those numbers (elements) can not be used again.
For now, I have code which you can find below. I have tried to delete numbers from the list after matching, but I feel that there is an issue with indexing after this.
It looks very easy but still not working. ;/
class Pairs():
def __init__(self, sum, n, arr ):
self.sum = sum
self.n = n
self.arr = arr
def find_pairs(self):
self.n = len(self.arr)
for i in range(0, self.n):
for j in range(i+1, self.n):
if (self.arr[i] + self.arr[j] == self.sum):
print("[", self.arr[i], ",", " ", self.arr[j], "]", sep = "")
self.arr.pop(i)
self.arr.pop(j-1)
self.n = len(self.arr)
i+=1
def Main():
sum = 12
arr = [4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
n = len(arr)
obj_Pairs = Pairs(sum, n, arr)
obj_Pairs.find_pairs()
if __name__ == "__main__":
Main()
update:
Thank you guys for the fast answers!
I've tried your solutions, and unfortunately, it is still not exactly what I'm looking for. I know that the expected output should look like this: [4, 8], [0, 12], [1, 11], [4, 8], [12, 0]. So in your first solution, there is still an issue with duplicated elements, and in the second one [4, 8] and [12, 0] are missing. Sorry for not giving output at the beginning.
With this problem you need to keep track of what numbers have already been tried. Python has a Counter class that will hold the count of each of the elements present in a given list.
The algorithm I would use is:
create counter of elements in list
iterate list
for each element, check if (target - element) exists in counter and count of that item > 0
decrement count of element and (target - element)
from collections import Counter
class Pairs():
def __init__(self, target, arr):
self.target = target
self.arr = arr
def find_pairs(self):
count_dict = Counter(self.arr)
result = []
for num in self.arr:
if count_dict[num] > 0:
difference = self.target - num
if difference in count_dict and count_dict[difference] > 0:
result.append([num, difference])
count_dict[num] -= 1
count_dict[difference] -= 1
return result
if __name__ == "__main__":
arr = [4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
obj_Pairs = Pairs(12, arr)
result = obj_Pairs.find_pairs()
print(result)
Output:
[[4, 8], [8, 4], [0, 12], [12, 0], [1, 11]]
Demo
Brief
If you have learned about hashmaps and linked lists/deques, you can consider using auxiliary space to map values to their indices.
Pro:
It does make the time complexity linear.
Doesn't modify the input
Cons:
Uses extra space
Uses a different strategy from the original. If this is for a class and you haven't learned about the data structures applied then don't use this.
Code
from collections import deque # two-ended linked list
class Pairs():
def __init__(self, sum, n, arr ):
self.sum = sum
self.n = n
self.arr = arr
def find_pairs(self):
mp = {} # take advantage of a map of values to their indices
res = [] # resultant pair list
for idx, elm in enumerate(self.arr):
if mp.get(elm, None) is None:
mp[elm] = deque() # index list is actually a two-ended linked list
mp[elm].append(idx) # insert this element
comp_elm = self.sum - elm # value that matches
if mp.get(comp_elm, None) is not None and mp[comp_elm]: # there is no match
# match left->right
res.append((comp_elm, elm))
mp[comp_elm].popleft()
mp[elm].pop()
for pair in res: # Display
print("[", pair[0], ",", " ", pair[1], "]", sep = "")
# in case you want to do further processing
return res
def Main():
sum = 12
arr = [4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
n = len(arr)
obj_Pairs = Pairs(sum, n, arr)
obj_Pairs.find_pairs()
if __name__ == "__main__":
Main()
Output
$ python source.py
[4, 8]
[0, 12]
[4, 8]
[1, 11]
[12, 0]
To fix your code - few remarks:
If you iterate over array in for loop you shouldn't be changing it - use while loop if you want to modify the underlying list (you can rewrite this solution to use while loop)
Because you're iterating only once the elements in the outer loop - you only need to ensure you "popped" elements in the inner loop.
So the code:
class Pairs():
def __init__(self, sum, arr ):
self.sum = sum
self.arr = arr
self.n = len(arr)
def find_pairs(self):
j_pop = []
for i in range(0, self.n):
for j in range(i+1, self.n):
if (self.arr[i] + self.arr[j] == self.sum) and (j not in j_pop):
print("[", self.arr[i], ",", " ", self.arr[j], "]", sep = "")
j_pop.append(j)
def Main():
sum = 12
arr = [4, 8, 9, 0, 12, 1, 4, 2, 12, 12, 4, 4, 8, 11, 12, 0]
obj_Pairs = Pairs(sum, arr)
obj_Pairs.find_pairs()
if __name__ == "__main__":
Main()
Here is what I am trying to do. Given a number and a set of numbers, I want to partition that number into the numbers given in the set (with repetitions).
For example :
take the number 9, and the set of numbers = {1, 4, 9}.
It will yield the following partitions :
{ (1, 1, 1, 1, 1, 1, 1, 1, 1), (1, 1, 1, 1, 1, 4), (1, 4, 4), (9,)}
No other possible partitions using the set {1, 4, 9} cannot be formed to sum the number 9.
I wrote a function in Python which do the task :
S = [ 1, 4, 9, 16 ]
def partition_nr_into_given_set_of_nrs(nr , S):
lst = set()
# Build the base case :
M = [1]*(nr%S[0]) + [S[0]] * (nr //S[0])
if set(M).difference(S) == 0 :
lst.add(M)
else :
for x in S :
for j in range(1, len(M)+1):
for k in range(1, nr//x +1 ) :
if k*x == sum(M[:j]) :
lst.add( tuple(sorted([x]*k + M[j:])) )
return lst
It works correctly but I want to see some opinions about it. I'm not satisfied about the fact that it uses 3 loops and I guess that it can be improved in a more elegant way. Maybe recursion is more suited in this case. Any suggestions or corrections would be appreciated. Thanks in advance.
I would solve this using a recursive function, starting with the largest number and recursively finding solutions for the remaining value, using smaller and smaller numbers.
def partition_nr_into_given_set_of_nrs(nr, S):
nrs = sorted(S, reverse=True)
def inner(n, i):
if n == 0:
yield []
for k in range(i, len(nrs)):
if nrs[k] <= n:
for rest in inner(n - nrs[k], k):
yield [nrs[k]] + rest
return list(inner(nr, 0))
S = [ 1, 4, 9, 16 ]
print(partition_nr_into_given_set_of_nrs(9, S))
# [[9], [4, 4, 1], [4, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1]]
Of course you could also do without the inner function by changing the parameters of the function and assuming that the list is already sorted in reverse order.
If you want to limit the number of parts for large numbers, you can add an aditional parameter indicating the remaining allowed number of elements and only yield result if that number is still greater than zero.
def partition_nr_into_given_set_of_nrs(nr, S, m=10):
nrs = sorted(S, reverse=True)
def inner(n, i, m):
if m > 0:
if n == 0:
yield []
for k in range(i, len(nrs)):
if nrs[k] <= n:
for rest in inner(n - nrs[k], k, m - 1):
yield [nrs[k]] + rest
return list(inner(nr, 0, m))
Here is a solution using itertools and has two for loops so time complexity is about O(n*n) (roughly)
A little memoization applied to reshape list by removing any element that is greater than max sum needed.
Assuming you are taking sum to be max of your set (9 in this case).
sourceCode
import itertools
x = [ 1, 4, 9, 16 ]
s = []
n = 9
#Remove elements >9
x = [ i for i in x if i <= n]
for i in xrange(1,n + 1):
for j in itertools.product(x,repeat = i):
if sum(j) == n:
s.append(list(j))
#Sort each combo
s =[sorted(i) for i in s]
#group by unique combo
print list(k for k,_ in itertools.groupby(s))
Result
>>>
>>>
[[9], [1, 4, 4], [1, 1, 1, 1, 1, 4], [1, 1, 1, 1, 1, 1, 1, 1, 1]]
EDIT
You can further optimize speed (if needed) by stopping finding combo's after sum of product is > 9
e.g.
if sum(j) > n + 2:
break
Q: A run is a sequence of adjacent repeated values. Given a list, write a function to
determine the length of the longest run. For example, for the sequence [1, 2, 5, 5, 3, 1, 2, 4, 3, 2, 2, 2, 2, 3, 6, 5, 5, 6, 3, 1], the longest run is 4.
I am having trouble with this, I've written a code that finds the longest run consist of the number '2' but have yet to get the length of the run which is 4.
Here is my code so far (i've commented out a part that i was working on but don't pay attention to it):
# longestrun.py
# A function to determine the length of the longest run
# A run is a sequence of adjacent repeated values.
def longestrun(myList):
result = None
prev = None
size = 0
max_size = 0
for i in myList:
if i == prev:
size += 1
if size > max_size:
result = i
max_size = size
else:
size = 0
prev = i
return result
def main():
print("This program finds the length of the longest run within a given list.")
print("A run is a sequence of adjacent repeated values.")
myString = input("Please enter a list of objects (numbers, words, etc.) separated by
commas: ")
myList = myString.split(',')
longest_run = longestrun(myList)
print(">>>", longest_run, "<<<")
main()
Help please!!! :(((
You can do this in one line using itertools.groupby:
import itertools
max(sum(1 for _ in l) for n, l in itertools.groupby(lst))
This should work if you do not want to use itertools and imports.
a=[1, 2, 5, 5, 3, 1, 2, 4, 3, 2, 2, 2, 2, 3, 6, 5, 5, 6, 3, 1]
def longestrun(myList):
result = None
prev = None
size = 0
max_size = 0
for i in myList:
if i == prev:
print (i)
size += 1
if size > max_size:
print ('******* '+ str(max_size))
max_size = size
else:
size = 0
prev = i
print (max_size+1)
return max_size+1
longestrun(a)
Just another way of doing it:
def longestrun(myList):
sett = set()
size = 1
for ind, elm in enumerate(myList):
if ind > 0:
if elm == myList[ind - 1]:
size += 1
else:
sett.update([size])
size = 1
sett.update([size])
return max(sett)
myList = [1, 2, 5, 5, 3, 1, 2, 4, 3, 2, 2, 2, 2, 3, 6, 5, 5, 6, 3, 1]
print longestrun(myList)
def getSublists(L,n):
outL=[]
for i in range(0,len(L)-n+1):
outL.append(L[i:i+n])
return outL
def longestRun(L):
for n in range(len(L), 0, -1):
temp=getSublists(L,n)
for subL in temp:
if subL==sorted(subL):
return len(subL)
def longestrun(myList):
size = 1
max_size = 0
for i in range(len(myList)-1):
if myList[i+1] = myList[i]:
size += 1
else:
size = 1
if max_size<size:
max_size = size
return size
Remove the .split() from myList in main() and you're good to go with this.
As an update to David Robinson's answer, it is now (Python 3.4) possible to return 0 on an empty sequence (instead of raising ValueError):
import itertools
max((sum(1 for _ in l) for n, l in itertools.groupby(lst)), default=0)
This question already has answers here:
python: recursive check to determine whether string is a palindrome
(6 answers)
How to check for palindrome using Python logic
(35 answers)
Closed 9 years ago.
I'm working on a Python code, where I have to test whether a list is a palindrome using recursion and am coming across come confusion and issues with my code:
def isPalindrome( thesublist ) :
thesublisttest = thesublist[0:]
if len(thesublisttest) <= 1:
return True
elif len(thesublisttest) == 2:
x = thesublisttest[0]
y = thesublisttest[1]
if x == y:
return True
else:
return false == thesublisttest.pop(0)
elif len(thesublisttest) > 2:
first = thesublisttest.pop(0)
last = thesublisttest.pop()
if first == last:
return isPalindrome(thesublisttest)
else:
return False
def maxPalindrome( thelist ) :
completelist=thelist[:]
completelist.reverse()
complete=len(thelist)-1
for i in range(complete):
if completelist[:]==thelist[:]:
x=len(thelist)
y=0
return(x,y)
elif completelist[i:complete]==thelist[i:complete]:
successlist=thelist[i:complete]
a=i
b=len(thelist)-a
return (a,b)
thelisttest = thelist[0:]
if thelisttest:
return (0,0)
# test
candidatePs = [
[1,],
range(8),
range(4)+range(3,-1,-1),
range(4)+[0]+range(3,-1,-1),
range(3)+range(4)+[0]+range(3,-1,-1),
[8,3,2,3],
]
for p in candidatePs :
print p, isPalindrome( p )
print p, "max", maxPalindrome( p )
I am unsure if what I am doing is considered recursion and I also know the [8,3,2,3] should show max(3,1) and my code spits it out as max (0,0)
Any assistance in my code would be of great help.
def max_palindrome(s, start_at):
# recursion base, a list with only 1 item is a palindrome OR
# a list that's equals to its reverse
if len(s) == 1 or s == s[::-1]:
return (len(s), start_at)
# if we got here the current list is not a palindrome,
# lets try to scan it by taking out one element from each of its sides
return max(max_palindrome(s[1:], start_at+1),
max_palindrome(s[:-1], start_at))
for p in candidatePs :
print p, "max", max_palindrome(p)
output:
[1] max (1, 0)
[0, 1, 2, 3, 4, 5, 6, 7] max (1, 7)
[0, 1, 2, 3, 3, 2, 1, 0] max (8, 0)
[0, 1, 2, 3, 0, 3, 2, 1, 0] max (9, 0)
[0, 1, 2, 0, 1, 2, 3, 0, 3, 2, 1, 0] max (9, 3)
[8, 3, 2, 3] max (3, 1)