How can I optimize this algorithm? Working with chars - java

Task: We are given two strings of the same length, m and n. We want to modify m into n. We can perform two operations;
We can take a contiguous segment of the current string and either shift each letter in the segment forward in the alphabet once, or backward in the alphabet.
We want to complete this in the minimum number of steps, the goal is an O (n) algorithm.
So here's my first stab at it; obviously not even close to being as optimized as it could be, but I'm kind of lost as to how to optimize it. I'm not sure how to determine what segment of letters would be best to take. My implementation just goes through one letter at a time currently.
public static void shift(String m, String n) {
char mChar[] = m.toCharArray();
char nChar[] = n.toCharArray();
int count = 0;
for (int i = 0; i < m.length(); i++){
while (mChar[i] != nChar[i]){
if (mChar[i] - nChar[i] < 0){
//System.out.println("SHIFT FORWARD");
mChar[i]++;
count++;
}
else{
//System.out.println("SHIFT BACKWARD");
mChar[i]--;
count++;
}
System.out.println(mChar[i]);
}
}
System.out.println(mChar);
System.out.println(count);
}
Also what would be the time complexity of this algorithm as is? The For loop makes it at the minimum O (n), and the while loop could run 25 times in the worst case (if we had 'y' and wanted 'a'). Am I right in this thinking?

Since you're supposed to learn how to program, I won't give you the code, but I can help you with the right algorithm in this case.
I'll do it by example:
shift( "AAAAZZZZ", "BCDBZYYX" )
The goal here is to minimize the number of shift operations, so you need to optimize the block size being shifted.
First, identify the number of shifts needed for each character:
A A A A Z Z Z Z
B C D B Z Y Y X
+1 +2 +3 +1 0 -1 -1 -2
Starting at the first position, if the shift is positive, find the largest consecutive block of positive shifts. If negative, find block of negative shifts. Apply shift. Repeat until zero, and go to next character.
1: Index 0 to 3, shift up:
B B B B Z Z Z Z
0 +1 +2 0 0 -1 -1 -2
2: Index 1 to 2, shift up:
B C C B Z Z Z Z
0 0 +1 0 0 -1 -1 -2
3: Index 2, shift up:
B C D B Z Z Z Z
0 0 0 0 0 -1 -1 -2
4: Index 5 to 7, shift down:
B C D B Z Y Y Y
0 0 0 0 0 0 0 -1
5: Index 7, shift down:
B C D B Z Y Y X
0 0 0 0 0 0 0 0
Done in 5 shift operations.
Update
Optimization: Program doesn't need to "identify the number of shifts" up front, or at all. That was mostly done to help illustrate the algorithm.

