Find maximum binary number with rotations, exceed time limit - python

Passed some test cases, but after submission, the time limit exceeded. How to optimize solution to reduce time complexity?
A large binary number is represented by a string A of size N and
comprises of 0s and 1s. You must perform a cyclic shift on this
string. The cyclic shift operation is defined as follows:
If the string A is [A0, A1,..., An-1], then after performing one
cyclic shift, the string becomes [A1, A2,..., An-1, A0].
You performed the shift infinite number of times and each time you
recorded the value of the binary number represented by the string. The
maximum binary number formed after performing (possibly 0) the
operation is B. Your task is to determine the number of cyclic shifts
that can be performed such that the value represented by the string A
will be equal to B for the Kth time.
Input format:
First line: A single integer T denoting the number of test cases For
each test case: First line: Two space-separated integers N and K
Second line: A denoting the string
Output format:
For each test case, print a single line containing one integer that
represents the number of cyclic shift operations performed such that
the value represented by string A is equal to B for the Kth time.
num_test_cases = int(input())
for i in range(num_test_cases):
array_length, num_of_repetition = map(int, input().split())
count = 0
bin_num = input()
original_bin_num = bin_num
dec_num = int(bin_num, 2)
maximum = dec_num
dec_num_array = [dec_num]
for j in range(array_length - 1):
bin_num = bin_num[1:] + bin_num[0]
if bin_num == original_bin_num:
break
dec_num = int(bin_num, 2)
dec_num_array.append(dec_num)
maximum = max(dec_num_array)
maxIndex = dec_num_array.index(maximum)
num_cyclic_shifts = 0
for kek in range(num_of_repetition):
if kek == 0:
num_cyclic_shifts += maxIndex
elif len(dec_num_array) == array_length:
num_cyclic_shifts += array_length
elif len(dec_num_array) < array_length:
num_cyclic_shifts += len(dec_num_array)
print(num_cyclic_shifts)

Since you asked for optimization of your code here's how I did it.
Replace the last for loop with a formula.
num_cyclic_shifts = maxIndex + (len(dec_num_array) * (num_of_repetition-1))
Entire code will become ,
num_test_cases = int(input())
for i in range(num_test_cases):
array_length, num_of_repetition = map(int, input().split())
count = 0
bin_num = input()
original_bin_num = bin_num
dec_num = int(bin_num, 2)
maximum = dec_num
dec_num_array = [dec_num]
for j in range(array_length - 1):
bin_num = bin_num[1:] + bin_num[0]
if bin_num == original_bin_num:
break
dec_num = int(bin_num, 2)
dec_num_array.append(dec_num)
maximum = max(dec_num_array)
maxIndex = dec_num_array.index(maximum)
num_cyclic_shifts = maxIndex + (len(dec_num_array) * (num_of_repetition-1))
print(num_cyclic_shifts)

Related

Conversion of denary number to binary number problem (Python)

Im stuck on a problem where I have to write a function that converts a denary number into a binary number using the repeated division by two algorithm. Steps Include:
The number to be converted is divided by two.
The remainder from the division is the next binary digit. Digits are added to the front of the sequence.
The result is truncated so that the input to the next division by two is always an integer.
The algorithm continues until the result is 0.
Please click the link below to see what the output should be like:
https://i.stack.imgur.com/pifUO.png
def dentobi(user):
denary = user
divide = user / 2
remainder = user % 2
binary = remainder
if user != 0:
print("Denary:", denary)
print("Divide by 2:", divide)
print("Remainder:", remainder)
print("Binary:", binary)
user = int(input("Please enter a number: "))
dentobi(user)
This is what I have done so far but Im not getting anywhere.
Can someone explain how I would do this?
The Answer provided by #user2390182 is functionally correct except that it returns an empty string when num is zero. However, I have noted on several occasions that divmod() is rather slow. Here are three slightly different techniques and their performance statistics.
import time
# This is the OP's original code edited to allow for num == 0
def binaryx(num):
b = ""
while num:
num, digit = divmod(num, 2)
b = f"{digit}{b}"
return b or '0'
# This is my preferred solution
def binaryo(n):
r = []
while n > 0:
r.append('1' if n & 1 else '0')
n >>= 1
return ''.join(reversed(r)) or '0'
# This uses techniques suggested by my namesake
def binaryy(n):
r = ''
while n > 0:
r = str(n & 1) + r
n >>= 1
return r or '0'
M = 250_000
for func in [binaryx, binaryo, binaryy]:
s = time.perf_counter()
for _ in range(M):
func(987654321)
e = time.perf_counter()
print(f'{func.__name__} -> {e-s:.4f}s')
Output:
binaryx -> 1.3817s
binaryo -> 0.9861s
binaryy -> 1.6052s
One way, using divmod to divide by 2 and get the remainder in one step:
def binary(num):
b = ""
while num:
num, digit = divmod(num, 2)
b = f"{digit}{b}"
return b
binary(26)
'11010'
This assumes a positive number but can easily be extended to work for 0 and negatives.

