Find the perfect square in the string - c++

A perfect square is taken in binary and some bits are replaced with "?" for example 1??, the number would be 4.(or 1????000???0000)
I need to find that perfect square.(there will be only such possible number)
number of '?'s in the string be n
To find that number what I am doing is iterating through 2**n numbers(111,110,101,100) and checking if it is a perfect square. I am using following function to check if it is a perfect square.
bool issqr(int n){
int d=(int)(sqrt(n));
if(d*d==n) return true;
else return false;
}
Even though in python I did it, it is taking a lot of time, so I shifted to C++ using only bit operations for populating 2**n numbers(which was much faster than the python version)
but this fails if the number has more than 64 bits
How to avoid this problem? How can I do the same thing if a number has say 120 bits.
(10100110???1?1?01?1?011000?1100?00101000?1?11001101100110001010111?0?1??0110?110?01?1100?1?0110?1?10111?01?0111000?10??101?01)

Rather than re-writing in C++ you should first have looked at improving your algorithm. The lowest possible answer is the square root from the original value with all '?' replace by 0 rounded up, the highest possible answer is the square root of the pattern with the '?'s replaced by 1 rounded down. Find those two values, iterate through them, square and check against the pattern.
This is faster both because you are iterating through many fewer numbers and because you aren't calculating any square roots in the loop: squaring is much easier.
You don't need to compare string to check for a match:
mask = int(pattern.replace('0', '1').replace('?', '0'), 2)
test = int(pattern.replace('?', '0'), 2)
def is_match(n):
return (n&mask)==test
So putting it all together:
def int_sqrt(x):
if x < 0:
raise ValueError('square root not defined for negative numbers')
n = int(x)
if n == 0:
return 0
a, b = divmod(n.bit_length(), 2)
x = 2**(a+b)
while True:
y = (x + n//x)//2
if y >= x:
return x
x = y
def find_match(pattern):
lowest = int(pattern.replace('?', '0'), 2)
highest = int(pattern.replace('?', '1'), 2)
mask = int(pattern.replace('0', '1').replace('?', '0'), 2)
lowsqrt = int_sqrt(lowest)
if lowsqrt*lowsqrt != lowest:
lowsqrt += 1
highsqrt = int_sqrt(highest)
for n in range(lowsqrt, highsqrt+1):
if (n*n & mask)==lowest:
return n*n
print(find_match('1??1??1'))
print(find_match('1??0??1'))
print(find_match('1??????????????????????????????????????????????????????????????????????1??0??1'))
Output:
121
81
151115727461209345152081
N.B. This only works in Python 3.x, the last test will overflow range in Python 2.x

From my understanding, given an integer n you are trying to find a square number sq that matches :
2n - 1 < sq < 2n+1 - 1
This condition is the mathematic translation of "my number must have the form 1????" where there are n "?".
First, you can notice that if n is even, the number 2n is a perfect square and matches your condition (in binary, it is the number 1000...000 - n zeroes -).
If n is uneven (say n = 2.p + 1), then 2n+1 is a perfect square ((2p+1)2). Computing the following number will give you a perfect square :
(2p+1 - 1)2
To satisfy the first inequality, p must satisfy :
2n - 1 < (2p+1 - 1)2
Then
0 < 2n+1 - 2p+2 + 1 - 2n + 1,
Finally,
2n + 2 - 2p+2 > 0
Or
22p - 2p+1 + 1 > 0
If we consider the function that matches p with f(p) such that :
f(p) = 22p - 2p+1 + 1
This function is defined for each positive real number, and is strictly increasing. Moreover, f(0) = 0. Finally, the initial condition is satisfied when p > 0 !
For p = 0 - or n = 1 -, the problem does not have a valid solution.

You don't need to iterate trough all the 2**n numbers to find the perfect square, in fact you only need one fractional square operation:
Say you have integer n and you want to find the largest perfect square smaller or equal than n, let's call it m.
Then:
d = (int)sqrt(n);
m = d*d;
Explanation:
Assume there is a perfect square m' larger than m , this implies there is an integer d' so that: d' > d and d'*d' = m'.
But d' >=d+1 and (d+1)*(d+1) > n so m' > n in contradiction to our requirement m' <= n.
Now to your question:
in order to find the perfect squares just change to "1" all of the "?" and find the perfect square if it conforms to your string you got the number you're looking for, if not change just enough "?" from the msb to "0" so that the resulting number is smaller or equal to the perfect square you just found, and keep going until you find the perfect square or run out of options.

Your operations may be returning something too large for an integer...
http://www.cplusplus.com/doc/tutorial/variables/

Related

Traversing a binary tree to get from one number to another using only two operations

I'm doing a problem that says that we have to get from one number, n, to another, m, in as few steps as possible, where each "step" can be 1) doubling, or 2) subtracting one. The natural approach is two construct a binary tree and run BFS since we are given that n, m are bounded by 0 ≤ n, m ≤ 104 and so the tree doesn't get that big. However, I ran into a stunningly short solution, and have no idea why it works. It basically goes from m … n instead, halving or adding one as necessary to decrease m until it is less than n, and then just adding to get up to n. Here is the code:
while(n<m){
if (m%2) m++;
else m /= 2;
count++;
}
count = count + n - m;
return count;
Is it obvious why this is necessarily the shortest path? I get that going from m … n is natural because n is lower bounded by zero and so the tree becomes more "finite" in some sense, but this method of modified halving until you get below the number, then adding up until you reach it, doesn't seem like it should necessarily always return the correct answer, yet it does. Why, and how might I have recognized this approach from the get-go?
You only have 2 available operations:
double n
subtract 1 from n
That means the only way to go up is to double and the only way to go down is to subtract 1.
If m is an even number, then you can land on it by doubling n when 2*n = m. Otherwise, you will have to subtract 1 as well (if 2*n = m + 1 then you will have to double n and then subtract 1).
If doubling n lands too far above m then you will have to subtract twice as many times than if you used the subtraction before doubling n.
example:
n = 12 and m = 20.
You can either double n and then subtract 4 times as in 12*2 -4 = 20. - 5 steps
Or you can subtract twice and then double n as in (12-2)*2 = 20. - 3 steps
You might be wondering 'How should I pick between doubling or subtracting when n < m/2?'.
The idea is to use a reccurence-based approach. You know that you want n to reach a value of v such as v = m/2 or v = (m+1)/2. In other words you want n to reach v... and the shortest way to do that is to reach a value v' such as v' = v/2 or v' = (v+1)/2 and so on.
example:
n = 2 and m = 21.
You want n to reach (21+1)/2 = 11 which means you want to reach (11+1)/2 = 6 and thus to reach 6/2=3 and thus to reach (3+1)/2 = 2.
Since n=2 you now know that the shortest path is: (((n*2-1)*2)*2-1)*2-1.
other example:
n = 14 and m = 22.
You want n to reach 22/2 = 11.
n is already above 11 so the shortest path is : (n-1-1-1)*2.
From here, you can see that the shortest path can be deduced without a binary tree.
On top of that, you have to think starting from m and going down to an obvious path for n. This implies that it will be easier to code an algorithm going from m to n than the opposite.
Using recurrence, this function achieves the same result:
function shortest(n, m) {
if (n >= m) return n-m; //only way to go down
if(m%2==0) return 1 + shortest(n, m/2); //if m is even => optimum goal is m/2
else return 2 + shortest(n, (m+1)/2);//else optimum goal is (m+1)/2 which necessitates 2 operations
}

Dynamic Programming: Counting numbers in between

Given two numbers X and Y, how many numbers exist between them inclusive that have at least half their digits the same? For example, 1122 and 4444 would work, while 11234 and 112233 would not work.
Obviously, the most straightforward way is to start at X and increment by 1 all the way to Y, and then check each number, but that is way too slow, as the boundaries for X and Y are between 100 and 10^18. I know that it is some form of dynamic programming, and that I should use strings to represent the numbers, but I can't get much further.
Any help would be accepted. Thanks!
I will explain you in some steps:
First step:
For solving this kind of range problems between X and Y always make it simple by counting between 0 to X and 0 to Y-1, then subtract the result. i.e. if you have a function like f(N) that calculates the numbers that have at least half their digits the same between 0 and N, then your final result is:
f(X) - f(Y-1)
Second step:
Next we have to compute f(N). We split this function into 2 sub functions, one for calculating the result for numbers having the same number of digits with N (lets call it f_equal), and the other for counting the qualified numbers having digits less the N (let's call it f_less). E.g. if N is 19354, we count the qualified numbers between 0 to 9999, then in another method count the favorite numbers between 10000 to 19354, after that we sum up the result. Next, I'll explain you how to implement these two methods.
Third step:
Here, we want to compute f_less method. you can do it by some math, but I always prefer to write a simple DP for solving these tasks. I will write the recursive function whether you can use memoization or you can make it bottom-up with some loops (I'll leave it as a practice for you).
long long f_less(int curDigit, int favNum, int favNumCountSoFar, int nonFavNum, int nonFavNumCountSoFar, int maxDigit){
if(curDigit == maxDigit ){
//for numbers with even maxDigit there may be a case when we have 2 favorite numbers
//and we should count them only once. like 522552
if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
if(2*favNumCountSoFar >= maxDigit) return 2;
return 0;
}
long long res = 0;
for(int i=(curDigit==0?1:0);i<=9;++i) //skip the leading zero
if(i==favNum)
res += f_less(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar,maxDigit);
else
res += f_less(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1),maxDigit);
return res;
}
And call it for all numbers through 0 to 9:
long long res = 0;
for(int maxDigit = 1; maxDigit < NUMBER_OF_DIGITS(N); ++maxDigit)
for(int favNumber = 0; favNumber < 10; ++favNumber)
res += f_less(0, favNumber, 0, -1, 0, maxDigit);
Fourth Step:
Finally we have to compute f_equal. Here we have to keep the number in a string to always check whether we are still in the range below N or not in the recursive function. Here is the implementation of f_equal (again use memoization or make it bottom-up):
string s = NUM_TO_STRING(N);
int maxDigit = s.size();
long long f_equal(int curDigit, int favNum, int favNumCountSoFar,int nonFavNum, int nonFavNumCountSoFar, bool isEqual){ //isEqual checks that whether our number is equal to N or it's lesser than it
if(curDigit == maxDigit ){
//for numbers with even maxDigit there may be a case when we have 2 favorite numbers
//and we should count them only once. like 522552
if(favNumCountSoFar*2 == maxDigit && favNumCountSoFar == nonFavNumCountSoFar) return 1;
if(2*favNumCountSoFar >= maxDigit) return 2;
return 0;
}
long long res = 0;
for(int i=(curDigit==0?1:0);i<=9;++i){ //skip the leading zero
if(isEqual && i>(s[curDigit]-'0')) break;
if(i==favNum)
res += f_equal(curDigit+1, favNum, favNumCountSoFar + 1, nonFavNum, nonFavNumCountSoFar, isEqual && (i==(s[curDigit]-'0')));
else
res += f_equal(curDigit+1, favNum, favNumCountSoFar, i, (i==nonFavNum?nonFavNumCountSoFar+1:1), isEqual && (i==(s[curDigit]-'0')));
}
return res;
}
And call it:
long long res = 0;
for(int favNumber = 0; favNumber < 10; ++favNumber)
res += f_equal(0, favNumber,0, -1, 0, true);
The final result is res/2. The code is tested and works well.
Obviously, then, you won't do this by considering all numbers in the range. Instead, think in terms of generating the numbers you want. For instance, design a function that will generate all of the qualifying numbers, given no more than the length in digits.
For instance, for 5 digits, you want all the numbers with at least three 1's, or three 2's, or ... Can you do that in one pass, or do you need to separate those with exactly three 1's from those with more?
Now that you've thought about that, think about this: instead of generating all those numbers, just count them. For instance, for three 1's and two other digits, you have 9*9 pairs of other digits (make sure not to double-count things such as 11122). You can arrange the 1's in 10 ways, with a possible swap of the other two digits.
Note that the problem is a little different with an even quantity of digits: you have to avoid double-counting the half-and-half numbers, such as 111222.
Does that get you moving?
RESPONSE TO COMMENTS 03 Dec
#bobjoe628: this is not intended to be a complete algorithm; rather, it's a suggestion to get you started. Yes, you have several combinatoric problems to handle. As for 11122233, I'm not sure I understand your concern: as with any such permutation problem, you have to handle each digit being interchangeable with its siblings. There are 10C5 ways to distribute the 1's; in the remaining spots, there are 5C3 ways to distribute the 2's; the other two slots are 3'3. Readily available algorithms (i.e. browser search) will cover those machinations.
I trust that you can write an algorithm to generate numbers: note that you need only one combination of digits, so it's safe to simply generate digits in ascending order, as you've been giving your examples: 1111122233. Once you've generated that, your combinatoric code should cover all unique permutations of those digits.
Finally, note that most languages have support packages that will perform permutations and combinations for you.
The number 0 is just shorthand. In reality there are an infinite number of leading zeros and an infinite number of trailing zeros (after the decimal point), like ...000000.000000....
For all integers it's obvious that there are at least as many 0s after the decimal point as there are non-zero digits before the decimal point; so all integers can be counted.
There are an infinite number of numbers between 0 and 1; and all of these have at least as many 0s to the left of the decimal point as they have non-zero digits after the decimal point. The same applies to numbers between 0 and -1.
For almost all floating point numbers that a computer can store, there simply isn't enough bits to cancel out all the leading and trailing zeros.
The only numbers that can't be counted are positive and negative infinity, and some but not all irrational numbers that are <= 1 or >= -1.
Code:
float getCount(int x, int y) {
if(x == y) return 0.0; // Special case (no numbers are between x and y)
return INFINITY; // The closest value to the correct answer that a computer can use
}
Here is a partial combinatoric answer. I leave out how to use the function to construct a full answer.
(Please see here for the same code with more elaborate comments: https://repl.it/#gl_dbrqn/AllSteelblueJuliabutterfly)
Fixing the leftmost digit(s), L, in a number with R digits to the right of L, we can calculate how many ways we can distribute (N / 2) or more of digit d by:
Python Code
import math, operator, collections
# Assumes L has at least one digit set
# f({'string':'12', 'digit_frequencies':[0,1,1,0,0,0,0,0,0,0], 'num_digit_frequencies': 2}, 6)
def f(L, N):
R = N - len(L['string'])
count = 0
counted = False
for digit_frequency in L['digit_frequencies']:
start = int(math.ceil(N / 2.0)) - digit_frequency
if start > R:
continue
for i in xrange(start, R + 1):
if not (N & 1) and not counted:
if L['num_digit_frequencies'] == 1 and not digit_frequency and i == N / 2:
count = count - choose(R, i)
if L['num_digit_frequencies'] == 2 and digit_frequency and not any([x > N / 2 for x in L['digit_frequencies']]) and i + digit_frequency == N / 2:
count = count - choose(R, i)
counted = True
m = 9**(R - i)
n = R - i + 1
k = i
count = count + m * choose(n + k - 1, k)
return count
# A brute-force function to confirm results
# check('12', 6)
def check(prefix, length):
result = [x for x in xrange(10**(length - 1), 10**length) if len(str(x)) == length and str(x).startswith(prefix) and isValid(str(x))]
print result
return len(result)
def isValid(str):
letters = collections.Counter(str)
return any([x >= math.ceil(len(str) / 2.0) for x in letters.values()])
# https://stackoverflow.com/questions/4941753/is-there-a-math-ncr-function-in-python
def choose(n, r):
r = min(r, n-r)
if r == 0: return 1
numer = reduce(operator.mul, xrange(n, n-r, -1))
denom = reduce(operator.mul, xrange(1, r+1))
return numer//denom

Finding optimal substructure

I'm looking for some pointers about a dynamic programming problem. I cannot find any relevant information about how to solve this kind of problem.
Problem
A number is called a special number if it doesn't contain 3 consecutive
zeroes. i have to calculate the number of positive integers of exactly d digits
that are special answer should be modulo 1000000007(just for overflow in c++).
Problem can easily solved by permutation and combination but i want it with dynamic programming.
I am unable to find its optimal substructure or bottom to top approach.
Let f(d,x) be the amount of most significant d digits whose last x digits are zeros, where 0 ≤ x ≤ 2. For d > 1, We have the recurrence:
f(d,0) = (f(d-1,0) + f(d-1,1) + f(d-1,2)) * 9 // f(d,0) comes from any d-1 digits patterns appended a non-zero digit
f(d,1) = f(d-1,0) // f(d,1) comes from the d-1 digits patterns without tailing zeros appended by a zero
f(d,2) = f(d-1,1) // f(d,2) comes from the d-1 digits patterns with one tailing zero appended by a zero
And for d = 1, we have f(1,0) = 9, f(1,1) = 0, f(1,2) = 0.
The final answer for the original problem is f(d,0) + f(d,1) + f(d,2).
Here is a simple C program for demo:
#include <cstdio>
const int MOD = 1000000007;
long long f[128][3];
int main() {
int n;
scanf("%d",&n);
f[1][0] = 9;
for (int i = 2 ; i <= n ; ++i) {
f[i][0] = (f[i-1][0] + f[i-1][1] + f[i-1][2]) * 9 % MOD;
f[i][1] = f[i-1][0];
f[i][2] = f[i-1][1];
}
printf("%lld\n", (f[n][0] + f[n][1] + f[n][2]) % MOD);
return 0;
}
NOTE: i haven't tested out my logic thoroughly, so please point out where i might be wrong.
The recurrence for the problem can be
f(d)=f(d/2)*f(d-d/2)-( f(d/2-1)*f(d-d/2-2) + f(d/2-2)*f(d-d/2-1) )
f(0)=1;f(1)=10;f(2)=100;f(3)=999;
here, f(i) is the total number special digits that can be formed considering that '0' can occur as the first digit. So, the actual answer for a 'd' digit number would be 9*f(d-1).
You can easily memoize the recurrence solution to make a DP solution.
I haven't tried out the validity of this solution, so it might be wrong.
Here is my logic:
for f(d), divide/partition the number into d/2 and (d-d/2) digit numbers, add the product of f(d)*f(d-d/2). Now, to remove the invalid cases which may occur across the partition we made, subtract f(d/2-1)*f(d-d/2-2) + f(d/2-2)*f(d-d/2-1) from the answer (assume that three zero occur across the partition we made). Try it with paper and pen and you will get it.

Find {E1,..En} (E1+E2+..En=N, N is given) with the following property that E1* E2*..En is Maximum

Given the number N, write a program that computes the numbers E1, E2, ...En with the following properties:
1) N = E1 + E2 + ... + En;
2) E1 * E2 * ... En is maximum.
3) E1..En, are integers. No negative values :)
How would you do that ? I have a solution based on divide et impera but i want to check if is optimal.
Example: N=10
5,5 S=10,P=25
3,2,3,2 S=10,P=36
No need for an algorithm, mathematic intuition can do it on its own:
Step 1: prove that a result set with numbers higher than 3 is at most as good as a result set with only 3's and 2's
Given any number x in your result set, one might consider whether it would be better to divide it into two numbers.
The sum should still be x.
When x is even, The maximum for t (x - t) is reached when t = x/2 , and except for the special case x = 2, then it is greater than x, and for the special case x = 4, equal to x (see note 1).
When x is odd, The maximum for t (x - t) is reached when t = (x ± 1)/2.
What does this show? Only that you should only have 3's and 2's in your final set, because otherwise it is suboptimal (or equivalent to an optimal set).
Step 2: you should have as many 3's as possible
Now, as 3² > 2³, you should have as many 3's as possible as long as the remainder is not 1.
Conclusion: for every N >= 3:
If N = 0 mod 3, then the result set is only 3's
If N = 1 mod 3, then the result set has one pair of 2's (or a 4) and the rest is 3's
If N = 2 mod 3, then the result set has one 2 and the rest is 3's
Please correct this post. The times when I was writing well-structured mathematical proofs is far away...
Note 1: (2,4) is the only pair of distinct integers such that x^y = y^x. You can prove that with:
x^y = y^x
y ln(x) = x ln(y)
ln(x)/x = ln(y) / y
and the function ln(t)/t is strictly decreasing after its global maximum, reached between 2 and 3, so if you want two distinct integers such that ln(x)/x = ln(y)/y, one of them must be lower or equal to 2. From that you can infer that only (2,4) works
This is not a complete solution, but might help.
First off note that if you fix n, and two of the terms E_i and E_j differ by more than one (for example 3 and 8), then you can do better by "equalizing" them as much as possible, i.e., if the number p = E_i + E_j is even, you do better both terms by p/2. If p is odd, you do better by replacing them with p/2 and p/2+1 (where / is integer division).
That said, then if you knew what the optimal number of terms, n, was, you'd be done: let all E_i's equal N/n and N/n+1 (again integer division), so that their sum is still N (this is now a straightforward problem).
So the question now is what is the optimal n. Suppose for the moment that you are allowed to use real numbers. Then the solution would be N/n for each term and you could write the product as (N/n)^n. If you differentiate this with respect to n and find its root you find that n should be equal to N/e (where e is the Neper number, also known as Euler's number, e = 2.71828....). Therefore, I'd look for a solution where either n = floor(N/e) or n = floor(N/e)+1, and then choose all the E_i's equal to either N/n or N/n+1, as above.
Hope that helps.
The Online Encycolpedia of Integer Sequences gives a recurrence relation for the solution to this problem.
I'll leave it up to someone else to compare complexities. Not sure I can figure out the complexity of OP's method.

Array: mathematical sequence

An array of integers A[i] (i > 1) is defined in the following way: an element A[k] ( k > 1) is the smallest number greater than A[k-1] such that the sum of its digits is equal to the sum of the digits of the number 4* A[k-1] .
You need to write a program that calculates the N th number in this array based on the given first element A[1] .
INPUT:
In one line of standard input there are two numbers seperated with a single space: A[1] (1 <= A[1] <= 100) and N (1 <= N <= 10000).
OUTPUT:
The standard output should only contain a single integer A[N] , the Nth number of the defined sequence.
Input:
7 4
Output:
79
Explanation:
Elements of the array are as follows: 7, 19, 49, 79... and the 4th element is solution.
I tried solving this by coding a separate function that for a given number A[k] calculates the sum of it's digits and finds the smallest number greater than A[k-1] as it says in the problem, but with no success. The first testing failed because of a memory limit, the second testing failed because of a time limit, and now i don't have any possible idea how to solve this. One friend suggested recursion, but i don't know how to set that.
Anyone who can help me in any way please write, also suggest some ideas about using recursion/DP for solving this problem. Thanks.
This has nothing to do with recursion and almost nothing with dynamic programming. You just need to find viable optimizations to make it fast enough. Just a hint, try to understand this solution:
http://codepad.org/LkTJEILz
Here is a simple solution in python. It only uses iteration, recursion is unnecessary and inefficient even for a quick and dirty solution.
def sumDigits(x):
sum = 0;
while(x>0):
sum += x % 10
x /= 10
return sum
def homework(a0, N):
a = [a0]
while(len(a) < N):
nextNum = a[len(a)-1] + 1
while(sumDigits(nextNum) != sumDigits(4 * a[len(a)-1])):
nextNum += 1
a.append(nextNum)
return a[N-1]
PS. I know we're not really supposed to give homework answers, but it appears the OP is in an intro to C++ class so probably doesn't know python yet, hopefully it just looks like pseudo code. Also the code is missing many simple optimizations which would probably make it too slow for a solution as is.
It is rather recursive.
The kernel of the problem is:
Find the smallest number N greater than K having digitsum(N) = J.
If digitsum(K) == J then test if N = K + 9 satisfies the condition.
If digitsum(K) < J then possibly N differs from K only in the ones digit (if the digitsum can be achieved without exceeding 9).
Otherwise if digitsum(K) <= J the new ones digit is 9 and the problem recurses to "Find the smallest number N' greater than (K/10) having digitsum(N') = J-9, then N = N'*10 + 9".
If digitsum(K) > J then ???
In every case N <= 4 * K
9 -> 18 by the first rule
52 -> 55 by the second rule
99 -> 189 by the third rule, the first rule is used during recursion
25 -> 100 requires the fourth case, which I had originally not seen the need for.
Any more counterexamples?