How to find all the palindromes in a large array? - arrays

I need to find all the palindromes of π with 50 million digits 3.141592653589793238462643383279502884197169399375105820974944592307816406286... (goes on and on...)
I've stored all the digits of π in a char array. Now I need to search and count the number of 'palindromes' of length 2 to 15. For example, 535, 979, 33, 88, 14941, etc. are all valid results.
The final output I want is basically like the following.
Palindrome length Number of Palindromes of this length
-----------------------------------------------------------------
2 1234 (just an example)
3 1245
4 689
... ...
... ...
... ...
... ...
15 0
pseudocode of my logic so far - it works but takes forever
//store all digits in a char array
char *piArray = (char *)malloc(NUM_PI_DIGITS * sizeof(char));
int count = 0; //count for the number of palindromes
//because we only need to find palindroms that are 2 - 15 digits long
for(int i = 2; i <= 15; i++){
//loop through the piArray and find all the palindromes with i digits long
for(int j = 0; j < size_of_piArray; j++){
//check if the the sub array piArray[j:j+i] is parlindrom, if so, add a count
bool isPalindrome = true;
for (int k = 0; k < i / 2; k++)
{
if (piArray [j + k] != piArray [j + i - 1 - k])
{
isPalindrom = false;
break;
}
}
if(isPalindrome){
count++;
}
}
}
The problem I am facing now is that it takes too long to loop through the array of this large size (15-2)=13 times. Is there any better way to do this?

Here is a C version adapted from the approach proposed by Caius Jard:
void check_pi_palindromes(int NUM_PI_DIGITS, int max_length, int counts[]) {
// store all digits in a char array
int max_span = max_length / 2;
int start = max_span;
int end = NUM_PI_DIGITS + max_span;
char *pi = (char *)malloc(max_span + NUM_PI_DIGITS + max_span);
// read of generate the digits starting at position `max_span`
[...]
// clear an initial and trailing area to simplify boundary testing
memset(pi, ' ', start);
memset(pi + end, ' ', max_span);
// clear the result array
for (int i = 0; i <= max_length; i++) {
count[i] = 0;
}
// loop through the pi array and find all the palindromes
for (int i = start; i < end; i++) {
if (pi[i + 1] == pi[i - 1]) { //center of an odd length palindrome
count[3]++;
for (n = 2; n <= max_span && pi[i + n] == pi[i - n]; n++) {
count[n * 2 + 1]++;
}
}
if (pi[i] == pi[i - 1]) { //center of an even length palindrome
count[2]++;
for (n = 1; n <= max_span && pi[i + n] == pi[i - n]; n++) {
count[n * 2]++;
}
}
}
}
For each position in the array, it scans in both directions for palindromes of odd and even lengths with these advantages:
single pass through the array
good cache locality because all reads from the array are in a small span from the current position
fewer tests as larger palindromes are only tested as extensions of smaller ones.
A small working prefix and suffix is used to avoid the need to special case the beginning and end of the sequence.

I can't solve it for C, as I'm a C# dev but I expect the conversion will be trivial - I've tried to keep it as basic as possible
char[] pi = "3.141592653589793238462643383279502884197169399375105820974944592307816406286".ToCharArray(); //get a small piece as an array of char
int[] lenCounts = new int[16]; //make a new int array with slots 0-15
for(int i = 1; i < pi.Length-1; i++){
if(pi[i+1] == pi[i-1]){ //center of an odd length pal
int n = 2;
while(pi[i+n] == pi[i-n] && n <= 7) n++;
lenCounts[((n-1)*2+1)]++;
} else if(pi[i] == pi[i-1]){ //center of an even length pal
int n = 1;
while(pi[i+n] == pi[i-1-n] && n <= 7) n++;
lenCounts[n*2]++;
}
}
This demonstrates the "crawl the string looking for a palindrome center then crawl away from it in both directions looking for equal chars" technique..
..the only thing I'm not sure on, and it has occurred in the Pi posted, is what you want to do if palindromes overlap:
3.141592653589793238462643383279502884197169399375105820974944592307816406286
This contains 939 and overlapping with it, 3993. The algo above will find both, so if overlaps are not to be allowed then you might need to extend it to deal with eliminating earlier palindromes if they're overlapped by a longer one found later
You can play with the c# version at https://dotnetfiddle.net/tkQzBq - it has some debug print lines in too. Fiddles are limited to a 10 second execution time so I don't know if you'll be able to time the full 50 megabyte 😀 - you might have to run this algo locally for that one
Edit: fixed a bug in the answer but I haven't fixed it in the fiddle; I did have while(.. n<lenCounts.Length) i.e. allowing n to reach 15, but that would be an issue because it's in both directions.. nshould go to 7 to remain in range of the counts array. I've patched that by hard coding 7 but you might want to make it dependent on array length/2 etc