Returns the largest n such that R[n] = S

Write a function answer(str_S) which, given the base-10 string
representation of an integer S, returns the largest n such that R(n) =
S. Return the answer as a string in base-10 representation. If there
is no such n, return "None". S will be a positive integer no greater
than 10^25.
where R(n) is the number of zombits at time n:
R(0) = 1
R(1) = 1
R(2) = 2
R(2n) = R(n) + R(n + 1) + n (for n > 1)
R(2n + 1) = R(n - 1) + R(n) + 1 (for n >= 1)
Test cases
==========
Inputs:
(string) str_S = "7"
Output:
(string) "4"
Inputs:
(string) str_S = "100"
Output:
(string) "None"
My program below is correct but it is not scalable since here the range of S can be a very large number like 10^24. Could anyone help me with some suggestion to improve the code further so that it can cover any input case.
def answer(str_S):
d = {0: 1, 1: 1, 2: 2}
str_S = int(str_S)
i = 1
while True:
if i > 1:
d[i*2] = d[i] + d[i+1] + i
if d[i*2] == str_S:
return i*2
elif d[i*2] > str_S:
return None
if i>=1:
d[i*2+1] = d[i-1] + d[i] + 1
if d[i*2+1] == str_S:
return i*2 + 1
elif d[i*2+1] > str_S:
return None
i += 1
print answer('7')
First of all, where are you having trouble with the scaling? I ran your code on a 30-digit number, and it seemed to complete okay. Do you have a memory limit? Python handles arbitrarily large integers, although very large ones get flipped into digital arithmetic mode.
Given the density of R values, I suspect that you can save space as well as time if you switch to a straight array: use the value as an array index instead of a dict key.

Number of numbers divisible by a prime number in a row to pascal triangle

