changing base of a number to a given number - python

I must write a recursive function that gets a number(n) in the 10 base and converts it to a given number base(k) and return a list which its components are the final number digits,for example f(5, 3) must result [1, 2] which 5 in base 3 is 12, or f(22, 3) must result [2, 1, 1].
Here's the code I tried:
def cb(n, k):
b = []
if n == 0:
b.append(0)
if n < k:
b.append(n)
if n == k:
b.append(10)
else:
a = n // k
b.append(n - ((n // k) * k))
if a < k:
b.append(a)
else:
cb(a, k)
return b
print(cb(22, 3))
Actually I thought a lot on it but since I'm not so good at writing codes I couldn't go any further. I appreciate your help and modifications to my code .

If you think in terms of recursion the base case is when n < k for which the answer is n and to get the last digit of the n you do n%k so the recusive case is cb(n//k,k)+[n%k].
The code will look like this :
def cb(n, k):
if n < k:
return [n]
else:
return cb(n//k, k) + [n%k]
print(cb(22, 3))

you were very close, the only thing that you needed to do was change:
else:
cb(a, k)
to:
else:
b.extend(cb(a, k))
however, your output is going to be:
>>> cb(22, 3)
[1, 1, 2]
which is the reverse of what you want, since 22 in base 3 is 211. you can fix this by either reversing the list [1,1,2][::-1] == [2,1,1] or replace all your calls to append and your new call to extend to instead add at the beginning of the list like: b.insert(0,element) or b = cb(a,k) + b

The biggest problem is that you aren't doing anything with the results of the recursive call, so they never go in your list. I think you are also complicating this too much. Something like this should work:
def cb(n,k):
if n > 0:
q = n // k
r = n - q * k
b = cb(q, k)
b.append(r)
else:
b = [0]
if b[0] == 0 and len(b) > 1:
b = b[1:]
return b
I think if you don't do the last part, then you always get a 0 on the front? You could also simplify it further by just testing to see if it is less than the radix, which gives an even simpler solution
def cb(n,k):
if n < k:
return [n]
else:
q = n // k
r = n - q * k
b = cb(q, k)
b.append(r)
return b

Related

Infinite loop in binary search algorithm

I'm a newbie in algorithms. I have recently started studying binary search and tryed to implement it on my own. The task is simple: we have an array of integers a and an integer x. If a contains x the result should be its index, otherwise the function should return -1.
Here is the code I have written:
def binary_search(a, x):
l = 0
r = len(a)
while r - l > 0:
m = (l + r) // 2
if a[m] < x:
l = m
else:
r = m
if a[l] == x:
return l
return -1
But this code stucks in infinite cycle on a = [1, 2] and x = 2. I suppose, that I have incorrect cycle condition (probably, should be r - l >= 0), but this solution does not help. Where am I wrong?
Let me do some desk checking. I'll assume a = [1, 2] and we are searching for a 2
So we start with
l = 0
r = 2
Since r - l = 2 > 0, we enter the while-loop.
m = (l + r) / 2 = (0 + 2) / 2 = 1
a[m] = a[1] = 2 == x (hence not less than x)
r = m = 1 (and l remains the same)
Now r - l = 1 - 0 = 1 > 0, so we continue
m = (l + r) / 2 = (0 + 1) / 2 = 0
a[m] = a[0] = 1 < x
l = m = 0 (and r remains the same)
After this iteration both r and l have the same value as before, which then produces an endless loop.
Ashok's answer is a great fix. But I think it'll be educational to do some desk checking on the fixed code and look what improves it.
Basically the problematic situation arises, when l + 1 = r.
Then m will always evaluate to l, a[l] < x and l is set to m again, which doesn't change the situation.
In a larger piece of code it'll make sense to make a table that contains a column for each variable to watch and a column to write down the code line that was evaluated. A column for remarks won't harm either.
As Mani mentioned you are not considering when A[m]==x. Include that case (at that point you've found a so just return m), and once you have that case we can let l=m+1 when we are still below x. Like this:
def binary_search(a, x):
l = 0
r = len(a)
while r - l > 0:
m = (l + r) // 2
if a[m] < x:
l = m + 1
elif a[m]==x:
return m
else:
r = m
if l<len(a) and a[l] == x:
return l
return -1

Python / smallest positive integer

I took following codility demo task
Write a function:
def solution(A)
that, given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
For example, given A = [1, 3, 6, 4, 1, 2], the function should return 5.
Given A = [1, 2, 3], the function should return 4.
Given A = [−1, −3], the function should return 1.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [−1,000,000..1,000,000].
My Solution
def solution(A):
# write your code in Python 3.6
l = len(A)
B = []
result = 0
n = 0
for i in range(l):
if A[i] >=1:
B.append(A[i])
if B ==[]:
return(1)
else:
B.sort()
B = list(dict.fromkeys(B))
n = len(B)
for j in range(n-1):
if B[j+1]>B[j]+1:
result = (B[j]+1)
if result != 0:
return(result)
else:
return(B[n-1]+1)
Although I get correct output for all inputs I tried but my score was just 22%. Could somebody please highlight where I am going wrong.
Python solution with O(N) time complexity and O(N) space complexity:
def solution(A):
arr = [0] * 1000001
for a in A:
if a>0:
arr[a] = 1
for i in range(1, 1000000+1):
if arr[i] == 0:
return i
My main idea was to:
creat a zero-initialized "buckets" for all the positive possibilities.
Iterate over A. Whenever you meet a positive number, mark it's bucket as visited (1).
Iterate over the "buckets" and return the first zero "bucket".
def solution(A):
s = set(A)
for x in range(1,100002):
if x not in s:
return x
pass
And GOT 100%
# you can write to stdout for debugging purposes, e.g.
# print("this is a debug message")
def solution(A):
# write your code in Python 3.6
i = 1;
B = set(A);
while True:
if i not in B:
return i;
i+=1;
My Javascript solution. The solution is to sort the array and compare the adjacent elements of the array. Complexity is O(N)
function solution(A) {
// write your code in JavaScript (Node.js 8.9.4)
A.sort((a, b) => a - b);
if (A[0] > 1 || A[A.length - 1] < 0 || A.length <= 2) return 1;
for (let i = 1; i < A.length - 1; ++i) {
if (A[i] > 0 && (A[i + 1] - A[i]) > 1) {
return A[i] + 1;
}
}
return A[A.length - 1] + 1;
}
in Codility you must predict correctly others inputs, not only the sample ones and also get a nice performance. I've done this way:
from collections import Counter
def maior_menos_zero(A):
if A < 0:
return 1
else:
return 1 if A != 1 else 2
def solution(A):
if len(A) > 1:
copia = set(A.copy())
b = max(A)
c = Counter(A)
if len(c) == 1:
return maior_menos_zero(A[0])
elif 1 not in copia:
return 1
else:
for x in range(1,b+2):
if x not in copia:
return x
else:
return maior_menos_zero(A[0])
Got it 100%. If is an array A of len(A) == 1, function maior_menos_zero will be called. Moreover, if it's an len(A) > 1 but its elements are the same (Counter), then function maior_menos_zero will be called again. Finally, if 1 is not in the array, so 1 is the smallest positive integer in it, otherwise 1 is in it and we shall make a for X in range(1,max(A)+2) and check if its elements are in A, futhermore, to save time, the first ocurrence of X not in A is the smallest positive integer.
My solution (100% acceptance):
def solution(nums):
nums_set = set()
for el in nums:
if el > 0 and el not in nums_set:
nums_set.add(el)
sorted_set = sorted(nums_set)
if len(sorted_set) == 0:
return 1
if sorted_set[0] != 1:
return 1
for i in range(0, len(sorted_set) - 1, 1):
diff = sorted_set[i + 1] - sorted_set[i]
if diff >= 2:
return sorted_set[i] + 1
return sorted_set[-1] + 1
I tried the following, and got 100% score
def solution(A):
A_set = set(A)
for x in range(10**5 + 1, 1):
if x not in A_set:
return x
else:
return 10**5 + 1
This solution is an easy approach!
def solution(A):
... A.sort()
... maxval = A[-1]
... nextmaxval = A[-2]
... if maxval < 0:
... while maxval<= 0:
... maxval += 1
... return maxval
... else:
... if nextmaxval + 1 in A:
... return maxval +1
... else:
... return nextmaxval + 1
This is my solution
def solution(A):
# write your code in Python 3.8.10
new = set(A)
max_ = abs(max(A)) #use the absolute here for negative maximum value
for num in range(1,max_+2):
if num not in new:
return num
Try this, I am assuming the list is not sorted but if it is sorted you can remove the number_list = sorted(number_list) to make it a little bit faster.
def get_smallest_positive_integer(number_list):
if all(number < 0 for number in number_list) or 1 not in number_list:
#checks if numbers in list are all negative integers or if 1 is not in list
return 1
else:
try:
#get the smallest number in missing integers
number_list = sorted(number_list) # remove if list is already sorted by default
return min(x for x in range(number_list[0], number_list[-1] + 1) if x not in number_list and x != 0)
except:
#if there is no missing number in list get largest number + 1
return max(number_list) + 1
print(get_smallest_positive_integer(number_list))
input:
number_list = [1,2,3]
output:
>>4
input:
number_list = [-1,-2,-3]
output:
>>1
input:
number_list = [2]
output:
>>1
input:
number_list = [12,1,23,3,4,5,61,7,8,9,11]
output:
>>2
input:
number_list = [-1,3,2,1]
output:
>>4
I think this should be as easy as starting at 1 and checking which number first fails to appear.
def solution(A):
i = 1
while i in A:
i += 1
return i
You can also consider putting A's elements into a set (for better performance on the search), but I'm not sure that it's worth for this case.
Update:
I've been doing some tests with the numbers OP gave (numbers from negative million to positive million and 100000 elements).
100000 elements:
Linear Search: 0.003s
Set Search: 0.017s
1000000 elements (extra test):
Linear Search: 0.8s
Set Search: 2.58s

Python given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A in O(n) time complexity

For example:
input: A = [ 6 4 3 -5 0 2 -7 1 ]
output: 5
Since 5 is the smallest positive integer that does not occur in the array.
I have written two solutions to that problem. The first one is good but I don't want to use any external libraries + its O(n)*log(n) complexity. The second solution "In which I need your help to optimize it" gives an error when the input is chaotic sequences length=10005 (with minus).
Solution 1:
from itertools import count, filterfalse
def minpositive(a):
return(next(filterfalse(set(a).__contains__, count(1))))
Solution 2:
def minpositive(a):
count = 0
b = list(set([i for i in a if i>0]))
if min(b, default = 0) > 1 or min(b, default = 0) == 0 :
min_val = 1
else:
min_val = min([b[i-1]+1 for i, x in enumerate(b) if x - b[i - 1] >1], default=b[-1]+1)
return min_val
Note: This was a demo test in codility, solution 1 got 100% and
solution 2 got 77 %.
Error in "solution2" was due to:
Performance tests ->
medium chaotic sequences length=10005 (with minus) got 3 expected
10000
Performance tests -> large chaotic + many -1, 1, 2, 3 (with
minus) got 5 expected 10000
Testing for the presence of a number in a set is fast in Python so you could try something like this:
def minpositive(a):
A = set(a)
ans = 1
while ans in A:
ans += 1
return ans
Fast for large arrays.
def minpositive(arr):
if 1 not in arr: # protection from error if ( max(arr) < 0 )
return 1
else:
maxArr = max(arr) # find max element in 'arr'
c1 = set(range(2, maxArr+2)) # create array from 2 to max
c2 = c1 - set(arr) # find all positive elements outside the array
return min(c2)
I have an easy solution. No need to sort.
def solution(A):
s = set(A)
m = max(A) + 2
for N in range(1, m):
if N not in s:
return N
return 1
Note: It is 100% total score (Correctness & Performance)
def minpositive(A):
"""Given an list A of N integers,
returns the smallest positive integer (greater than 0)
that does not occur in A in O(n) time complexity
Args:
A: list of integers
Returns:
integer: smallest positive integer
e.g:
A = [1,2,3]
smallest_positive_int = 4
"""
len_nrs_list = len(A)
N = set(range(1, len_nrs_list+2))
return min(N-set(A)) #gets the min value using the N integers
This solution passes the performance test with a score of 100%
def solution(A):
n = sorted(i for i in set(A) if i > 0) # Remove duplicates and negative numbers
if not n:
return 1
ln = len(n)
for i in range(1, ln + 1):
if i != n[i - 1]:
return i
return ln + 1
def solution(A):
B = set(sorted(A))
m = 1
for x in B:
if x == m:
m+=1
return m
Continuing on from Niroj Shrestha and najeeb-jebreel, added an initial portion to avoid iteration in case of a complete set. Especially important if the array is very large.
def smallest_positive_int(A):
sorted_A = sorted(A)
last_in_sorted_A = sorted_A[-1]
#check if straight continuous list
if len(sorted_A) == last_in_sorted_A:
return last_in_sorted_A + 1
else:
#incomplete list, iterate to find the smallest missing number
sol=1
for x in sorted_A:
if x == sol:
sol += 1
else:
break
return sol
A = [1,2,7,4,5,6]
print(smallest_positive_int(A))
This question doesn't really need another answer, but there is a solution that has not been proposed yet, that I believe to be faster than what's been presented so far.
As others have pointed out, we know the answer lies in the range [1, len(A)+1], inclusively. We can turn that into a set and take the minimum element in the set difference with A. That's a good O(N) solution since set operations are O(1).
However, we don't need to use a Python set to store [1, len(A)+1], because we're starting with a dense set. We can use an array instead, which will replace set hashing by list indexing and give us another O(N) solution with a lower constant.
def minpositive(a):
# the "set" of possible answer - values_found[i-1] will tell us whether i is in a
values_found = [False] * (len(a)+1)
# note any values in a in the range [1, len(a)+1] as found
for i in a:
if i > 0 and i <= len(a)+1:
values_found[i-1] = True
# extract the smallest value not found
for i, found in enumerate(values_found):
if not found:
return i+1
We know the final for loop always finds a value that was not marked, because it has one more element than a, so at least one of its cells was not set to True.
def check_min(a):
x= max(a)
if x-1 in a:
return x+1
elif x <= 0:
return 1
else:
return x-1
Correct me if i'm wrong but this works for me.
def solution(A):
clone = 1
A.sort()
for itr in range(max(A) + 2):
if itr not in A and itr >= 1:
clone = itr
break
return clone
print(solution([2,1,4,7]))
#returns 3
def solution(A):
n = 1
for i in A:
if n in A:
n = n+1
else:
return n
return n
def not_in_A(a):
a=sorted(a)
if max(a)<1:
return(1)
for i in range(0,len(a)-1):
if a[i+1]-a[i]>1:
out=a[i]+1
if out==0 or out<1:
continue
return(out)
return(max(a)+1)
mark and then find the first one that didn't find
nums = [ 6, 4, 3, -5, 0, 2, -7, 1 ]
def check_min(nums):
marks = [-1] * len(nums)
for idx, num in enumerate(nums):
if num >= 0:
marks[num] = idx
for idx, mark in enumerate(marks):
if mark == -1:
return idx
return idx + 1
I just modified the answer by #najeeb-jebreel and now the function gives an optimal solution.
def solution(A):
sorted_set = set(sorted(A))
sol = 1
for x in sorted_set:
if x == sol:
sol += 1
else:
break
return sol
I reduced the length of set before comparing
a=[1,222,3,4,24,5,6,7,8,9,10,15,2,3,3,11,-1]
#a=[1,2,3,6,3]
def sol(a_array):
a_set=set()
b_set=set()
cnt=1
for i in a_array:
#In order to get the greater performance
#Checking if element is greater than length+1
#then it can't be output( our result in solution)
if i<=len(a) and i >=1:
a_set.add(i) # Adding array element in set
b_set.add(cnt) # Adding iterator in set
cnt=cnt+1
b_set=b_set.difference(a_set)
if((len(b_set)) > 1):
return(min(b_set))
else:
return max(a_set)+1
sol(a)
def solution(A):
nw_A = sorted(set(A))
if all(i < 0 for i in nw_A):
return 1
else:
ans = 1
while ans in nw_A:
ans += 1
if ans not in nw_A:
return ans
For better performance if there is a possibility to import numpy package.
def solution(A):
import numpy as np
nw_A = np.unique(np.array(A))
if np.all((nw_A < 0)):
return 1
else:
ans = 1
while ans in nw_A:
ans += 1
if ans not in nw_A:
return ans
def solution(A):
# write your code in Python 3.6
min_num = float("inf")
set_A = set(A)
# finding the smallest number
for num in set_A:
if num < min_num:
min_num = num
# print(min_num)
#if negative make positive
if min_num < 0 or min_num == 0:
min_num = 1
# print(min_num)
# if in set add 1 until not
while min_num in set_A:
min_num += 1
return min_num
Not sure why this is not 100% in correctness. It is 100% performance
def solution(A):
arr = set(A)
N = set(range(1, 100001))
while N in arr:
N += 1
return min(N - arr)
solution([1, 2, 6, 4])
#returns 3

Check if a list is a rotation of another list that works with duplicates

I have this function for determining if a list is a rotation of another list:
def isRotation(a,b):
if len(a) != len(b):
return False
c=b*2
i=0
while a[0] != c[i]:
i+=1
for x in a:
if x!= c[i]:
return False
i+=1
return True
e.g.
>>> a = [1,2,3]
>>> b = [2,3,1]
>>> isRotation(a, b)
True
How do I make this work with duplicates? e.g.
a = [3,1,2,3,4]
b = [3,4,3,1,2]
And can it be done in O(n)time?
The following meta-algorithm will solve it.
Build a concatenation of a, e.g., a = [3,1,2,3,4] => aa = [3,1,2,3,4,3,1,2,3,4].
Run any string adaptation of a string-matching algorithm, e.g., Boyer Moore to find b in aa.
One particularly easy implementation, which I would first try, is to use Rabin Karp as the underlying algorithm. In this, you would
calculate the Rabin Fingerprint for b
calculate the Rabin fingerprint for aa[: len(b)], aa[1: len(b) + 1], ..., and compare the lists only when the fingerprints match
Note that
The Rabin fingerprint for a sliding window can be calculated iteratively very efficiently (read about it in the Rabin-Karp link)
If your list is of integers, you actually have a slightly easier time than for strings, as you don't need to think what is the numerical hash value of a letter
-
You can do it in 0(n) time and 0(1) space using a modified version of a maximal suffixes algorithm:
From Jewels of Stringology:
Cyclic equality of words
A rotation of a word u of length n is any word of the form u[k + 1...n][l...k]. Let u, w be two words of the same length n. They are said to be cyclic-equivalent if u(i) == w(j) for some i, j.
If words u and w are written as circles, they are cyclic-equivalent if the circles coincide after appropriate rotations.
There are several linear-time algorithms for testing the cyclic-equivalence
of two words. The simplest one is to apply any string matching algorithm to pattern pat = u and text = ww because words u and w are cyclic=equivalent if pat occurs in text.
Another algorithm is to find maximal suffixes of uu and ww and check if
they are identical on prefixes of size n. We have chosen this problem because there is simpler interesting algorithm, working in linear time and constant space simultaneously, which deserves presentation.
Algorithm Cyclic-Equivalence(u, w)
{ checks cyclic equality of u and w of common length n }
x := uu; y := ww;
i := 0; j := 0;
while (i < n) and (j < n) do begin
k := 1;
while x[i + k] = y[j + k] do k := k + 1;
if k > n then return true;
if x[i + k]> y[i + k] then i := i + k else j := j + k;
{ invariant }
end;
return false;
Which translated to python becomes:
def cyclic_equiv(u, v):
n, i, j = len(u), 0, 0
if n != len(v):
return False
while i < n and j < n:
k = 1
while k <= n and u[(i + k) % n] == v[(j + k) % n]:
k += 1
if k > n:
return True
if u[(i + k) % n] > v[(j + k) % n]:
i += k
else:
j += k
return False
Running a few examples:
In [4]: a = [3,1,2,3,4]
In [5]: b =[3,4,3,1,2]
In [6]: cyclic_equiv(a,b)
Out[6]: True
In [7]: b =[3,4,3,2,1]
In [8]: cyclic_equiv(a,b)
Out[8]: False
In [9]: b =[3,4,3,2]
In [10]: cyclic_equiv(a,b)
Out[10]: False
In [11]: cyclic_equiv([1,2,3],[1,2,3])
Out[11]: True
In [12]: cyclic_equiv([3,1,2],[1,2,3])
Out[12]: True
A more naive approach would be to use a collections.deque to rotate the elements:
def rot(l1,l2):
from collections import deque
if l1 == l2:
return True
# if length is different we cannot get a match
if len(l2) != len(l1):
return False
# if any elements are different we cannot get a match
if set(l1).difference(l2):
return False
l2,l1 = deque(l2),deque(l1)
for i in range(len(l1)):
l2.rotate() # l2.appendleft(d.pop())
if l1 == l2:
return True
return False
I think you could use something like this:
a1 = [3,4,5,1,2,4,2]
a2 = [4,5,1,2,4,2,3]
# Array a2 is rotation of array a1 if it's sublist of a1+a1
def is_rotation(a1, a2):
if len(a1) != len(a2):
return False
double_array = a1 + a1
return check_sublist(double_array, a2)
def check_sublist(a1, a2):
if len(a1) < len(a2):
return False
j = 0
for i in range(len(a1)):
if a1[i] == a2[j]:
j += 1
else:
j = 0
if j == len(a2):
return True
return j == len(a2)
Just common sense if we are talking about interview questions:
we should remember that solution should be easy to code and to describe.
do not try to remember solution on interview. It's better to remember core principle and re-implement it.
Alternatively (I couldn't get the b in aa solution to work), you can 'rotate' your list and check if the rotated list is equal to b:
def is_rotation(a, b):
for n in range(len(a)):
c = c = a[-n:] + a[:-n]
if b == c:
return True
return False
I believe this would be O(n) as it only has one for loop. Hope it helps
This seems to work.
def func(a,b):
if len(a) != len(b):
return False
elif a == b:
return True
indices = [i for i, x in enumerate(b) if x == a[0] and i > 0]
for i in indices:
if a == b[i:] + b[:i]:
return True
return False
And this also:
def func(a, b):
length = len(a)
if length != len(b):
return False
i = 0
while i < length:
if a[0] == b[i]:
j = i
for x in a:
if x != b[j]:
break
j = (j + 1) % length
return True
i += 1
return False
You could try testing the performance of just using the rotate() function in the deque collection:
from collections import deque
def is_rotation(a, b):
if len(a) == len(b):
da = deque(a)
db = deque(b)
for offset in range(len(a)):
if da == db:
return True
da.rotate(1)
return False
In terms of performance, do you need to make this calculation many times for small arrays, or for few times on very large arrays? This would determine whether or not special case testing would speed it up.
If you can represent these as strings instead, just do:
def cyclically_equivalent(a, b):
return len(a) == len(b) and a in 2 * b
Otherwise, one should get a sublist searching algorithm, such as Knuth-Morris-Pratt (Google gives some implementations) and do
def cyclically_equivalent(a, b):
return len(a) == len(b) and sublist_check(a, 2 * b)
Knuth-Morris-Pratt algorithm is a string search algorithm that runs in O(n) where n is the length of a text S (assuming the existence of preconstructed table T, which runs in O(m) where m is the length of the search string). All in all it is O(n+m).
You could do a similar pattern matching algorithm inspired by KMP.
Concatenate a list to itself, like a+a or b+b - this is the searched text/list with 2*n elements
Build the table T based on the other list (be it b or a) - this is done in O(n)
Run the KMP inspired algorithm - this is done in O(2*n) (because you concatenate a list to itself)
Overall time complexity is O(2*n+n) = O(3*n) which is in O(n)

Alternating counters in Python (Fibonacci Plot)

I've been assigned a project in my computing class to do a report on some area of mathematics in LaTeX, using Python 2.7 code - I chose the Fibonacci sequence.
As part of my project I wanted to include a plot of the Fibonacci 'spiral' which is actually comprised of a series of quarter-circles of increasing radii. As such, I've tried to define a function to give a loop that returns the centres of these quarter-circles so I can create a plot. Using pen and paper I have found the centres of each quarter-circle and noticed that with each new quarter-circle there's an exchange of coordinates - ie. if n is even, the x-coordinate of the previous centre remains the x-coordinate for the nth centre; similarly, when n is odd, the y-coordinate remains the same.
My problem arises with the other coordinate. They work on an alternating pattern of + or - the (n-2)th Fibonacci number to the y-coordinate (for even n) or x-coordinate (for odd) of the previous centre.
I've created the following loop in SageMathCloud, but I think I've deduced that my counters aren't incrementing when I wanted them to:
def centrecoords(n):
k = 0
l = 1
if fib(n) == 1:
return tuple((0,-1))
elif n % 2 == 0 and k % 2 == 0:
return tuple((centrecoords(n-1)[0], centrecoords(n-1)[1] + ((-1) ** k) * fib(n - 2)))
k += 1
elif n % 2 == 0:
return tuple((centrecoords(n-1)[0], centrecoords(n-1)[1] + ((-1) ** k) * fib(n - 2)))
elif n % 2 != 0 and l % 2 == 0:
return tuple((centrecoords(n-1)[0] + ((-1) ** l) * fib(n - 2), centrecoords(n-1)[1]))
l += 1
else:
return tuple((centrecoords(n-1)[0] + ((-1) ** l) * fib(n - 2), centrecoords(n-1)[1]))
cen_coords = []
for i in range(0, 21):
cen_coords.append(centrecoords(i))
cen_coords
Any help in making the k counter increment with its if statement only, and the same with the l counter would be greatly appreciated.
Your problem is that k and l are local variables. As such they are lost every time the function exits, and re-start at zero and one respectively when is called again (yes, even when it's called from itself).
Nick's code aims to store a single instance each of k and l in the top-level function, sharing them with the recursive calls.
Another reasonable approach might be to rewrite your recursion as a loop, and yield the sequence. This makes it trivial to keep the state of k and l, as your locals are preserved.
Or, you could re-write your function as a class method, and make k and l instance variables. This behaves similarly, with the instance storing your intermediate state between calls to centrecoords.
Apart from all of these, your code looks like it requires each call to centrecoords to receive the next value of n. So, even if you fix the state problem, this is a poor design.
I'd suggest going the generator route, and taking a single argument, the maximum value of n. Then you can iterate over range(n), yielding each result in turn. Note also that your only recursive call is for n-1, which is just your previous iteration, so you can simply remember it.
Quick demo: I haven't tested this, or checked the corner cases ...
def fib(n):
if n < 2:
return 1
return fib(n-1) + fib(n-2)
def centrecoords(max_n):
# initial values
k = 0
l = 1
result=(0,-1)
# note fib(0) == fib(1) == 1
for n in range(2,max_n):
if n % 2 == 0:
result = (result[0], result[1] + ((-1) ** k) * fib(n - 2))
yield result
if k % 2 == 0:
k += 1
else:
result = (result[0] + ((-1) ** l) * fib(n - 2), result[1])
yield result
if l % 2 == 0:
l += 1
cen_coords = list(centrecoords(21))
Expanding on my comment. Your code could look something like the one below. But please not that you might need to adjust starting values of k and l to -1 and 0 correspondingly, because k and l are incremented before recursion calls (opposite to your code which implied that first a recursion is called and only then k and l are increased).
I also deleted tuple, it is unnecessary in python and hard to read, to create a tuple use comma syntax, e.g.: 1, 2.
Also n == 0 (fib(n) == 0) should be considered as special case, or you program will enter infinite recursion and crash when centrecoords called with n=0.
I have no account on SageMathCloud to test it, but it at least should fix counters increment.
def centrecoords(n, k=0, l=1):
if n == 0:
return 0, 0 # this is pure guess and most likely incorrect, but n == 0 (or fib(n) == 0 should be handled separatly)
if fib(n) == 1:
return 0, -1
elif n % 2 == 0 and k % 2 == 0:
k += 1
return centrecoords(n-1, k, l)[0], centrecoords(n-1, k, l)[1] + ((-1) ** k) * fib(n - 2)
elif n % 2 == 0:
return centrecoords(n-1, k, l)[0], centrecoords(n-1, k, l)[1] + ((-1) ** k) * fib(n - 2)
elif n % 2 != 0 and l % 2 == 0:
l += 1
return centrecoords(n-1, k, l)[0] + ((-1) ** l) * fib(n - 2), centrecoords(n-1, k, l)[1]
else:
return centrecoords(n-1, k, l)[0] + ((-1) ** l) * fib(n - 2), centrecoords(n-1, k, l)[1]
cen_coords = []
for i in range(0, 21):
cen_coords.append(centrecoords(i))
cen_coords

Categories

Resources