Fibonacci series in bit string - python

I am working on Fibonacci series but in bit string which can be represented as:
f(0)=0;
f(1)=1;
f(2)=10;
f(3)=101;
f(4)=10110;
f(5)=10110101;
Secondly, I have a pattern for example '10' and want to count how many times this occurs in particular series, for example, the Fibonacci series for 5 is '101101101' so '10' occur 3 times.
my code is running correctly without error but the problem is that it cannot run for more than the value of n=45 I want to run n=100
can anyone help? I only want to calculate the count of occurrence
n=5
fibonacci_numbers = ['0', '1']
for i in range(1,n):
fibonacci_numbers.append(fibonacci_numbers[i]+fibonacci_numbers[i-1])
#print(fibonacci_numbers[-1])
print(fibonacci_numbers[-1])
nStr = str (fibonacci_numbers[-1])
pattern = '10'
count = 0
flag = True
start = 0
while flag:
a = nStr.find(pattern, start)
if a == -1:
flag = False
else:
count += 1
start = a + 1
print(count)

This is a fun one! The trick is that you don't actually need that giant bit string, just the number of 10s it contains and the edges. This solution runs in O(n) time and O(1) space.
from typing import NamedTuple
class FibString(NamedTuple):
"""First digit, last digit, and the number of 10s in between."""
first: int
tens: int
last: int
def count_fib_string_tens(n: int) -> int:
"""Count the number of 10s in a n-'Fibonacci bitstring'."""
def combine(b: FibString, a: FibString) -> FibString:
"""Combine two FibStrings."""
tens = b.tens + a.tens
# mind the edges!
if b.last == 1 and a.first == 0:
tens += 1
return FibString(b.first, tens, a.last)
# First two values are 0 and 1 (tens=0 for both)
a, b = FibString(0, 0, 0), FibString(1, 0, 1)
for _ in range(1, n):
a, b = b, combine(b, a)
return b.tens # tada!
I tested this against your original implementation and sure enough it produces the same answers for all values that the original function is able to calculate (but it's about eight orders of magnitude faster by the time you get up to n=40). The answer for n=100 is 218922995834555169026 and it took 0.1ms to calculate using this method.

The nice thing about the Fibonacci sequence that will solve your issue is that you only need the last two values of the sequence. 10110 is made by combining 101 and 10. After that 10 is no longer needed. So instead of appending, you can just keep the two values. Here is what I've done:
n=45
fibonacci_numbers = ['0', '1']
for i in range(1,n):
temp = fibonacci_numbers[1]
fibonacci_numbers[1] = fibonacci_numbers[1] + fibonacci_numbers[0]
fibonacci_numbers[0] = temp
Note that it still uses a decent amount of memory, but it didn't give me a memory error (it does take a bit of time to run though).
I also wasn't able to print the full string as I got an OSError [Errno 5] Input/Output error but it can still count and print that output.
For larger numbers, storing as a string is going to quickly cause a memory issue. In that case, I'd suggest doing the fibonacci sequence with plain integers and then converting to bits. See here for tips on binary conversion.
While the regular fibonacci sequence doesn't work in a direct sense, consider that 10 is 2 and 101 is 5. 5+2 doesn't work - you want 10110 or an or operation 10100 | 10 yielding 22; so if you shift one by the length of the other, you can get the result. See for example
x = 5
y = 2
(x << 2) | y
>> 22
Shifting x by the number of bits representing y and then doing a bitwise or with | solves the issue. Python summarizes these bitwise operations well here. All that's left for you to do is determine how many bits to shift and implement this into your for loop!
For really large n you will still have a memory issue shown in the plot:
'

Finally i got the answer but can someone explain it briefly why it is working
def count(p, n):
count = 0
i = n.find(p)
while i != -1:
n = n[i + 1:]
i = n.find(p)
count += 1
return count
def occurence(p, n):
a1 = "1"
a0 = "0"
lp = len(p)
i = 1
if n <= 5:
return count(p, atring(n))
while lp > len(a1):
temp = a1
a1 += a0
a0 = temp
i += 1
if i >= n:
return count(p, a1)
fn = a1[:lp - 1]
if -lp + 1 < 0:
ln = a1[-lp + 1:]
else:
ln = ""
countn = count(p, a1)
a1 = a1 + a0
i += 1
if -lp + 1 < 0:
lnp1 = a1[-lp + 1:]
else:
lnp1 = ""
k = 0
countn1 = count(p, a1)
for j in range(i + 1, n + 1):
temp = countn1
countn1 += countn
countn = temp
if k % 2 == 0:
string = lnp1 + fn
else:
string = ln + fn
k += 1
countn1 += count(p, string)
return countn1
def atring(n):
a0 = "0"
a1 = "1"
if n == 0 or n == 1:
return str(n)
for i in range(2, n + 1):
temp = a1
a1 += a0
a0 = temp
return a1
def fn():
a = 100
p = '10'
print( occurence(p, a))
if __name__ == "__main__":
fn()

Related

Python code for hailstone nums to check if the numbers are converging or not & also to findout how many diff holding pattern the sequence converges to

Recall in class that we discussed the hailstone numbers where xn = 3xn−1 +1 if xn−1 is odd and xn = xn−1/2 ifxn−1 iseven. Thehailstonenumbersconvergetoasortofholdingpattern4→2→1→4→2→1→ 4 → 2 → 1. We call this kind of pattern a convergence because it repeats.
Write a program to test generalized hailstone numbers where xn = axn−1 + b if xn−1 is odd and xn = xn−1/2 if xn−1 is even where a and b are positive integers. For each of the a, b pairs less than or equal to 10, find whether or not the sequence seems to converge. Once you can do that, tell me how many different holding patternsthesequenceconvergesto. Forinstance,whena=3andb=5then1→8→4→2→1this is holding pattern. However, if we start with a different number, say 5 we get a different holding pattern 5 → 20 → 10 → 5.
def validation(x,a,b):
steps = 1
start = x
set1 = set()
while x not in set1:
steps += 1
set1.add(x)
if x % 2 == 0:
x = x//2
else:
x = a*x + b
if steps == 100:
break;
if x == start:
return True
else:
return False
def hailstone(number):
List = []
for i in range(1,11):
for j in range(1,11):
count = 0
for x in range(1, number+1):
if (((i%2 != 0 ) and (j%2 == 0)) or ((i%2 == 0 ) and (j%2 != 0))):
break
else:
if validation(x,i,j): #calling 'validation' to check if it is true
count += 1
List.append([i,j,count])
return(List)
pattern_count = hailstone(number = 100)
print(pattern_count)

Optimizing the algorithm for brute force numbers in the problem

How many pairs (i, j) exist such that 1 <= i <= j <= n, j - i <= a?
'n' and 'a' input numbers.
The problem is my algorithm is too slow when increasing 'n' or 'a'.
I cannot think of a correct algorithm.
Execution time must be less than 10 seconds.
Tests:
n = 3
a = 1
Number of pairs = 5
n = 5
a = 4
Number of pairs = 15
n = 10
a = 5
Number of pairs = 45
n = 100
a = 0
Number of pairs = 100
n = 1000000
a = 333333
Number of pairs = 277778388889
n = 100000
a = 555555
Number of pairs = 5000050000
n = 1000000
a = 1000000
Number of pairs = 500000500000
n = 998999
a = 400000
Number of pairs = 319600398999
n = 898982
a = 40000
Number of pairs = 35160158982
n, a = input().split()
i = 1
j = 1
answer = 0
while True:
if n >= j:
if a >= (j-i):
answer += 1
j += 1
else:
i += 1
j = i
if j > n:
break
else:
i += 1
j = i
if j > n:
break
print(answer)
One can derive a direct formula to solve this problem.
ans = ((a+1)*a)/2 + (a+1) + (a+1)*(n-a-1)
Thus the time complexity is O(1). This is the fastest way to solve this problem.
Derivation:
The first a number can have pairs of (a+1)C2 + (a+1).
Every additional number has 'a+1' options to pair with. So, therefore, there are n-a-1 number remaining and have (a+1) options, (a+1)*(n-a-1)
Therefore the final answer is (a+1)C2 + (a+1) + (a+1)*(n-a-1) implies ((a+1)*a)/2 + (a+1) + (a+1)*(n-a-1).
You are using a quadratic algorithm but you should be able to get it to linear (or perhaps even better).
The main problem is to determine how many pairs, given i and j. It is natural to split that off into a function.
A key point is that, for i fixed, the j which go with that i are in the range i to min(n,i+a). This is since j-i <= a is equivalent to j <= i+a.
There are min(n,i+a) - i + 1 valid j for a given i. This leads to:
def count_pairs(n,a):
return sum(min(n,i+a) - i + 1 for i in range(1,n+1))
count_pairs(898982,40000) evaluates to 35160158982 in about a second. If that is still to slow, do some more mathematical analysis.
Here is an improvement:
n, a = map(int, input().split())
i = 1
j = 1
answer = 0
while True:
if n >= j <= a + i:
answer += 1
j += 1
continue
i = j = i + 1
if j > n:
break
print(answer)

Recursion gives me completely wrong answers

I want to find the number of ways, a given integer X can be decomposed into sums of numbers which are N-th powers and every summand must be unique. For example if X = 10 and N=3, I can decompose this number like that:
10 = 2^3+1^3+1^3 ,but this is not a valid decomposition, because the number 1 appears twice. A valid decomposition for X = 10 and N = 2 would be 10 = 3^2+1^2, since no summand is repeating here.
Now I tried it to use recursion and created the following Python Code
st = set(range(1,int(pow(X,1/float(N))))) # generate set of unique numbers
print(str(ps(X, N, st)))
def ps(x, n, s):
res = 0
for c in s:
chk = x-pow(c,n) # test validity
if chk > 0:
ns = s-set([c])
res += ps(chk,n,ns)
elif chk == 0:
res += 1 # one result is found
else:
res += 0 # no valid result
return res
I used a set called st and then I recursively called the function ps that includes the base case "decomposition found" and "decomposition not found". Moreover it reduces a larger number to a smaller one by considering only the ways how to decompose a given number into only two summands.
Unfortunately, I get completely wrong results, e.g.
X = 100, N = 3: Outputs 0, Expected 1
X = 100, N = 2: Outputs 122, Expected 3
X = 10, N = 2: Outputs 0, Expected 1
My thoughts are correct, but I think the Problem is anywhere in the recursion. Does anybody see what I make wrong? Any help would be greatly appreciated.
Hint:
>>> X = 100
>>> N = 3
>>> int(pow(X, 1/float(N)))
4
>>> list(range(1, 4))
[1, 2, 3]
The output is indeed correct for the input you are feeding it.
The problem is line res += 1 # one result is found in conjuction with res += ps(chk,n,ns) will make the algorithm add twice.
E.g X = 10, N = 2: Outputs 0, Expected 1 because:
c=1:
10 - 1^2 > 0 -> res += ps(chk,n,ns)
c=3:
9 - 3^2 == 0 -> res += 1 # one result is found ... return res
So, in c=3 res=1 is returned to the c=1 call, which will
res += ps(chk,n,ns), and ps(chk,n,ns) = 1, making res = 2 and doubling the result expected.
E.g. X = 29, N = 2.
29 = 2^2 + 3^2 + 4^2
Solving from bottom to top (the algorithm flow):
c=4 -> res += 1... return res
c=3 -> res += ps() -> res += 1 -> res = 2 ... return res
c=2 -> res += ps() -> res += 2 -> res = 4 ... return res
But res is supposed to be 1.
Solution: You cannot add res to res. And you must remove the previous iterated objects to avoid path repetition. Check the solution below (with prints for better understanding):
def ps(x, n, s):
print(s)
print("")
return ps_aux(x, n, s, 0) # level
def ps_aux(x, n, s, level):
sum = 0
for idx, c in enumerate(s):
print("----> " * level + "C = {}".format(c))
chk = x - pow(c,n) # test validity
if chk > 0:
ns = s[idx + 1:]
sum += ps_aux(chk,n,ns, level + 1)
elif chk == 0:
print("OK!")
sum += 1 # one result is found
else:
sum += 0 # no valid result
return sum
Try with:
X=10 # 1 solution
N=2
st = list(range(1,int(pow(X,1/float(N))) + 1 )) # generate set of unique numbers
print(str(ps(X, N, st)))
X=25 # 2 solutions [3,4], [5]
N=2
st = list(range(1,int(pow(X,1/float(N))) + 1 )) # generate set of unique numbers
print(str(ps(X, N, st)))

Sum of subsequences recursion in Python

Over the weekend I was working on the Ad Infinitum challenge on HackerRank.
One problem was to calculate the sum of all subsequences of a finite sequence, if each subsequence is thought of as an integer.
For example, sequence 4,5,6 would give answer 4 + 5 + 6 + 45 + 46 + 56 + 456 = 618.
I found a recursion and wrote the Python code below. It solved 5/13 test cases.
The remaining 8/13 test cases had runtime errors.
I was hoping someone could spy where in the code the inefficiencies lie, and how they can be sped up. Or, help me decide that it must be that my recursion is not the best strategy.
# Input is a list, representing the given sequence, e.g. L = [4,5,6]
def T(L):
limit = 10**9 + 7 # answer is returned modulo 10**9 + 7
N = len(L)
if N == 1:
return L[0]
else:
last = L[-1]
K = L[:N-1]
ans = T(K)%limit + 10*T(K)%limit + (last%limit)*pow(2,N-1,limit)
return ans%limit
This is my submission for the same problem (Manasa and Sub-sequences).
https://www.hackerrank.com/contests/infinitum-may14/challenges/manasa-and-sub-sequences
I hope this will help you to think of a better way.
ans = 0
count = 0
for item in raw_input():
temp = (ans * 10 + (count + 1)*(int(item)))%1000000007
ans = (ans + temp)%1000000007
count = (count*2 + 1)%1000000007
print ans
Well, you want the combinations:
from itertools import combinations
def all_combinations(iterable):
for r in range(len(digits)):
yield from combinations(digits, r+1)
And you want to convert them to integers:
def digits_to_int(digits):
return sum(10**i * digit for i, digit in enumerate(reversed(digits)))
And you want to sum them:
sum(map(digits_to_int, all_combinations([4, 5, 6])))
Then focus on speed.
Assuming you mean continuous subsequence.
test = [4, 5, 6]
def coms(ilist):
olist = []
ilist_len = len(ilist)
for win_size in range(ilist_len, 0, -1):
for offset in range((ilist_len - win_size) + 1):
subslice = ilist[offset: offset + win_size]
sublist = [value * (10 ** power) for (power, value) in enumerate(reversed(subslice))]
olist.extend(sublist)
return olist
print sum(coms(test))

How to produce the i-th combination/permutation without iterating

Given any iterable, for example: "ABCDEF"
Treating it almost like a numeral system as such:
A
B
C
D
E
F
AA
AB
AC
AD
AE
AF
BA
BB
BC
....
FF
AAA
AAB
....
How would I go about finding the ith member in this list? Efficiently, not by counting up through all of them. I want to find the billionth (for example) member in this list. I'm trying to do this in python and I am using 2.4 (not by choice) which might be relevant because I do not have access to itertools.
Nice, but not required: Could the solution be generalized for pseudo-"mixed radix" system?
--- RESULTS ---
# ------ paul -----
def f0(x, alph='ABCDE'):
result = ''
ct = len(alph)
while x>=0:
result += alph[x%ct]
x /= ct-1
return result[::-1]
# ----- Glenn Maynard -----
import math
def idx_to_length_and_value(n, length):
chars = 1
while True:
cnt = pow(length, chars)
if cnt > n:
return chars, n
chars += 1
n -= cnt
def conv_base(chars, n, values):
ret = []
for i in range(0, chars):
c = values[n % len(values)]
ret.append(c)
n /= len(values)
return reversed(ret)
def f1(i, values = "ABCDEF"):
chars, n = idx_to_length_and_value(i, len(values))
return "".join(conv_base(chars, n, values))
# -------- Laurence Gonsalves ------
def f2(i, seq):
seq = tuple(seq)
n = len(seq)
max = n # number of perms with 'digits' digits
digits = 1
last_max = 0
while i >= max:
last_max = max
max = n * (max + 1)
digits += 1
result = ''
i -= last_max
while digits:
digits -= 1
result = seq[i % n] + result
i //= n
return result
# -------- yairchu -------
def f3(x, alphabet = 'ABCDEF'):
x += 1 # Make us skip "" as a valid word
group_size = 1
num_letters = 0
while 1: #for num_letters in itertools.count():
if x < group_size:
break
x -= group_size
group_size *= len(alphabet)
num_letters +=1
letters = []
for i in range(num_letters):
x, m = divmod(x, len(alphabet))
letters.append(alphabet[m])
return ''.join(reversed(letters))
# ----- testing ----
import time
import random
tries = [random.randint(1,1000000000000) for i in range(10000)]
numbs = 'ABCDEF'
time0 = time.time()
s0 = [f1(i, numbs) for i in tries]
print 's0 paul',time.time()-time0, 'sec'
time0 = time.time()
s1 = [f1(i, numbs) for i in tries]
print 's1 Glenn Maynard',time.time()-time0, 'sec'
time0 = time.time()
s2 = [f2(i, numbs) for i in tries]
print 's2 Laurence Gonsalves',time.time()-time0, 'sec'
time0 = time.time()
s3 = [f3(i,numbs) for i in tries]
print 's3 yairchu',time.time()-time0, 'sec'
times:
s0 paul 0.470999956131 sec
s1 Glenn Maynard 0.472999811172 sec
s2 Laurence Gonsalves 0.259000062943 sec
s3 yairchu 0.325000047684 sec
>>> s0==s1==s2==s3
True
Third time's the charm:
def perm(i, seq):
seq = tuple(seq)
n = len(seq)
max = n # number of perms with 'digits' digits
digits = 1
last_max = 0
while i >= max:
last_max = max
max = n * (max + 1)
digits += 1
result = ''
i -= last_max
while digits:
digits -= 1
result = seq[i % n] + result
i //= n
return result
Multi-radix solution at the bottom.
import math
def idx_to_length_and_value(n, length):
chars = 1
while True:
cnt = pow(length, chars)
if cnt > n:
return chars, n
chars += 1
n -= cnt
def conv_base(chars, n, values):
ret = []
for i in range(0, chars):
c = values[n % len(values)]
ret.append(c)
n /= len(values)
return reversed(ret)
values = "ABCDEF"
for i in range(0, 100):
chars, n = idx_to_length_and_value(i, len(values))
print "".join(conv_base(chars, n, values))
import math
def get_max_value_for_digits(digits_list):
max_vals = []
for val in digits_list:
val = len(val)
if max_vals:
val *= max_vals[-1]
max_vals.append(val)
return max_vals
def idx_to_length_and_value(n, digits_list):
chars = 1
max_vals = get_max_value_for_digits(digits_list)
while True:
if chars-1 >= len(max_vals):
raise OverflowError, "number not representable"
max_val = max_vals[chars-1]
if n < max_val:
return chars, n
chars += 1
n -= max_val
def conv_base(chars, n, digits_list):
ret = []
for i in range(chars-1, -1, -1):
digits = digits_list[i]
radix = len(digits)
c = digits[n % len(digits)]
ret.append(c)
n /= radix
return reversed(ret)
digits_list = ["ABCDEF", "ABC", "AB"]
for i in range(0, 120):
chars, n = idx_to_length_and_value(i, digits_list)
print "".join(conv_base(chars, n, digits_list))
What you're doing is close to a conversion from base 10 (your number) to base 6, with ABCDEF being your digits. The only difference is "AA" and "A" are different, which is wrong if you consider "A" the zero-digit.
If you add the next greater power of six to your number, and then do a base conversion to base 6 using these digits, and finally strip the first digit (which should be a "B", i.e. a "1"), you've got the result.
I just want to post an idea here, not an implementation, because the question smells a lot like homework to me (I do give the benefit of the doubt; it's just my feeling).
First compute the length by summing up powers of six until you exceed your index (or better use the formula for the geometric series).
Subtract the sum of smaller powers from the index.
Compute the representation to base 6, fill leading zeros and map 0 -> A, ..., 5 -> F.
This works (and is what i finally settled on), and thought it was worth posting because it is tidy. However it is slower than most answers. Can i perform % and / in the same operation?
def f0(x, alph='ABCDE'):
result = ''
ct = len(alph)
while x>=0:
result += alph[x%ct]
x /= ct-1
return result[::-1]
alphabet = 'ABCDEF'
def idx_to_excel_column_name(x):
x += 1 # Make us skip "" as a valid word
group_size = 1
for num_letters in itertools.count():
if x < group_size:
break
x -= group_size
group_size *= len(alphabet)
letters = []
for i in range(num_letters):
x, m = divmod(x, len(alphabet))
letters.append(alphabet[m])
return ''.join(reversed(letters))
def excel_column_name_to_idx(name):
q = len(alphabet)
x = 0
for letter in name:
x *= q
x += alphabet.index(letter)
return x+q**len(name)//(q-1)-1
Since we are converting from a number Base(10) to a number Base(7), whilst avoiding all "0" in the output, we will have to adjust the orginal number, so we do skip by one every time the result would contain a "0".
1 => A, or 1 in base [0ABCDEF]
7 => AA, or 8 in base [0ABCDEF]
13 => BA, or 15 in base [0ABCDEF]
42 => FF, or 48 in base [0ABCDEF]
43 =>AAA, or 50 in base [0ABCDEF]
Here's some Perl code that shows what I'm trying to explain
(sorry, didn't see this is a Python request)
use strict;
use warnings;
my #Symbols=qw/0 A B C D E F/;
my $BaseSize=#Symbols ;
for my $NR ( 1 .. 45) {
printf ("Convert %3i => %s\n",$NR ,convert($NR));
}
sub convert {
my ($nr,$res)=#_;
return $res unless $nr>0;
$res="" unless defined($res);
#Adjust to skip '0'
$nr=$nr + int(($nr-1)/($BaseSize-1));
return convert(int($nr/$BaseSize),$Symbols[($nr % ($BaseSize))] . $res);
}
In perl you'd just convert your input i from base(10) to base(length of "ABCDEF"), then do a tr/012345/ABCDEF/ which is the same as y/0-5/A-F/. Surely Python has a similar feature set.
Oh, as pointed out by Yarichu the combinations are a tad different because if A represented 0, then there would be no combinations with leading A (though he said it a bit different). It seems I thought the problem to be more trivial than it is. You cannot just transliterate different base numbers, because numbers containing the equivalent of 0 would be
skipped in the sequence.
So what I suggested is actually only the last step of what starblue suggested, which is essentially what Laurence Gonsalves implemented ftw. Oh, and there is no transliteration (tr// or y//) operation in Python, what a shame.

Categories

Resources