How can i find the total number of numbers in a given row number of a pascal triangle divisible by a prime number in which the row number and prime is given
I am using the following code in python
def factorial(x):
result = 1
for i in xrange(1,x+1):
result *= i
return result
def combination(n,r):
return factorial(n)/(factorial(n-r)*factorial(r))
p = input()
cnt = 0
for i in range(0,n+1):
if((combination(n,i)%p)==0):
cnt += 1
print cnt
but the given code takes long time for big numbers.
Can you please suggest me a better algorithm.
One corollary from Luca's theorem states that number of binomial coefficients C(n,k) which are not divisible by prime p, is
(a₁+1)⋅(a₂+1)⋅...⋅(am+1), where ai is ith digit of n in p-ary numeral system.
Example:
p = 3, n = 7dec = 213
Result = (2+1)⋅(1+1) = 6
7th row of Pascal triangle is 1 7 21 35 35 21 7 1, it contains 6 coefficients not divisible by 3, and the two remaining are divisible by 3.
You do not need to compute the binomial coefficient (n,r).
Count how often p is in n!, r! and (n-r)! and check if n! has more factors p than the other two togeter.
// sry... no python...
long count_p_in_fac(long n, long p)
{
long count = 0;
long i = 1;
long temp;
while(true)
{
temp = floor(n/pow(p,i));
count += temp;
if(temp == 0)
break;
}
return count;
}
p = input()
cnt = 0
for i in range(0,n+1):
if(count_p_in_fac(n,p) > count_p_in_fac(i,p) + count_p_in_fac(n-i,p)):
cnt += 1
print cnt
This avoids big numbers and reduces the operations.
This checks (n,r) = 0 mod p in O(log(n)) without computing factorials. But counting a row takes O(n log n).
You can also speed this up by using the symmetry of (n,r). Computing only the first half and multiply it by two. If n is even, you have to count the first half exept the middle r = n/2 and check add the middle after multiply by two.
And you can precompute count_p_in_fac(i,p) for all i.
There's no way you're going to do 10^12 in less than a second. There has to be some property of Pascall's Triangle that makes this easier.. If it's possible
Another interesting property of Pascal's triangle is that in a row p
where p is a prime number, all the terms in that row except the 1s are
multiples of p. This can be proven easily, since if p\in \mathbb{P},
then p has no factors save for 1 and itself. Every entry in the
triangle is an integer, so therefore by definition (p-k)! and k! are
factors of p!\,. However, there is no possible way p itself can show
up in the denominator, so therefore p (or some multiple of it) must be
left in the numerator, making the entire entry a multiple of p.
It might have something to do with that result (from the wiki page http://en.wikipedia.org/wiki/Pascal%27s_triangle).. if this has an answer (i.e. if it's university homework some professor gave you).
See here https://mathoverflow.net/questions/9181/pascal-triangle-and-prime-numbers
(I love this question - I'm not sure it's a programming question though).
You can rewrite your combination function without needing to calculate factorial. (n, r) can be written recursively as
(n, r) = (n-1, r) + (n-1, r-1)
Now we should find the base cases. These are:
(n, 1) = n
(n, 0) = 1
(n, n) = 1
Here, we are assuming that n and r are non-negative integers and n >= r holds true. Then the function combination can be rewritten as
def combination(n, r):
if r == 1:
return n
if r == 0 or r == n:
return 1
return combination(n-1, r) + combination(n-1, r-1)
p = input()
count = 0
for i in range(n + 1):
if combination(n, i) % p == 0:
count += 1
print count
Thank you all for responding to the question of a noob like me
Here is a working python code
n,p = map(int,raw_input().split(' '))
if n==p:
print n-1
elif p>n:
print 0
else:
result = 1
m = n
while n:
temp = n%p
result *= (temp+1)
n /= p
print m+1-result
n = input("enter the row for pascal triangle:")
p = input("enter any prime number u want:")
cnt = 0
line = [1]
for k in range(0, n):
line.append(line[k] * (n-k) / (k+1))
print line
lengths = map(lambda word: line[word]%p ==0, range(len(line))).count(True)
print lengths

Optimise the solution to Project Euler 12 (Python)

I have the following code for Project Euler Problem 12. However, it takes a very long time to execute. Does anyone have any suggestions for speeding it up?
n = input("Enter number: ")
def genfact(n):
t = []
for i in xrange(1, n+1):
if n%i == 0:
t.append(i)
return t
print "Numbers of divisors: ", len(genfact(n))
print
m = input("Enter the number of triangle numbers to check: ")
print
for i in xrange (2, m+2):
a = sum(xrange(i))
b = len(genfact(a))
if b > 500:
print a
For n, I enter an arbitrary number such as 6 just to check whether it indeed returns the length of the list of the number of factors.
For m, I enter entered 80 000 000
It works relatively quickly for small numbers. If I enter b > 50 ; it returns 28 for a, which is correct.
My answer here isn't pretty or elegant, it is still brute force. But, it simplifies the problem space a little and terminates successfully in less than 10 seconds.
Getting factors of n:
Like #usethedeathstar mentioned, it is possible to test for factors only up to n/2. However, we can do better by testing only up to the square root of n:
let n = 36
=> factors(n) : (1x36, 2x18, 3x12, 4x9, 6x6, 9x4, 12x3, 18x2, 36x1)
As you can see, it loops around after 6 (the square root of 36). We also don't need to explicitly return the factors, just find out how many there are... so just count them off with a generator inside of sum():
import math
def get_factors(n):
return sum(2 for i in range(1, round(math.sqrt(n)+1)) if not n % i)
Testing the triangular numbers
I have used a generator function to yield the triangular numbers:
def generate_triangles(limit):
l = 1
while l <= limit:
yield sum(range(l + 1))
l += 1
And finally, start testing:
def test_triangles():
triangles = generate_triangles(100000)
for i in triangles:
if get_factors(i) > 499:
return i
Running this with the profiler, it completes in less than 10 seconds:
$ python3 -m cProfile euler12.py
361986 function calls in 8.006 seconds
The BIGGEST time saving here is get_factors(n) testing only up to the square root of n - this makes it heeeaps quicker and you save heaps of memory overhead by not generating a list of factors.
As I said, it still isn't pretty - I am sure there are more elegant solutions. But, it fits the bill of being faster :)
I got my answer to run in 1.8 seconds with Python.
import time
from math import sqrt
def count_divisors(n):
d = {}
count = 1
while n % 2 == 0:
n = n / 2
try:
d[2] += 1
except KeyError:
d[2] = 1
for i in range(3, int(sqrt(n+1)), 2):
while n % i == 0 and i != n:
n = n / i
try:
d[i] += 1
except KeyError:
d[i] = 1
d[n] = 1
for _,v in d.items():
count = count * (v + 1)
return count
def tri_number(num):
next = 1 + int(sqrt(1+(8 * num)))
return num + (next/2)
def main():
i = 1
while count_divisors(i) < 500:
i = tri_number(i)
return i
start = time.time()
answer = main()
elapsed = (time.time() - start)
print("result %s returned in %s seconds." % (answer, elapsed))
Here is the output showing the timedelta and correct answer:
$ python ./project012.py
result 76576500 returned in 1.82238006592 seconds.
Factoring
For counting the divisors, I start by initializing an empty dictionary and a counter. For each factor found, I create key of d[factor] with value of 1 if it does not exist, otherwise, I increment the value d[factor].
For example, if we counted the factors 100, we would see d = {25: 1, 2: 2}
The first while loop, I factor out all 2's, dividing n by 2 each time. Next, I begin factoring at 3, skipping two each time (since we factored all even numbers already), and stopping once I get to the square root of n+1.
We stop at the square_root of n because if there's a pair of factors with one of the numbers bigger than square_root of n, the other of the pair has to be less than 10. If the smaller one doesn't exist, there is no matching larger factor.
https://math.stackexchange.com/questions/1343171/why-only-square-root-approach-to-check-number-is-prime
while n % 2 == 0:
n = n / 2
try:
d[2] += 1
except KeyError:
d[2] = 1
for i in range(3, int(sqrt(n+1)), 2):
while n % i == 0 and i != n:
n = n / i
try:
d[i] += 1
except KeyError:
d[i] = 1
d[n] = 1
Now that I have gotten each factor, and added it to the dictionary, we have to add the last factor (which is just n).
Counting Divisors
Now that the dictionary is complete, we loop through each of the items, and apply the following formula: d(n)=(a+1)(b+1)(c+1)...
https://www.wikihow.com/Determine-the-Number-of-Divisors-of-an-Integer
All this formula means is taking all of the counts of each factor, adding 1, then multiplying them together. Take 100 for example, which has factors 25, 2, and 2. We would calculate d(n)=(a+1)(b+1) = (1+1)(2+1) = (2)(3) = 6 total divisors
for _,v in d.items():
count = count * (v + 1)
return count
Calculate Triangle Numbers
Now, taking a look at tri_number(), you can see that I opted to calculate the next triangle number in a sequence without manually adding each whole number together (saving me millions of operations). Instead I used T(n) = n (n+1) / 2
http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/runsums/triNbProof.html
We are providing a whole number to the function as an argument, so we need to solve for n, which is going to be the whole number to add next. Once we have the next number (n), we simply add that single number to num and return
S=n(n+1)2
S=n2+n2
2S=n2+n
n2+n−2S=0
At this point, we use the quadratic formula for : ax2+bx+c=0.
n=−b±√b2−4ac / 2a
n=−1±√1−4(1)(−2S) / 2
n=−1±√1+8S / 2
https://socratic.org/questions/how-do-you-solve-for-n-in-s-n-n-1-2
So all tri_number() does is evaluate n=1+√1+8S / 2 (we ignore the negative equation here). The answer that is returned is the next triangle number in the sequence.
def tri_number(num):
next = 1 + int(sqrt(1+(8 * num)))
return num + (next/2)
Main Loop
Finally, we can look at main(). We start at whole number 1. We count the divisor of 1. If it is less than 500, we get the next triangle number, then try again and again until we get a number with > 500 divisors.
def main():
i = 1
while count_divisors(i) < 500:
i = tri_number(i)
return i
I am sure there are additional ways to optimize but I am not smart enough to understand those ways. If you find any better ways to optimize python, let me know! I originally solved project 12 in Golang, and that run in 25 milliseconds!
$ go run project012.go
76576500
2018/07/12 01:56:31 TIME: main() took 23.581558ms
one of the hints i can give is
def genfact(n):
t = []
for i in xrange(1, n+1):
if n%i == 0:
t.append(i)
return t
change that to
def genfact(n):
t=[]
for i in xrange(1,numpy.sqrt(n)+1):
if(n%i==0):
t.append(i)
t.apend(n/i)
since if a is a divisor than so is b=n/a, since a*b=a*n/b=n, That should help a part already (not sure if in your case a square is possible, but if so, add another case to exclude adding the same number twice)
You could devise a recursive thing too, (like if it is something like for 28, you get 1,28,2,14 and at the moment you are at knowing 14, you put in something to actually remember the divisors of 14 (memoize), than check if they are alraedy in the list, and if not, add them to the list, together with 28/d for each of the divisors of 14, and at the end just take out the duplicates
If you think my first answer is still not fast enough, ask for more, and i will check how it would be done to solve it faster with some more tricks (could probably make use of erastothenes sieve or so too, and some other tricks could be thought up as well if you would wish to really blow up the problem to huge proportions, like to check the first one with over 10k divisors or so)
while True:
c=0
n=1
m=1
for i in range(1,n+1):
if n%i==0:
c=c+1
m=m+1
n=m*(m+1)/2
if c>500:
break
print n
this is not my code but it is so optimized.
source: http://code.jasonbhill.com/sage/project-euler-problem-12/
import time
def num_divisors(n):
if n % 2 == 0: n = n / 2
divisors = 1
count = 0
while n % 2 == 0:
count += 1
n = n / 2
divisors = divisors * (count + 1)
p = 3
while n != 1:
count = 0
while n % p == 0:
count += 1
n = n / p
divisors = divisors * (count + 1)
p += 2
return divisors
def find_triangular_index(factor_limit):
n = 1
lnum, rnum = num_divisors(n), num_divisors(n + 1)
while lnum * rnum < 500:
n += 1
lnum, rnum = rnum, num_divisors(n + 1)
return n
start = time.time()
index = find_triangular_index(500)
triangle = (index * (index + 1)) / 2
elapsed = (time.time() - start)
print("result %s returned in %s seconds." % (triangle, elapsed))

Optimizing python code

Any tips on optimizing this python code for finding next palindrome:
Input number can be of 1000000 digits
COMMENTS ADDED
#! /usr/bin/python
def inc(lst,lng):#this function first extract the left half of the string then
#convert it to int then increment it then reconvert it to string
#then reverse it and finally append it to the left half.
#lst is input number and lng is its length
if(lng%2==0):
olst=lst[:lng/2]
l=int(lng/2)
olst=int(olst)
olst+=1
olst=str(olst)
p=len(olst)
if l<p:
olst2=olst[p-2::-1]
else:
olst2=olst[::-1]
lst=olst+olst2
return lst
else:
olst=lst[:lng/2+1]
l=int(lng/2+1)
olst=int(olst)
olst+=1
olst=str(olst)
p=len(olst)
if l<p:
olst2=olst[p-3::-1]
else:
olst2=olst[p-2::-1]
lst=olst+olst2
return lst
t=raw_input()
t=int(t)
while True:
if t>0:
t-=1
else:
break
num=raw_input()#this is input number
lng=len(num)
lst=num[:]
if(lng%2==0):#this if find next palindrome to num variable
#without incrementing the middle digit and store it in lst.
olst=lst[:lng/2]
olst2=olst[::-1]
lst=olst+olst2
else:
olst=lst[:lng/2+1]
olst2=olst[len(olst)-2::-1]
lst=olst+olst2
if int(num)>=int(lst):#chk if lst satisfies criteria for next palindrome
num=inc(num,lng)#otherwise call inc function
print num
else:
print lst
I think most of the time in this code is spent converting strings to integers and back. The rest is slicing strings and bouncing around in the Python interpreter. What can be done about these three things? There are a few unnecessary conversions in the code, which we can remove. I see no way to avoid the string slicing. To minimize your time in the interpreter you just have to write as little code as possible :-) and it also helps to put all your code inside functions.
The code at the bottom of your program, which takes a quick guess to try and avoid calling inc(), has a bug or two. Here's how I might write that part:
def nextPal(num):
lng = len(num)
guess = num[:lng//2] + num[(lng-1)//2::-1] # works whether lng is even or odd
if guess > num: # don't bother converting to int
return guess
else:
return inc(numstr, n)
This simple change makes your code about 100x faster for numbers where inc doesn't need to be called, and about 3x faster for numbers where it does need to be called.
To do better than that, I think you need to avoid converting to int entirely. That means incrementing the left half of the number without using ordinary Python integer addition. You can use an array and carry out the addition algorithm "by hand":
import array
def nextPal(numstr):
# If we don't need to increment, just reflect the left half and return.
n = len(numstr)
h = n//2
guess = numstr[:n-h] + numstr[h-1::-1]
if guess > numstr:
return guess
# Increment the left half of the number without converting to int.
a = array.array('b', numstr)
zero = ord('0')
ten = ord('9') + 1
for i in range(n - h - 1, -1, -1):
d = a[i] + 1
if d == ten:
a[i] = zero
else:
a[i] = d
break
else:
# The left half was all nines. Carry the 1.
# Update n and h since the length changed.
a.insert(0, ord('1'))
n += 1
h = n//2
# Reflect the left half onto the right half.
a[n-h:] = a[h-1::-1]
return a.tostring()
This is another 9x faster or so for numbers that require incrementing.
You can make this a touch faster by using a while loop instead of for i in range(n - h - 1, -1, -1), and about twice as fast again by having the loop update both halves of the array rather than just updating the left-hand half and then reflecting it at the end.
You don't have to find the palindrome, you can just generate it.
Split the input number, and reflect it. If the generated number is too small, then increment the left hand side and reflect it again:
def nextPal(n):
ns = str(n)
oddoffset = 0
if len(ns) % 2 != 0:
oddoffset = 1
leftlen = len(ns) / 2 + oddoffset
lefts = ns[0:leftlen]
right = lefts[::-1][oddoffset:]
p = int(lefts + right)
if p < n:
## Need to increment middle digit
left = int(lefts)
left += 1
lefts = str(left)
right = lefts[::-1][oddoffset:]
p = int(lefts + right)
return p
def test(n):
print n
p = nextPal(n)
assert p >= n
print p
test(1234567890)
test(123456789)
test(999999)
test(999998)
test(888889)
test(8999999)
EDIT
NVM, just look at this page: http://thetaoishere.blogspot.com/2009/04/finding-next-palindrome-given-number.html
Using strings. n >= 0
from math import floor, ceil, log10
def next_pal(n):
# returns next palindrome, param is an int
n10 = str(n)
m = len(n10) / 2.0
s, e = int(floor(m - 0.5)), int(ceil(m + 0.5))
start, middle, end = n10[:s], n10[s:e], n10[e:]
assert (start, middle[0]) == (end[-1::-1], middle[-1]) #check that n is actually a palindrome
r = int(start + middle[0]) + 1 #where the actual increment occurs (i.e. add 1)
r10 = str(r)
i = 3 - len(middle)
if len(r10) > len(start) + 1:
i += 1
return int(r10 + r10[-i::-1])
Using log, more optized. n > 9
def next_pal2(n):
k = log10(n + 1)
l = ceil(k)
s, e = int(floor(l/2.0 - 0.5)), int(ceil(l/2.0 + 0.5))
mmod, emod = 10**(e - s), int(10**(l - e))
start, end = divmod(n, emod)
start, middle = divmod(start, mmod)
r1 = 10*start + middle%10 + 1
i = middle > 9 and 1 or 2
j = s - i + 2
if k == l:
i += 1
r2 = int(str(r1)[-i::-1])
return r1*10**j + r2

Categories