I was solving Sam and substrings problem from hackerrank. It is basically finding sum of all substrings of a string having all integers.
Samantha and Sam are playing a numbers game. Given a number as a string, no leading zeros, determine the sum of all integer values of substrings of the string.
Given an integer as a string, sum all of its substrings cast as integers. As the number may become large, return the value modulo 10⁹ + 7.
Example: n = '42'
Here n is a string that has three integer substrings: 4, 2, and 42. Their sum is 48, and 48 modulo 10⁹ + 7 = 48.
Function Description
Complete the substrings function in the editor below.
substrings has the following parameter(s):
string n: the string representation of an integer
Returns
int: the sum of the integer values of all substrings in n, modulo (10⁹ + 7)
I tried following recursive top down dynamic problem solution with memoization:
from functools import cache
def substrings(n):
#cache
def substrSum(curIndex):
if curIndex == 0: return int(n[0])
return substrSum(curIndex-1)*10 + int(n[curIndex]) * (curIndex+1)
totalSum = 0
for i in range(len(n)-1, -1,-1):
totalSum += substrSum(i)
return totalSum % (10 ** 9 + 7)
I also tried recursive bottom up dynamic programming solution with memoization (this simply involves changing for loop counting direction):
from functools import cache
def substrings(n):
#cache
def substrSum(curIndex):
if curIndex == 0: return int(n[0])
return substrSum(curIndex-1)*10 + int(n[curIndex]) * (curIndex+1)
totalSum = 0
for i in range(len(n)):
totalSum += substrSum(i)
return totalSum % (10 ** 9 + 7)
For top-down solution gives runtime error in 8 out of 13 test cases, whearas in bottom up solution gives gives runtime error in 6 out of 13 test cases. Where am I making mistake?
Your algorithm is correct (both versions), but HackerRank will test with strings that have many thousands of digits, and as you perform a recursive call for each digit, your first code runs into a maximum recursion depth exceeded error, and the second one runs into a memory error (think of the cache).
It should be noted that they phrased the constraint wrong. It is not the value of n "cast to integer" that is limited by 2 x 105, but the number of digits in n. I checked this, and one of their tests concerns a string of about 199000 digits.
Related
Working on project Euler problem (26), and wanting to use an algorithm looking for the prime, p with the largest order of 10 modulo p. Essentially the problem is to look for the denominator which creates the longest repetend in a decimal. After a bunch of wikipedia reading, it looks like the prime described above would fulfill that. But, unfortunately, it looks like taking the very large powers of 10 results in an error. My question then is : is there a way of getting around this error (making the numbers smaller), or should I abandon this strategy and just do long division (with the plan being to focus on the primes).
[of note, in the order_ten method I can get it to run if I limit the powers of 10 to 300 and probably can go a bit long, which goes along with the length of a long]
import math
def prime_seive(limit):
seive_list = [True]*limit
seive_list[0] = seive_list[1] = False
for i in range(2, limit):
if seive_list[i] == True :
n = 2
while i*n < limit :
seive_list[i*n] = False #get rid of multiples
n = n+1
prime_numbers = [i for i,j in enumerate(seive_list) if j == True]
return prime_numbers
def order_ten(n) :
for k in range(1, n) :
if (math.pow(10,k) -1)%n == 0:
return k
primes = prime_seive(1000)
max_order = 0
max_order_d = -1
for x in reversed(primes) :
order = order_ten(x)
if order > max_order :
max_order = order
max_order_d = x
print max_order
print max_order_d
I suspect that the problem is that your numbers get to large when first taking a large power of ten and then computing the value mod n. (For instance If I asked you to compute 10^11 mod 11, you could remark than 10 mod 11 is (-1) and thus 10^11 mod 11 is just (-1)^11 mod 11 ie. -1.)
Maybe you could try programming your own exponentiation routine mod n, something like (in pseudo code)
myPow (int k, int n) {
if (k==0) return 1;
else return ((myPow(k-1,n)*10)%n);
}
This way you never deal with numbers larger than n.
The way it is written you will get a linear complexity in k for computing the power, and thus a quadratic complexity in n for your function order_ten(n). If this is too slow for you could improve the function myPow to use some smart exponentiation.
Given a number K which is a product of two different numbers (A,B), find the maximum number(<=A & <=B) who's square divides the K .
Eg : K = 54 (6*9) . Both the numbers are available i.e 6 and 9.
My approach is fairly very simple or trivial.
taking the smallest of the two ( 6 in this case).Lets say A
Square the number and divide K, if its a perfect division, that's the number.
Else A = A-1 ,till A =1.
For the given example, 3*3 = 9 divides K, and hence 3 is the answer.
Looking for a better algorithm, than the trivial solution.
Note : The test cases are in 1000's so the best possible approach is needed.
I am sure someone else will come up with a nice answer involving modulus arithmetic. Here is a naive approach...
Each of the factors can themselves be factored (though it might be an expensive operation).
Given the factors, you can then look for groups of repeated factors.
For instance, using your example:
Prime factors of 9: 3, 3
Prime factors of 6: 2, 3
All prime factors: 2, 3, 3, 3
There are two 3s, so you have your answer (the square of 3 divides 54).
Second example of 36 x 9 = 324
Prime factors of 36: 2, 2, 3, 3
Prime factors of 9: 3, 3
All prime factors: 2, 2, 3, 3, 3, 3
So you have two 2s and four 3s, which means 2x3x3 is repeated. 2x3x3 = 18, so the square of 18 divides 324.
Edit: python prototype
import math
def factors(num, dict):
""" This finds the factors of a number recursively.
It is not the most efficient algorithm, and I
have not tested it a lot. You should probably
use another one. dict is a dictionary which looks
like {factor: occurrences, factor: occurrences, ...}
It must contain at least {2: 0} but need not have
any other pre-populated elements. Factors will be added
to this dictionary as they are found.
"""
while (num % 2 == 0):
num /= 2
dict[2] += 1
i = 3
found = False
while (not found and (i <= int(math.sqrt(num)))):
if (num % i == 0):
found = True
factors(i, dict)
factors(num / i, dict)
else:
i += 2
if (not found):
if (num in dict.keys()):
dict[num] += 1
else:
dict[num] = 1
return 0
#MAIN ROUTINE IS HERE
n1 = 37 # first number (6 in your example)
n2 = 41 # second number (9 in your example)
dict = {2: 0} # initialise factors (start with "no factors of 2")
factors(n1, dict) # find the factors of f1 and add them to the list
factors(n2, dict) # find the factors of f2 and add them to the list
sqfac = 1
# now find all factors repeated twice and multiply them together
for k in dict.keys():
dict[k] /= 2
sqfac *= k ** dict[k]
# here is the result
print(sqfac)
Answer in C++
int func(int i, j)
{
int k = 54
float result = pow(i, 2)/k
if (static_cast<int>(result)) == result)
{
if(i < j)
{
func(j, i);
}
else
{
cout << "Number is correct: " << i << endl;
}
}
else
{
cout << "Number is wrong" << endl;
func(j, i)
}
}
Explanation:
First recursion then test if result is a positive integer if it is then check if the other multiple is less or greater if greater recursive function tries the other multiple and if not then it is correct. Then if result is not positive integer then print Number is wrong and do another recursive function to test j.
If I got the problem correctly, I see that you have a rectangle of length=A, width=B, and area=K
And you want convert it to a square and lose the minimum possible area
If this is the case. So the problem with your algorithm is not the cost of iterating through mutliple iterations till get the output.
Rather the problem is that your algorithm depends heavily on the length A and width B of the input rectangle.
While it should depend only on the area K
For example:
Assume A =1, B=25
Then K=25 (the rect area)
Your algorithm will take the minimum value, which is A and accept it as answer with a single
iteration which is so fast but leads to wrong asnwer as it will result in a square of area 1 and waste the remaining 24 (whatever cm
or m)
While the correct answer here should be 5. which will never be reached by your algorithm
So, in my solution I assume a single input K
My ideas is as follows
x = sqrt(K)
if(x is int) .. x is the answer
else loop from x-1 till 1, x--
if K/x^2 is int, x is the answer
This might take extra iterations but will guarantee accurate answer
Also, there might be some concerns on the cost of sqrt(K)
but it will be called just once to avoid misleading length and width input
https://projecteuler.net/problem=35
All problems on Project Euler are supposed to be solvable by a program in under 1 minute. My solution, however, has a runtime of almost 3 minutes. Other solutions I've seen online are similar to mine conceptually, but have runtimes that are exponentially faster. Can anyone help make my code more efficient/run faster?
Thanks!
#genPrimes takes an argument n and returns a list of all prime numbers less than n
def genPrimes(n):
primeList = [2]
number = 3
while(number < n):
isPrime = True
for element in primeList:
if element > number**0.5:
break
if number%element == 0 and element <= number**0.5:
isPrime = False
break
if isPrime == True:
primeList.append(number)
number += 2
return primeList
#isCircular takes a number as input and returns True if all rotations of that number are prime
def isCircular(prime):
original = prime
isCircular = True
prime = int(str(prime)[-1] + str(prime)[:len(str(prime)) - 1])
while(prime != original):
if prime not in primeList:
isCircular = False
break
prime = int(str(prime)[-1] + str(prime)[:len(str(prime)) - 1])
return isCircular
primeList = genPrimes(1000000)
circCount = 0
for prime in primeList:
if isCircular(prime):
circCount += 1
print circCount
Two modifications of your code yield a pretty fast solution (roughly 2 seconds on my machine):
Generating primes is a common problem with many solutions on the web. I replaced yours with rwh_primes1 from this article:
def genPrimes(n):
sieve = [True] * (n/2)
for i in xrange(3,int(n**0.5)+1,2):
if sieve[i/2]:
sieve[i*i/2::i] = [False] * ((n-i*i-1)/(2*i)+1)
return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]
It is about 65 times faster (0.04 seconds).
The most important step I'd suggest, however, is to filter the list of generated primes. Since each circularly shifted version of an integer has to be prime, the circular prime must not contain certain digits. The prime 23, e.g., can be easily spotted as an invalid candidate, because it contains a 2, which indicates divisibility by two when this is the last digit. Thus you might remove all such bad candidates by the following simple method:
def filterPrimes(primeList):
for i in primeList[3:]:
if '0' in str(i) or '2' in str(i) or '4' in str(i) \
or '5' in str(i) or '6' in str(i) or '8' in str(i):
primeList.remove(i)
return primeList
Note that the loop starts at the fourth prime number to avoid removing the number 2 or 5.
The filtering step takes most of the computing time (about 1.9 seconds), but reduces the number of circular prime candidates dramatically from 78498 to 1113 (= 98.5 % reduction)!
The last step, the circulation of each remaining candidate, can be done as you suggested. If you wish, you can simplify the code as follows:
circCount = sum(map(isCircular, primeList))
Due to the reduced candidate set this step is completed in only 0.03 seconds.
What is the best approach to find the total number of numbers between two given numbers whose binary representation is palindrome?
The problem I am trying to solve is here on spoj
http://www.spoj.com/problems/BINPALI/
I solved the spoj problem and code as below:
#include<iostream>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<string>
using namespace std;
int main()
{
int a,b,t;
cin>>t;
while(t--)
{
cin>>a>>b;
int total=0;
string s="";
while(a<=b)
{
s="";
for(int i=a;i>0;i=i/2)
{
if(i%2)
s+='1';
else
s+='0';
}
string s2="",s3="";
s2=s.substr(0,s.length()/2);
int k=s.length();
if(k%2)
s3=s.substr(s.length()/2+1,s.length());
else
s3=s.substr(s.length()/2,s.length());
reverse(s2.begin(),s2.end());
if(s2==s3)
{
cout<<a<<" ";
total++;
}
a++;
}
if(!total)
cout<<"none"<<endl;
}
return 0;
}
One possible approach is:
Take the binary representation of the 1st number M.
Find the 1st number greater than M that is palindrome in binary representation:
- For M, keep the left half of bits, the same value, and match the right half of the binary string with the left half.
For example if M is 10110111, the number shall be 10111101
If the resultant number is < M, then increment the left substring by 1 and then match the right substring.
Eg. if M is 10000011, the number shall be 10000001 < M , hence number shall be 10011001.
To find subsequent numbers, increment bits from the middle towards the end.
10011001
10100101
10111101
11000011
The time limit is very strict on this problem. Even an optimized palindrome generator will probably not work. You likely have to use the formula at OEIS for this given integer sequence.
There is an inversion formula as well. It's given as follows.
Inversion formula: If b>0 is any binary palindrome, then the index n for which a(n)=b is
n=palindromicIndexOf(b)=(((5-(-1)^m)/2) + sum_{k=1...floor(m/2)} (floor(b/2^k) mod 2)/2^k))*2^floor(m/2), where m=floor(log_2(b)).
You probably have to take the two given indexes and find the lowest n and highest n from the sequence somehow. Then print out all nth numbers from the sequence within the range (lowest n, highest n). Each query for the nth binary palindromic number is O(1) time so each test case should take O(log(B - A)) time. This is very very low but you need to get the formula working. :)
Good luck implementing the generator formula for this sequence. I tried it and could not get it to work. :( It's quite complicated.
But anyways for reference, I tried using an optimized palindrome generator in Python 2.7.5 and it gave me Time Limit Exceeded. Here is the code if you're interested.
from itertools import product, repeat
from bisect import insort, bisect
def all_binary_sequences_of_length_(n):
return [''.join(seq) for seq in product('01', repeat=n)]
def main():
binary_palindromes = [0, 1, 3, 5, 7]
for n in xrange(1, 15):
A = all_binary_sequences_of_length_(n)
for a in A:
b = a[::-1]
# Add palindromes of length 2n + 2
insort(binary_palindromes, int((a+b).join('11'), 2))
# Add palindromes of length 2n + 3
insort(binary_palindromes, int((a+'0'+b).join('11'), 2))
insort(binary_palindromes, int((a+'1'+b).join('11'), 2))
t = int(raw_input())
for _ in repeat(0, t):
a, b = map(int, raw_input().split())
start = bisect(binary_palindromes, a - 1)
end = bisect(binary_palindromes, b)
output = [str(binary_palindromes[i]) for i in xrange(start, end)]
if len(output) == 0:
print 'none'
else:
print ' '.join(output)
if __name__ == '__main__':
main()
I realize Python is not a very fast language but the time limit of only 1 second leads me to believe that the only way to solve this is by using the formula in OEIS. :)
Python is powerful! Don't make it complicated! Well, it is a bit slow!
for _ in range(input()):
has = False
x,y = map(int, raw_input().split())
for i in range(x,y+1):
temp = bin(i)
temp = temp[temp.index('b')+1:]
if temp[::-1] == temp:
has = True
print i,
if not has:
print "none"
Let me start with an example -
I have a range of numbers from 1 to 9. And let's say the target number that I want is 29.
In this case the minimum number of operations that are required would be (9*3)+2 = 2 operations. Similarly for 18 the minimum number of operations is 1 (9*2=18).
I can use any of the 4 arithmetic operators - +, -, / and *.
How can I programmatically find out the minimum number of operations required?
Thanks in advance for any help provided.
clarification: integers only, no decimals allowed mid-calculation. i.e. the following is not valid (from comments below): ((9/2) + 1) * 4 == 22
I must admit I didn't think about this thoroughly, but for my purpose it doesn't matter if decimal numbers appear mid-calculation. ((9/2) + 1) * 4 == 22 is valid. Sorry for the confusion.
For the special case where set Y = [1..9] and n > 0:
n <= 9 : 0 operations
n <=18 : 1 operation (+)
otherwise : Remove any divisor found in Y. If this is not enough, do a recursion on the remainder for all offsets -9 .. +9. Offset 0 can be skipped as it has already been tried.
Notice how division is not needed in this case. For other Y this does not hold.
This algorithm is exponential in log(n). The exact analysis is a job for somebody with more knowledge about algebra than I.
For more speed, add pruning to eliminate some of the search for larger numbers.
Sample code:
def findop(n, maxlen=9999):
# Return a short postfix list of numbers and operations
# Simple solution to small numbers
if n<=9: return [n]
if n<=18: return [9,n-9,'+']
# Find direct multiply
x = divlist(n)
if len(x) > 1:
mults = len(x)-1
x[-1:] = findop(x[-1], maxlen-2*mults)
x.extend(['*'] * mults)
return x
shortest = 0
for o in range(1,10) + range(-1,-10,-1):
x = divlist(n-o)
if len(x) == 1: continue
mults = len(x)-1
# We spent len(divlist) + mults + 2 fields for offset.
# The last number is expanded by the recursion, so it doesn't count.
recursion_maxlen = maxlen - len(x) - mults - 2 + 1
if recursion_maxlen < 1: continue
x[-1:] = findop(x[-1], recursion_maxlen)
x.extend(['*'] * mults)
if o > 0:
x.extend([o, '+'])
else:
x.extend([-o, '-'])
if shortest == 0 or len(x) < shortest:
shortest = len(x)
maxlen = shortest - 1
solution = x[:]
if shortest == 0:
# Fake solution, it will be discarded
return '#' * (maxlen+1)
return solution
def divlist(n):
l = []
for d in range(9,1,-1):
while n%d == 0:
l.append(d)
n = n/d
if n>1: l.append(n)
return l
The basic idea is to test all possibilities with k operations, for k starting from 0. Imagine you create a tree of height k that branches for every possible new operation with operand (4*9 branches per level). You need to traverse and evaluate the leaves of the tree for each k before moving to the next k.
I didn't test this pseudo-code:
for every k from 0 to infinity
for every n from 1 to 9
if compute(n,0,k):
return k
boolean compute(n,j,k):
if (j == k):
return (n == target)
else:
for each operator in {+,-,*,/}:
for every i from 1 to 9:
if compute((n operator i),j+1,k):
return true
return false
It doesn't take into account arithmetic operators precedence and braces, that would require some rework.
Really cool question :)
Notice that you can start from the end! From your example (9*3)+2 = 29 is equivalent to saying (29-2)/3=9. That way we can avoid the double loop in cyborg's answer. This suggests the following algorithm for set Y and result r:
nextleaves = {r}
nops = 0
while(true):
nops = nops+1
leaves = nextleaves
nextleaves = {}
for leaf in leaves:
for y in Y:
if (leaf+y) or (leaf-y) or (leaf*y) or (leaf/y) is in X:
return(nops)
else:
add (leaf+y) and (leaf-y) and (leaf*y) and (leaf/y) to nextleaves
This is the basic idea, performance can be certainly be improved, for instance by avoiding "backtracks", such as r+a-a or r*a*b/a.
I guess my idea is similar to the one of Peer Sommerlund:
For big numbers, you advance fast, by multiplication with big ciphers.
Is Y=29 prime? If not, divide it by the maximum divider of (2 to 9).
Else you could subtract a number, to reach a dividable number. 27 is fine, since it is dividable by 9, so
(29-2)/9=3 =>
3*9+2 = 29
So maybe - I didn't think about this to the end: Search the next divisible by 9 number below Y. If you don't reach a number which is a digit, repeat.
The formula is the steps reversed.
(I'll try it for some numbers. :) )
I tried with 2551, which is
echo $((((3*9+4)*9+4)*9+4))
But I didn't test every intermediate result whether it is prime.
But
echo $((8*8*8*5-9))
is 2 operations less. Maybe I can investigate this later.