Well, I think it can't be done less than O(len*n), and that you are doing this O(len^2*n), where 2 <= len <= 15, is almost the same since the K coefficient doesn't change the O notation in this case, but if you want to avoid this extra loop, you can check these links, it shouldn't be hard to add a counter for each length since these codes are counting all of them, with maximum possible length:
source1, source2, source3.
NOTE: Mostly it's better to reach out GeekForGeeks when you are looking for algorithms or optimizations.
EDIT: one of the possible ways with O(n^2) time complexity and O(n)
Auxiliary Space. You can change unordered_map by array if you wish, anyway here the key will be the length and the value will be the count of palindromes with that length.
unordered_map<int, int> countPalindromes(string& s) {
unordered_map<int, int> m;
for (int i = 0; i < s.length(); i++) {
// check for odd length palindromes
for (int j = 0; j <= i; j++) {
if (!s[i + j])
break;
if (s[i - j] == s[i + j]) {
// check for palindromes of length
// greater than 1
if ((i + j + 1) - (i - j) > 1)
m[(i + j + 1) - (i - j)]++;
} else
break;
}
// check for even length palindromes
for (int j = 0; j <= i; j++) {
if (!s[i + j + 1])
break;
if (s[i - j] == s[i + j + 1]) {
// check for palindromes of length
// greater than 1
if ((i + j + 2) - (i - j) > 1)
m[(i + j + 2) - (i - j)]++;
} else
break;
}
}
return m;
}

Related

c - find palindrome