Although #Andreas 's answer is viable, it's not O(N). You want to think about the worst case when you then in the minute details it'll be..
How to implement Andreas's answer
you need to know the size of the gaps, so not where it changes indices, but the blocks themselves. Have 2 temp variables -> int startIndex, endIndex...
startIndex = 0, endIndex = -1 at first, and then when you see the sign change, change endIndex = i, record that block length i-startIndex in your blockSize[] append...
then when you see another change, startIndex = endIndex, endIndex = i, record i-startIndex in your blockSize[] append...
When you're done with that, the answer-producing block of code goes like this...
Thinking...
"I need to increment... the last 4 blocks.. let's go through our array which might be size N, let's see.. okay the last 4 is biggest block, now let's go increment the last 4"
Now why is that bad?
You need to go through that size N array everytime you go through the incrementing process, which is why it leads to N^2, do you see what I mean? for big Oh, you always need to think of the literal worst case, which in yours is
[1, -1, 1, -1, 1, -1]
what will you do then? You'll create a gap size array of
[1,1,1,1,1,1]
and then you'll have to go through those gap size array N times to find thebiggest size which is actually any of them so then you'll go through N times to find the biggest size through an N sized, alternating array hence N^2.
Here's another method, but I'm not completely sure if it'll be O(N) or O(N*k), where k is factoring in the # of processes required to shift one letter by one(because you specified that).
[1, -1, 1, -1, 1, -1]
remove 1 from everything
[0, -2, 0, -2, 0, -2]
next time you remove 2 from everything EXCLUDING the 0's
(keep track of the 0's in another array as a flag)
[0,0,0,0,0,0] is your 2nd run through of the array
so 2 shifting operations as opposed to 36
Of course, doing it my method has its worst case too, shown below:
[1, 4, 12, -3, -2, 3] let's say...
1st. [0,3,11,-4,-3,2]
2nd. [0,0,8,-7,-6,-1]
3rd. [0,0,0,-15,-14,-9]
This will lead to a total of 6 operations, but the indices to increment has almost quadrupled in the last 3. I don't know if you're going straight from a -> z, or a->b->c... If it's the former, then I don't think the avalanche effect will be significant.
I can't think of any O(N) operations other than this, which require k to be constant.
When someone answers a question regarding big O computational speed, you should always think of this phrase:
A description of a function in terms of big O notation usually only
provides an upper bound on the growth rate of the function. Associated
with big O notation are several related notations, using the symbols
o, Ω, ω, and Θ, to describe other kinds of bounds on asymptotic growth
rates. - Wikipedia
Although #Andrea's answer is elegant and on average probably performs well, it's not O(N) because the upper bound on the growth rate can be much higher than you expected.

Related

append strings with increasing frequency

You are given two strings S and T. An infinitely long string is formed in the following manner:
Take an empty string,
Append S one time,
Append T two times,
Append S three times,
Append T four times,
and so on, appending the strings alternately and increasing the number of repetitions by 1 each time.
You will also be given an integer K.
You need to tell the Kth Character of this infinitely long string.
Sample Input (S, T, K):
a
bc
4
Sample Output:
b
Sample Explanation:
The string formed will be "abcbcaaabcbcbcbcaaaaa...". So the 4th character is "b".
My attempt:
public class FindKthCharacter {
public char find(String S, String T, int K) {
// lengths of S and T
int s = S.length();
int t = T.length();
// Counters for S and T
int sCounter = 1;
int tCounter = 2;
// To store final chunks of string
StringBuilder sb = new StringBuilder();
// Loop until K is greater than zero
while (K > 0) {
if (K > sCounter * s) {
K -= sCounter * s;
sCounter += 2;
if (K > tCounter * t) {
K -= tCounter * t;
tCounter += 2;
} else {
return sb.append(T.repeat(tCounter)).charAt(K - 1);
}
} else {
return sb.append(S.repeat(sCounter)).charAt(K - 1);
}
}
return '\u0000';
}
}
But is there any better way to reduce its time complexity?
I've tried to give a guide here, rather than just give the solution.
If s and t are the lengths of the strings S and T, then you need to find the largest odd n such that
(1+3+5+...+n)s + (2+4+6+...+(n+1))t < K.
You can simplify these expressions to get a quadratic equation in n.
Let N be (1+3+..+n)s + (2+4+6+...+(n+1))t. You know that K will lie either in the next (n+2) copies of S, or the (n+3) copies of T that follow. Compare K to N+(n+2)s, and take the appropriate letter of either S or T using a modulo.
The only difficult step here is solving the large quadratic, but you can do it in O(log K) arithmetic operations easily enough by doubling n until it's too large, and then using a binary search on the remaining range. (If K is not too large so that floating point is viable, you can do it in O(1) time using the well-known quadratic formula).
Here my quick attempt, there probably is a better solution. Runtime is still O(sqrt n), but memory is O(1).
public static char find(String a, String b, int k) {
int lenA = a.length();
int lenB = b.length();
int rep = 0;
boolean isA = false;
while (k >= 0) {
++rep;
isA = !isA;
k -= (isA ? lenA : lenB) * rep;
}
int len = (isA ? lenA : lenB);
int idx = (len * rep + k) % len;
return (isA ? a : b).charAt(idx);
}
Here's a O(1) solution that took me some time to come up with (read I would have failed an interview on time). Hopefully the process is clear and you can implement it in code.
Our Goal is to return the char that maps to the kth index.
But How? Just 4 easy steps, actually.
Step 1: Find out how many iterations of our two patterns it would take to represent at least k characters.
Step 2: Using this above number of iterations i, return how many characters are present in the previous i-1 iterations.
Step 3: Get the number of characters n into iteration i that our kth character is. (k - result of step 2)
Step 4: Mod n by the length of the pattern to get index into pattern for the specific char. If i is odd, look into s, else look into t.
For step 1, we need to find a formula to give us the iteration i that character k is in. To derive this formula, it may be easier to first derive the formula needed for step 2.
Step 2's formula is basically given an iteration i, return how many characters are present in that iteration. We are solving for 'k' in this equation and are given i, while it's the opposite for step 1 where were are solving for i given k. If we can derive the equation of find k given i, then we can surely reverse it to find i given k.
Now, let's try to derive the formula for step 2 and find k given i. Here it's best to start with the most basic example to see the pattern.
s = "a", t = "b"
i=1 a
i=2 abb
i=3 abbaaa
i=4 abbaaabbbb
i=5 abbaaabbbbaaaaa
i=6 abbaaabbbbaaaaabbbbbb
Counting the total number of combined chars for each pattern during its next iteration gives us:
#iterations of pattern: 1 2 3 4 5 6 7 8 9 10
every new s iteration: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100
every new t iteration: 2, 6, 12, 20, 30, 42, 56, 72, 90, 110
You might notice some nice patterns here. For example, s has a really nice formula to find out how many combined characters it has at any given iteration. It's simply (# of s iterations^2)*s.length. t also has a simple formula. It is (# of t iterations * (# of t iterations + 1))*t.length. You may have noticed that these formulas are the formulas for sum of odd and even numbers (if you did you get a kudos). This makes sense because each pattern's sum for an iteration i is the sum of all of its previous iterations.
Using s,t as length of their respective patterns, we now have the following formula to find the total number of chars at a given iteration.
#chars = s*(# of s iterations)^2 + t * (# of t iterations * (# of t iterations + 1))
Now we just need to do some math to get the number of iterations for each pattern given i.
# of s iterations given i = ceil(i/2.0)
# of t iterations given i = floor(i/2) which / operation gives us by default
Plugging these back into our formula we get:
total # of chars = s*(ceil(i/2.0)^2) + t*((i/2)*((i/2)+1))
We have just completed step 2, and we now know at any given iteration how many total chars there are. We could stop here and start picking random iterations and adjusting accordingly until we get near k, but we can do better than that. Let's use the above formula now to complete step 1 which we skipped. We just need to reorganize our equation to solve for i now.
Doing some simplyfying we get:
// 2
// i i i
// s (-) + t - ( - + 1 ) = k
// 2 2 2
// ----------------------------
// 2
// i t i
// s - + - ( - + 1 )i = k
// 4 2 2
// ----------------------------
// 2 2
// si ti ti
// ---- + ---- + ---- - k = 0
// 4 4 2
// ----------------------------
//
// 2 2
// si + ti + 2ti - 4k = 0
// ----------------------------
// 2
// (s + t)i + 2ti - 4k = 0
// ----------------------------
This looks like a polynomial. Wow! You're right! That means we can solve it using the quadratic formula.
A=(s+t), B=2t, C=-4k
quadratic formula = (-2t + sqrt(2t^2 + 16(s+t)k)) / 2(s+t)
This is our formula for step 1, and it will give us the iteration that the kth character is on. We just need to ceil it. I'm actually not smart enough to know why this works. It just does. Here is a desmos graph that graphs our two polynomials from step 2: s(Siterations)^2 and t(Titerations (Titerations + 1)).
The area under both curves is our total number of chars at an iteration (the vertical line). The formula from step 1 is also graphed, and we can see that for any s, t, k that the x intercept (which represents our xth iteration) is always: previous iteration < x <= current iteration, which is why the ceil works.
We have now completed steps 1 and 2. We have a formula to get the ith iteration that the kth character is on and a formula that gives us how many characters are in an ith iteration. Steps 3 and 4 should follow and we get our answer. This is constant time.

How to find the point that gives the maximum value fast? Java or c++ code please

I need a fast way to find maximum value when intervals are overlapping, unlike finding the point where got overlap the most, there is "order". I would have int[][] data that 2 values in int[], where the first number is the center, the second number is the radius, the closer to the center, the larger the value at that point is going to be. For example, if I am given data like:
int[][] data = new int[][]{
{1, 1},
{3, 3},
{2, 4}};
Then on a number line, this is how it's going to looks like:
x axis: -2 -1 0 1 2 3 4 5 6 7
1 1: 1 2 1
3 3: 1 2 3 4 3 2 1
2 4: 1 2 3 4 5 4 3 2 1
So for the value of my point to be as large as possible, I need to pick the point x = 2, which gives a total value of 1 + 3 + 5 = 9, the largest possible value. It there a way to do it fast? Like time complexity of O(n) or O(nlogn)
This can be done with a simple O(n log n) algorithm.
Consider the value function v(x), and then consider its discrete derivative dv(x)=v(x)-v(x-1). Suppose you only have one interval, say {3,3}. dv(x) is 0 from -infinity to -1, then 1 from 0 to 3, then -1 from 4 to 6, then 0 from 7 to infinity. That is, the derivative changes by 1 "just after" -1, by -2 just after 3, and by 1 just after 6.
For n intervals, there are 3*n derivative changes (some of which may occur at the same point). So find the list of all derivative changes (x,change), sort them by their x, and then just iterate through the set.
Behold:
intervals = [(1,1), (3,3), (2,4)]
events = []
for mid, width in intervals:
before_start = mid - width - 1
at_end = mid + width
events += [(before_start, 1), (mid, -2), (at_end, 1)]
events.sort()
prev_x = -1000
v = 0
dv = 0
best_v = -1000
best_x = None
for x, change in events:
dx = x - prev_x
v += dv * dx
if v > best_v:
best_v = v
best_x = x
dv += change
prev_x = x
print best_x, best_v
And also the java code:
TreeMap<Integer, Integer> ts = new TreeMap<Integer, Integer>();
for(int i = 0;i<cows.size();i++) {
int index = cows.get(i)[0] - cows.get(i)[1];
if(ts.containsKey(index)) {
ts.replace(index, ts.get(index) + 1);
}else {
ts.put(index, 1);
}
index = cows.get(i)[0] + 1;
if(ts.containsKey(index)) {
ts.replace(index, ts.get(index) - 2);
}else {
ts.put(index, -2);
}
index = cows.get(i)[0] + cows.get(i)[1] + 2;
if(ts.containsKey(index)) {
ts.replace(index, ts.get(index) + 1);
}else {
ts.put(index, 1);
}
}
int value = 0;
int best = 0;
int change = 0;
int indexBefore = -100000000;
while(ts.size() > 1) {
int index = ts.firstKey();
value += (ts.get(index) - indexBefore) * change;
best = Math.max(value, best);
change += ts.get(index);
ts.remove(index);
}
where cows is the data
Hmmm, a general O(n log n) or better would be tricky, probably solvable via linear programming, but that can get rather complex.
After a bit of wrangling, I think this can be solved via line intersections and summation of function (represented by line segment intersections). Basically, think of each as a triangle on top of a line. If the inputs are (C,R) The triangle is centered on C and has a radius of R. The points on the line are C-R (value 0), C (value R) and C+R (value 0). Each line segment of the triangle represents a value.
Consider any 2 such "triangles", the max value occurs in one of 2 places:
The peak of one of the triangle
The intersection point of the triangles or the point where the two triangles overall. Multiple triangles just mean more possible intersection points, sadly the number of possible intersections grows quadratically, so O(N log N) or better may be impossible with this method (unless some good optimizations are found), unless the number of intersections is O(N) or less.
To find all the intersection points, we can just use a standard algorithm for that, but we need to modify things in one specific way. We need to add a line that extends from each peak high enough so it would be higher than any line, so basically from (C,C) to (C,Max_R). We then run the algorithm, output sensitive intersection finding algorithms are O(N log N + k) where k is the number of intersections. Sadly this can be as high as O(N^2) (consider the case (1,100), (2,100),(3,100)... and so on to (50,100). Every line would intersect with every other line. Once you have the O(N + K) intersections. At every intersection, you can calculate the the value by summing the of all points within the queue. The running sum can be kept as a cached value so it only changes O(K) times, though that might not be posible, in which case it would O(N*K) instead. Making it it potentially O(N^3) (in the worst case for K) instead :(. Though that seems reasonable. For each intersection you need to sum up to O(N) lines to get the value for that point, though in practice, it would likely be better performance.
There are optimizations that could be done considering that you aim for the max and not just to find intersections. There are likely intersections not worth pursuing, however, I could also see a situation where it is so close you can't cut it down. Reminds me of convex hull. In many cases you can easily reduce 90% of the data, but there are cases where you see the worst case results (every point or almost every point is a hull point). For example, in practice there are certainly causes where you can be sure that the sum is going to be less than the current known max value.
Another optimization might be building an interval tree.

Create and fill a variable-sized binary truth table

I am trying solve the 0/1 Knapsack problem through brute force. The simplest (it seems) way to do it would be to set up a 2d matrix with 1's and 0's signifying present and non-present in the knapsack, respectively. The parameters would be the number of items (ie: columns), so then the rows should be 2^numOfItems. But since the number of items isn't constant, I can't think of how to fill the matrix. I was told that bit-shifting would work, but I do not understand how that works. Can someone point me in the right direction?
EDIT: by truth table I mean the 'A' part of one of these: http://www.johnloomis.org/ece314/notes/devices/binary_to_BCD/bcd03.png
You don't have to store all the bit sequences in a matrix, it's unnecessary and will waste way too much memory. You can simply use an integer to denote the current set. The integer will go from 0 to 2^n-1 where n is the number of elements that you can choose from. Here's the basic idea.
int max = (1 << n);
for(int set = 0; set < max; set++)
{
for(int e = 0; e < n; e++)
{
if((set & (1 << e)) != 0)
//eth bit is 1 means that the eth item is in our set
else
// eth element will not be put in the knapsack
}
}
The algorithm relies on logical left bit shifting. (1 << n) means that we will shift 1, n positions to the left by padding zeros to the right side of the number. So for example, if we represent 1 as an 8-bit number 00000001, (1 << 1) == 00000010, (1 << 2) == 00000100, etc. The bitwise-and operator is an operator that takes two arguments, and "ands" every two bits that have the same index. So if we have 2 bit-strings of length n each, bit zero will be anded with bit 0, bit 1 with bit 1, etc. The output of & is a 1 if and only if both bits are 1s, otherwise it's 0. Why is this useful?? we need it to test bits. For example, assume that we have some set represented as a bit-string, and we want to determine if the ith bit in the bit-set is one or a zero. We can do that by using a shift left operation followed by a bitwise-and operation.
Example
Set = 00101000
we want to test Set(3) (remember that the rightmost bit is bit 0)
We can do that by shifting 1 3 places to the left, so it becomes 00001000. Then we "and" the shifted 1 with the set
00101000
&
00001000
---------
00001000
As you can see, if the bit I am testing is a 1, then the output of the & will be non zero, otherwise it'll be zero.

Determine If An Array of Length N is in an Array of Length M [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Algorithm to determine if array contains n…n+m?
Lets assume that M > N, and you have 2 arrays. One of length M called A and one of length N called B. Is there a faster way to find out if array B exists in array A?
For Example:
A = [ 1 2 3 4 5 6 ]
B1 = [ 2 3 4 ]
so array B1 exists in A while something like [ 1 3 2 ] does not.
This is essentially implementing something like isSubstring() in Java with a char array.
The only method that I can think of is in O(n^2) where you compare each element in A with the initial element in B and iterate through B looking for a match.
I guess this question is fairly common in interviews, so my question is asking if there is a faster approach.
You want KMP
algorithm kmp_search:
input:
an array of characters, S (the text to be searched)
an array of characters, W (the word sought)
output:
an integer (the zero-based position in S at which W is found)
define variables:
an integer, m ← 0 (the beginning of the current match in S)
an integer, i ← 0 (the position of the current character in W)
an array of integers, T (the table, computed elsewhere)
while m+i is less than the length of S, do:
if W[i] = S[m + i],
if i equals the (length of W)-1,
return m
let i ← i + 1
otherwise,
let m ← m + i - T[i],
if T[i] is greater than -1,
let i ← T[i]
else
let i ← 0
(if we reach here, we have searched all of S unsuccessfully)
return the length of S
Complexity:
Assuming the prior existence of the table T, the search portion of the
Knuth–Morris–Pratt algorithm has complexity O(k), where k is the
length of S and the O is big-O notation. As except for the fixed
overhead incurred in entering and exiting the function, all the
computations are performed in the while loop, we will calculate a
bound on the number of iterations of this loop; in order to do this we
first make a key observation about the nature of T. By definition it
is constructed so that if a match which had begun at S[m] fails while
comparing S[m + i] to W[i], then the next possible match must begin at
S[m + (i - T[i])]. In particular the next possible match must occur at
a higher index than m, so that T[i] < i. Using this fact, we will show
that the loop can execute at most 2k times. For in each iteration, it
executes one of the two branches in the loop. The first branch
invariably increases i and does not change m, so that the index m + i
of the currently scrutinized character of S is increased. The second
branch adds i - T[i] to m, and as we have seen, this is always a
positive number. Thus the location m of the beginning of the current
potential match is increased. Now, the loop ends if m + i = k;
therefore each branch of the loop can be reached at most k times,
since they respectively increase either m + i or m, and m ≤ m + i: if
m = k, then certainly m + i ≥ k, so that since it increases by unit
increments at most, we must have had m + i = k at some point in the
past, and therefore either way we would be done. Thus the loop
executes at most 2k times, showing that the time complexity of the
search algorithm is O(k).
additional information:
Efficiency of the KMP algorithm
Since the two portions of the algorithm have, respectively,
complexities of O(k) and O(n), the complexity of the overall algorithm
is O(n + k). These complexities are the same, no matter how many
repetitive patterns are in W or S.

Find an integer n > 0 which holds the following three conditions

Some definition for starters: flip(n) is the 180 degree rotation of a seven segment display font number, so a 2 in seven segment font will be flipped to a 2. 0,1,2,5,8 will be mapped to themselfs. 6 -> 9, 9 -> 6 and 3,4,7 are not defined. Therefore any number containing 3,4,7 will not be flippable. More examples: flip(112) = 211, flip(168) = 891, flip(3112) = not defined.
(By the way, I am quite sure that flip(1) should be undefined, but the homework says that flip(168) = 891 so regarding this assignment flip(1) is defined)
The original challenge: Find an integer n > 0 which holds the following three conditions:
flip(n) is defined and flip(n) = n
flip(n*n) is defined
n is divisible by 2011 -> n % 2011 == 0
Our solution which you can find below seems to work, but it does not find an answer at least not for 2011. If I am using 1991 instead (I searched for some "base" number for which the problem could be solved) I am getting a pretty fast answer saying 1515151 is the one. So the basic concept seems to work but not for the given "base" in the homework. Am I missing something here?
Solution written in pseudo code (We have an implementation in Small Basic and I made a multithreading one in Java):
for (i = 1; i < Integer.MaxValue; i++) {
n = i * 2011;
f = flip(n, true);
if (f != null && flip(n*n, false) != null) {
print n + " is the number";
return;
}
}
flip(n, symmetry) {
l = n.length;
l2 = (symmetry) ? ceil(l/2) : l;
f = "";
for (i = 0; i < l2; i++) {
s = n.substr(i,1);
switch(s) {
case 0,1,2,5,8:
r = s; break;
case 6:
r = 9; break;
case 9:
r = 6; break;
default:
r = "";
}
if (r == "") {
print n + " is not flippable";
return -1;
} elseif (symmetry && r != n.substr(l-i-1,1)) {
print n + " is not flip(n)";
return -1;
}
f = r + f;
}
return (symmetry) ? n : f;
}
Heuristically (with admittedly minimal experimentation and going mainly on intuition), it is not so likely you will find a solution without optimising your search technique mathematically (e.g. employing a method of construction to build a perfect square that doesn't contain 3,4,7 and is flippably symmetrical. as opposed to optimising the computations, which will not change the complexity by a noticeable amount):
I'll start with a list of all numbers who satisfy 2 criteria (that the number and it's flip be the same, i.e. flippably symmetrical, and that it be a multiple of 2011), less than 10^11:
192555261 611000119 862956298
988659886 2091001602 2220550222
2589226852 6510550159 8585115858
10282828201 12102220121 18065559081
18551215581 19299066261 20866099802
22582528522 25288188252 25510001552
25862529852 28018181082 28568189582
28806090882 50669869905 51905850615
52218581225 55666299955 58609860985
59226192265 60912021609 68651515989
68828282889 69018081069 69568089569
85065859058 85551515558 89285158268
91081118016 92529862526 92852225826
95189068156 95625052956 96056895096
96592826596 98661119986 98882128886
98986298686
There are 46 numbers there, all flippably symmetrical according to the definition and multiples of 2011, under 10^11. Seemingly multiples of 2011 that satisfy this condition will become scarcer because as the number of digits increases, less of the multiples will be palindromes, statistically.
I.e. for any given range, say [1, 10^11] (as above), there were 46. For the adjacent range of equal width: [10^11+1, 2*10^11], we might guess to find another 46 or thereabouts. But as we continue up with intervals of the same width in higher powers of 10, the number of numbers is the same (because we analyse equal width intervals) although the palindrome condition now falls on more digits because the number of digits increases. So approaching infinity we expect the number of palindromes on any fixed with interval to approach 0. Or, more formally (but without proof) for every positive value N, with probability 0 a given interval (of predetermined width) will have more than N multiples of 2011 that are palindromes.
So the number of palindromes we can find will decrease as an exhaustive search continues. As per the probability that for any found palindrome the square will be flippable, we assume uniform distribution of the squares of palindromes (since we have no analysis to tell us otherwise, and no reason to believe otherwise) and then the probability that any given square of d digits length will be flippable is (7/10)^d.
Let's start with the smallest such square we found
192555261 ^ 2 = 37077528538778121
which is already 17 digits long, giving it a probability of around 0.002 (approx. 1/430) that it's flippably defined. But already by the time we've reached the last on the list:
98986298686 ^ 2 = 9798287327554005326596
which is 24 digits long, and has a probability of less than 1/5000 of being flippably defined.
So as the search continues in higher numbers, the number of palindromes decreases, and the probability that any found palindrome's square is flippable also decreases - a double edged blade.
What's left is to find some sort of ratio of densities and accordingly see how improbable finding a solution is... Although it's clear intuitively that finding a solution gets much less likely probabilistically speaking (which by no means rules out that one or even a large number of solutions exist (possibly an infinite number?)).
Good luck! I hope someone solves this. As with many problems, the solutions are often not as simple as running the algorithm on a faster machine or with more parallelism or for a longer period of time or whatnot, but with a more advanced technique or more inventive methods of attacking the problem, which themselves further the field. The answer, a number, is of much less interest (usually) than the method used to derive it.
You are searching through all of the numbers divisible by 2011, then checking whether they are the flip of themselves. But after you've reached 7 digit numbers the condition that it be a flip of itself is more restrictive than the condition that it be divisible by 2011. So I'd suggest that you instead iterate through all of the numbers that can be constructed without the digits 3, 4, 7, then construct the number that is flip of itself prepended to itself, possibly squishing a middle digit if the middle digits are 11, 22, 55, or 88. Then test for divisibility by 2011, then test whether n*n is flippable.
Be very, very aware of the possibility that n*n will hit integer overflow. By the time you've reached a 5-digit number for the base, your n will be 9 or 10 digits long, and n*n will be 18-21 digits long.
Not necessarily a complete solution, more like thought process which may help you on the way.
n = flip(n) => n is a palindrome (180° rotation in flip()), n consists only of numbers which map to themselves in flip() i.e.: 0, 1, 2, 5, 8
flip(n*n) is defined. Thus n*n may not contain 3, 4, 7
n % 2011 = 0.
n > 0.

Categories