I'm a newcomer to programming, and I chose C as my first language(been learning it for a month or so).
I've been trying to solve this palindrome question for hours and still couldn't come up with a satisfying solution.
The question is here (from SPOJ), and here's my code:
#include <stdio.h>
#include <string.h>
void plus_one(char *number);
int main(void)
{
char number[1000001];
int i, j, m, k, indicator;
int a;
scanf("%d", &j);
for (i = 0; i < j; i++) {
scanf("%s", number);
k = 1;
while (k != 0) {
plus_one(number);
a = strlen(number);
indicator = 1;
for (m = 0; m < a / 2; m++) {
if (number[m] != number[a - m - 1]) {
indicator = 0;
break;
}
}
if (indicator != 0) {
printf("%s\n", number);
k = 0;
}
}
}
return 0;
}
void plus_one(char *number)
{
int a = strlen(number);
int i;
number[a - 1]++;
for (i = a; i >= 0; i--){
if (number[i - 1] == ':') {
number[i - 1] = '0';
number[i - 2]++;
}
else
break;
}
if (number[0] == '0') {
number[0] = '1';
strcat(number, "0");
}
return;
}
My idea was to examine every number greater than the input until a palindrome is found, and it worked well on my computer. But SPOJ responded "time limit exceeded", so I guess I need to find the next palindrome possible myself instead of using brute force. Can someone please give me a hint about how I can make this go faster? Thanks!
Since you're asking for a hint and not for C code (which I'm notoriously bad at), here's what I would do:
Determine if the number k has an even or odd number of digits, store that in a boolean called odd.
Take the first half of the number k, including the middle digit if odd is true, and store it in a variable called half.
808 -> 80
2133 -> 21
Mirror the half variable, taking care to not duplicate the middle digit if odd is true, and store it in a variable called mirror.
80 -> 808
21 -> 2112
Check if mirror > k
If true: you found your result
If false: increment half and start over from step 3.
(After maximum one increment you're guaranteed to have found your result.)
80 -> 81 -> 818
21 -> 22 -> 2222
Here's a JavaScript implementation for your reference:
const palin = (k) => {
const mirror = (half, odd) => half + Array.from(half).reverse().join('').substring(odd);
const s = k.toString();
const odd = s.length % 2;
const half = s.substring(0, Math.floor(s.length / 2) + odd);
let mirrored = mirror(half, odd);
if (+mirrored <= k) {
mirrored = mirror((+half + 1).toString(), odd);
}
return mirrored;
}
console.log(palin(5));
console.log(palin(808));
console.log(palin(2133));
Welcome to the site. What you have posted is commendable for someone who has only been using C for a month! Anyway ... I think your suspicion is correct. Using 'brute force' to find the next palindrome is probably the not to way go.
This question is as much about algorithm design as about C. Nonetheless, how you handle char[] representations of integers in C is interesting and relevant. FWIW, my attempt is pasted below.
It accepts a char[] representation of the number (n) and the number of digits (k) as arguments, and returns 1 on success or 0 on failure (another pass needed).
static int next_palindrome(char *n, size_t k) {
unsigned i = 0, carry = 0;
char tmp = 0;
int finished = 1;
for (i = 0; i < k; i++) {
if (carry) {
finished = 0;
*(n + k - i - 1) = *(n + k - i - 1) + 1;
if (*(n + k - i - 1) == 10) {
*(n + k - i - 1) = 0;
carry = 1;
} else
carry = 0;
continue;
}
if (i >= k / 2) continue;
if (*(n + k - i - 1) == *(n + i)) continue;
tmp = *(n + k - i - 1);
*(n + k - i - 1) = *(n + i);
if (tmp > *(n + i)) {
carry = 1;
}
}
return finished;
}
I have only tested it on numbers with < 64 digits so far, but have no reason to believe it will fail for larger numbers of digits.
Sample usage: http://codepad.org/3yyI9wEl

Do not know where I'm wrong in the task

For some n, we have to determine number of different strings made only of '0' and '1' in which there is no two adjacent '1'.(Size of string is n) Sorry for my bad english.
This is my attempt:
long Num(int n){
if(n==0)
return 0;
else if(n==1)
return 2;
else if(n==2)
return 3;
else if(n==3)
return 5;
else
return 2*Num(n-2) + Num(n-3);
};
Problem :
To find out the number of possible binary strings of length n, having no consecutive 1's.
Input/Output :
Input: N = 2
Output: 3
// The 3 strings are 00, 01, 10
Input: N = 3
Output: 5
// The 5 strings are 000, 001, 010, 100, 101
Approach :
Let a[i] be the number of binary strings of length i which do not contain any two consecutive 1’s and which end in 0. Similarly, let b[i] be the number of such strings which end in 1. We can append either 0 or 1 to a string ending in 0, but we can only append 0 to a string ending in 1. This yields the recurrence relation:
a[i] = a[i - 1] + b[i - 1]
b[i] = a[i - 1]
The base cases of above recurrence are a[1] = b[1] = 1. The total number of strings of length i is just a[i] + b[i]. While using array i (length of string) will be 1 less, for array's zero position.
Solution :
int countStrings(int n)
{
int a[] = new int [n];
int b[] = new int [n];
a[0] = b[0] = 1;
for (int i = 1; i < n; i++)
{
a[i] = a[i-1] + b[i-1];
b[i] = a[i-1];
}
return a[n-1] + b[n-1];
}
For more details see http://www.geeksforgeeks.org/count-number-binary-strings-without-consecutive-1s/

Maximizing count of distinct numbers that produce a given sum 'k'

I need help with this dynamic programming problem.
Given a positive integer k, find the maximum number of distinct positive integers that sum to k. For example, 6 = 1 + 2 + 3 so the answer would be 3, as opposed to 5 + 1 or 4 + 2 which would be 2.
The first thing I think of is that I have to find a subproblem. So to find the max sum for k, we need to find the max sum for the values less than k. So we have to iterate through the values 1 -> k and find the max sum for those values.
What confuses me is how to make a formula. We can define M(j) as the maximum number of distinct values that sum to j, but how do I actually write the formula for it?
Is my logic for what I have so far correct, and can someone explain how to work through this step by step?
No dynamic programming is need. Let's start with an example:
50 = 50
50 = 1 + 49
50 = 1 + 2 + 47 (three numbers)
50 = 1 + 2 + 3 + 44 (four numbers)
50 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 14 (nine numbers)
Nine numbers is as far as we can go. If we use ten numbers, the sum would be at least 1 + 2 + 3 + ... + 10 = 55, which is greater than 50 - thus it is impossible.
Indeed, if we use exactly n distinct positive integers, then the lowest number with such a sum is 1+2+...+n = n(n+1)/2. By solving the quadratic, we have that M(k) is approximately sqrt(2k).
Thus the algorithm is to take the number k, subtract 1, 2, 3, etc. until we can't anymore, then decrement by 1. Algorithm in C:
int M(int k) {
int i;
for (i = 1; ; i++) {
if (k < i) return i - 1;
else k -= i;
}
}
The other answers correctly deduce that the problem essentially is this summation:
However this can actually be simplified to
In code this looks like : floor(sqrt(2.0 * k + 1.0/4) - 1.0/2)
The disadvantage of this answer is that it requires you to deal with floating point numbers.
Brian M. Scott (https://math.stackexchange.com/users/12042/brian-m-scott), Given a positive integer, find the maximum distinct positive integers that can form its sum, URL (version: 2012-03-22): https://math.stackexchange.com/q/123128
The smallest number that can be represented as the sum of i distinct positive integers is 1 + 2 + 3 + ... + i = i(i+1)/2, otherwise known as the i'th triangular number, T[i].
Let i be such that T[i] is the largest triangular number less than or equal to your k.
Then we can represent k as the sum of i different positive integers:
1 + 2 + 3 + ... + (i-1) + (i + k - T[i])
Note that the last term is greater than or equal to i (and therefore different from the other integers), since k >= T[i].
Also, it's not possible to represent k as the sum of i+1 different positive integers, since the smallest number that's the sum of i+1 different positive integers is T[i+1] > k because of how we chose i.
So your question is equivalent to finding the largest i such that T[i] <= k.
That's solved by this:
i = floor((-1 + sqrt(1 + 8k)) / 2)
[derivation here: https://math.stackexchange.com/questions/1417579/largest-triangular-number-less-than-a-given-natural-number ]
You could also write a simple program to iterate through triangular numbers until you find the first larger than k:
def uniq_sum_count(k):
i = 1
while i * (i+1) <= k * 2:
i += 1
return i - 1
for k in xrange(20):
print k, uniq_sum_count(k)
I think you just check if 1 + ... + n > k. If so, print n-1.
Because if you find the smallest n as 1 + ... + n > k, then 1 + ... + (n-1) <= k. so add the extra value, say E, to (n-1), then 1 + ... + (n-1+E) = k.
Hence n-1 is the maximum.
Note that : 1 + ... + n = n(n+1) / 2
#include <stdio.h>
int main()
{
int k, n;
printf(">> ");
scanf("%d", &k);
for (n = 1; ; n++)
if (n * (n + 1) / 2 > k)
break;
printf("the maximum: %d\n", n-1);
}
Or you can make M(j).
int M(int j)
{
int n;
for (n = 1; ; n++)
if (n * (n + 1) / 2 > j)
return n-1; // return the maximum.
}
Well the problem might be solved without dynamic programming however i tried to look at it in dynamic programming way.
Tip: when you wanna solve a dynamic programming problem you should see when situation is "repetitive". Here, since from the viewpoint of the number k it does not matter if, for example, I subtract 1 first and then 3 or first 3 and then 1; I say that "let's subtract from it in ascending order".
Now, what is repeated? Ok, the idea is that I want to start with number k and subtract it from distinct elements until I get to zero. So, if I reach to a situation where the remaining number and the last distinct number that I have used are the same the situation is "repeated":
#include <stdio.h>
bool marked[][];
int memo[][];
int rec(int rem, int last_distinct){
if(marked[rem][last_distinct] == true) return memo[rem][last_distinct]; //don't compute it again
if(rem == 0) return 0; //success
if(rem > 0 && last > rem - 1) return -100000000000; //failure (minus infinity)
int ans = 0;
for(i = last_distinct + 1; i <= rem; i++){
int res = 1 + rec(rem - i, i); // I've just used one more distinct number
if(res > ans) ans = res;
}
marked[rem][last_distinct] = true;
memo[rem][last_distinct] = res;
return res;
}
int main(){
cout << rec(k, 0) << endl;
return 0;
}
The time complexity is O(k^3)
Though it isn't entirely clear what constraints there may be on how you arrive at your largest discrete series of numbers, but if you are able, passing a simple array to hold the discrete numbers, and keeping a running sum in your functions can simplify the process. For example, passing the array a long with your current j to the function and returning the number of elements that make up the sum within the array can be done with something like this:
int largest_discrete_sum (int *a, int j)
{
int n, sum = 0;
for (n = 1;; n++) {
a[n-1] = n, sum += n;
if (n * (n + 1) / 2 > j)
break;
}
a[sum - j - 1] = 0; /* zero the index holding excess */
return n;
}
Putting it together in a short test program would look like:
#include <stdio.h>
int largest_discrete_sum(int *a, int j);
int main (void) {
int i, idx = 0, v = 50;
int a[v];
idx = largest_discrete_sum (a, v);
printf ("\n largest_discrete_sum '%d'\n\n", v);
for (i = 0; i < idx; i++)
if (a[i])
printf (!i ? " %2d" : " +%2d", a[i]);
printf (" = %d\n\n", v);
return 0;
}
int largest_discrete_sum (int *a, int j)
{
int n, sum = 0;
for (n = 1;; n++) {
a[n-1] = n, sum += n;
if (n * (n + 1) / 2 > j)
break;
}
a[sum - j - 1] = 0; /* zero the index holding excess */
return n;
}
Example Use/Output
$ ./bin/largest_discrete_sum
largest_discrete_sum '50'
1 + 2 + 3 + 4 + 6 + 7 + 8 + 9 +10 = 50
I apologize if I missed a constraint on the discrete values selection somewhere, but approaching in this manner you are guaranteed to obtain the largest number of discrete values that will equal your sum. Let me know if you have any questions.

Split C array into n equal parts

I am trying to split an array into n equal parts by calculating start and end indices. The address of the start and end elements will be passed into a function that will sort these arrays. For example, if arraySize = 1000, and n=2, the indices will be 0, 499, 999. So far I have the below code but for odd n, it is splitting it into more than n arrays. Another way I thought of doing this is by running through the loop n times, but I'm not sure where to start.
int chunkSize = arraySize / numThreads;
for (int start = 0; start < arraySize; start += chunkSize) {
int end = start + chunkSize - 1;
if (end > arraySize - 1) {
end = arraySize - 1;
}
InsertionSort(&array[start], end - start + 1);
}
EDIT: Here's something else I came up with. It seems to be working, but I need to do some more thorough testing. I've drawn this out multiple times and traced it by hand. Hopefully, there aren't any edge cases that will fail. I am already restricting n >= arraySize.
int chunkSize = arraySize / numThreads;
for (int i = 0; i < numThreads; i++) {
int start = i * chunkSize;
int end = start + chunkSize - 1;
if (i == numThreads - 1) {
end = arraySize - 1;
}
for (int i = start; i <= end; i++) {
printf("%d ", array[i]);
}
printf("\n");
}
Calculate the minimum chunk size with the truncating division. Then calculate the remainder. Distribute this remainder by adding 1 to some chunks:
Pseudo-code:
chunk_size = array_size / N
bonus = array_size - chunk_size * N // i.e. remainder
for (start = 0, end = chunk_size;
start < array_size;
start = end, end = start + chunk_size)
{
if (bonus) {
end++;
bonus--;
}
/* do something with array slice over [start, end) interval */
}
For instance if array_size is 11 and N == 4, 11/N yields 2. The remainder ("bonus") is 3: 11 - 2*3. Thus the first three iterations of the loop will add 1 to the size: 3 3 3. The bonus then hits zero and the last chunk size will just be 2.
What we are doing here is nothing more than distributing an error term in a discrete quantization, in a way that is satisfactory somehow. This is exactly what happens when a line segment is drawn on a raster display with the Bresenham algorithm, or when an image is reduced to a smaller number of colors using Floyd-Steinberg dithering, et cetera.
You need to calculate your chunk size so that it is "rounded up", not down. You could do it using % operator and a more complex formula, but just using simple if is probably easier to understand:
int chunkSize = arraySize / numThreads;
if (chunkSize * numThreads < arraySize) {
// In case arraySize is not exactly divisible by numThreads,
// we now end up with one extra smaller chunk at the end.
// Fix this by increseing chunkSize by one byte,
// so we'll end up with numThread chunks and smaller last chunk.
++chunkSize;
}
I hope this would help:
int chunkSize = arraySize / numThreads;
for (int i = 0; i < numThreads-1; i++) {
start = i* chunkSize;
end = start + chunkSize - 1;
InsertionSort(&array[start], end + 1);
}
//Last chunk with all the remaining content
start = end + 1;
end = arraySize - 1;
InsertionSort(&array[start], end + 1);

Combinations based on 2 variables

What I'm trying to accomplish is making a function to the following:
Imagine that I have between 1-9 squares. Those squares have a number assigned to them globally, not individually. They are like a set, and that set has this number.
E.g.: | _ | _ | _ | 19
What I'm trying to do is a function that gives me the possible combinations depending on number of squares and the number associated with them. For the example above: 9, 8, 2 is one of the possible combinations. However I just want the numbers that are in those combinations, not the combinations themselves. Plus they have to be unique (shouldn't be 9, 9, 1). Oh and those numbers range from 1-9 only.
How can I achieve this in C? If you are wondering this is for a puzzle game.
Thanks in advance!
Looks like you are trying to find a restricted Partition of the integer on the right. The link should give you a good starting place, and you should be able to find some algorithms that generate partitions of an integer into an arbitrary number of parts.
For future reference, in combinatorics we say "order doesn't matter" to mean "I only want the set of numbers, not a specific ordering"
//Sets the given digit array to contain the "first" set of numbers which sum to sum
void firstCombination(int digits[], int numDigits, int sum) {
reset(digits, 0, 1, numDigits, sum);
}
//Modifies the digit array to contain the "next" set of numbers with the same sum.
//Returns false when no more combinations left
int nextCombination(int digits[], int numDigits) {
int i;
int foundDiffering = 0;
int remaining = 0;
for (i = numDigits - 1; i > 0; i--) {
remaining += digits[i];
if (digits[i] - digits[i - 1] > 1) {
if (foundDiffering || digits[i] - digits[i - 1] > 2) {
digits[i - 1]++;
remaining--;
break;
} else
foundDiffering = 1;
}
}
if (i == 0)
return 0;
else {
reset(digits, i, digits[i - 1] + 1, numDigits - i, remaining);
return 1;
}
}
//Helper method for firstCombination and nextCombination
void reset(int digits[], int off, int lowestValue, int numDigits, int sum) {
int i;
int remaining = sum;
for (i = 0; i < numDigits; i++) {
digits[i + off] = lowestValue;
remaining -= lowestValue;
lowestValue++;
}
int currentDigit = 9;
for (i = numDigits + off - 1; i >= off; i--) {
if (remaining >= currentDigit - digits[i]) {
remaining -= currentDigit - digits[i];
digits[i] = currentDigit;
currentDigit--;
} else {
digits[i] += remaining;
break;
}
}
}
It sounds like what you're working on is very similar to kakuro, also know as Cross Sums: http://en.wikipedia.org/wiki/Cross_Sums
There are generators out there for these kinds of puzzles, for example: http://www.perlmonks.org/?node_id=550884
I suspect that most kakuro generators would have to solve your exact problem, so you might look at some for inspiration.

Resources