How a for loop works without printing - c++

I've seen someone post this same for loop, but my problem is slightly different. Wouldn't the variable temp be changed on each iteration, so just leaving one character that keeps getting changed? How are the characters stored? Also, how does the loop know that rand() won't generate the same number for both index1 and index2? Sorry if this isn't so clear, i'm a bit of a newbie!
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
int main()
{
enum { WORD, HINT, NUM_FIELDS };
const int NUM_WORDS = 3;
const std::string WORDS[NUM_WORDS][NUM_FIELDS] = {
{ "Redfield", "Main Resident Evil character" },
{ "Valentine", "Will you be mine?" },
{ "Jumbled", "These words are..." }
};
srand(static_cast<unsigned int>(time(0)));
int choice = (rand() % NUM_WORDS);
std::string theWord = WORDS[choice][WORD];
std::string theHint = WORDS[choice][HINT];
std::string jumble = theWord;
int length = jumble.size();
for (int i = 0; i < length; ++i) {
int index1 = (rand() % length);
int index2 = (rand() % length);
char temp = jumble[index1];
jumble[index1] = jumble[index2];
jumble[index2] = temp;
}
std::cout << jumble << '\n'; // Why 'jumbled word' instead of just a character?
std::cin.get();
}

Wouldn't the variable temp be changed on each iteration, so just leaving one character that keeps getting changed?
It depends. Notice that you're trying to come up with a new random index1 and a new random index2 in each iteration. What happens if your jumble variable is Redfield, and index1 = 1 and index2 = 5? You would be swapping two e's.
But because in every iteration you're trying to access chars in a random position of your jumble string on positions index1 and index2:
int index1 = (rand() % length);
int index2 = (rand() % length);
The value of those indexes are unpredictable on each iteration. It could happen that you get a 1 and a 5 again.
Nevertheless, remember that you're creating a variable tempin every iteration, thereby you wouldn't be changing its value, you would be assigning a new variable in each iteration.
How are the characters stored?
I'm not sure what do you mean here, but every char is stored within 1 byte. Therefore, a string would be a sequence of bytes (char). This sequence is a contiguous block of memory. Every time you're accessing jumble[index1], you're accessing the char on position index1 within your string jumble.
If jumble = "Valentine" and index1 = 1, then you will be accessing an a, because your V is on position 0.
Also, how does the loop know that rand() won't generate the same number for both index1 and index2?
It doesn't. You would have to come up with a strategy to ensure that this doesn't happen. One approach, but not an efficient one, would be:
int index1 = (rand() % length);
int index2 = (rand() % length);
while (index1 == index2) {
index1 = (rand() % length);
index2 = (rand() % length);
}

Related

How to give conditions to Rand()

First time on stack overflow.
I have this assignment due for class where we have a guessing game where our program has to generate a string of Uppercase letters of n length and n different defined by the user. I got most of my assignment working but when generate the string I am lost with how I could put these conditions in place for it to work.
char create_sequence(){
return rand() % 26 + 65;
}
Do you have any tips?
If you know sequence length, you don't need amount of different characters. This is because you require length <= characters.
To create sequence of n unique characters write a separate function:
vector<char> create_sequence(int n) {
vector<char> letters;
for (char ch = 'A'; ch <= 'Z'; ++ch) {
letters.push_back(ch);
}
vector<char> sequence;
for (int i = 0; i < n; ++i) {
int index = rand() % letters.size();
sequence.push_back(letters[index]);
letters.erase(letters.begin() + index, letters.begin() + index + 1);
}
return sequence;
}
Well, personally I think you are not far from the answer:
rand() % 26 + 65
Will effectively returns an uppercase ASCII letter. As long as you initialize the random seed once srand (time(NULL));, you can then call your instruction as many times as you want to get random values. So all you miss is a simple loop. Here is an example for 5 characters:
#include <iostream>
#include <string>
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
char randomChar(){
return rand() % 26 + 65;
}
std::string randomString(int length)
{
srand (time(NULL));
std::string rc("");
for(int i=0; i<length; ++i)
{
rc += randomChar();
}
return rc;
}
int main()
{
std::cout << "Random string (x5) is " << randomString(5) << "\n";
}

Need help understanding a word jumble for loop

This code is part of a program that jumbles a word. I need help understanding how the for loop is working and creating the jumbled word. For example if theWord = "apple" the output would be something like: plpea. So I want to know whats going on in the for loop to make this output.
std::string jumble = theWord;
int length = theWord.size();
for (int i = 0; i < length; i++)
{
int index1 = (rand() % length);
int index2 = (rand() % length);
char temp = jumble[index1];
jumble[index1] = jumble[index2];
jumble[index2] = temp;
}
std::cout << jumble << std::endl;
I'll add comments on each line of the for loop:
for (int i = 0; i < length; i++) // basic for loop syntax. It will execute the same number of times as there are characters in the string
{
int index1 = (rand() % length); // get a random index that is 0 to the length of the string
int index2 = (rand() % length); // Does the same thing, gets a random index
char temp = jumble[index1]; // Gets the character at the random index
jumble[index1] = jumble[index2]; // set the value at the first index to the value at the second
jumble[index2] = temp; // set the value at the second index to the vaue of the first
// The last three lines switch two characters
}
You can think of it like this: For each character in the string, switch two characters in the string.
Also the % (or the modulus operator) just gets the remainder Understanding The Modulus Operator %
It's also important to understand that myString[index] will return whatever character is at that index. Ex: "Hello world"[1] == "e"

Generate (not so)random string with particular string occurences

I have a requirement where I have the alphabet 'ACGT' and I need to create a string of around 20,000 characters. This string should contain 100+ occurrences of the pattern "CCGT". Most of the time the generated string contains it around 20-30 instances.
int N = 20000;
std::string alphabet("ACGT");
std::string str;
str.reserve(N);
for (int index = 0; index < N; index++)
{
str += alphabet[rand() % (alphabet.length())];
}
How do I tweak the code so that the pattern would appear more often?
Edit - Is there a way of changing the alphabet, i.e - 'A', 'C', 'G', 'T', 'CCGT' as characters of the alphabet?
Thank you.
Generate an array of ints containing 100 x 0s and 490 1s, 2s, 3s and 4s
[000000....111111....2222 etc] making almost 20,000 entries.
Then random shuffle it (std::random_shuffle)
Then write a string where each 0 translates to 'CCGT', each 1 translates to 'A', each 2 .... etc
I think that gives you what you want, and by tweaking the original array of ints you could change the number of 'A' characters in the output too.
Edit: If that isn't random enough, do 100 0s at the start and then random 1-4 for the rest.
The only solution I can think of that would meet the "100+" criteria is:
create 20000 character string
number of instances (call it n) = 100 + some random value
for (i = 0 ; i < n ; ++i)
{
pick random start position
write CCGT
}
Of course, you'd need to ensure the overwritten characters weren't part of a "CCGT" already.
My first thought would be to generate a list of 100 indexes where you will definitely insert the special string. Then as you generate the random string, insert the special string at each of these indexes as you reach them.
I've missed out checking that the intervals are spaced appropriately (cannot be within 4 of another interval) and also sorting them in ascending order - both of which would be necessary for this to work.
int N = 20000;
std::string alphabet("ACGT");
int intervals[100];
for (int index = 0; index < 100; index)
{
intervals[index] = rand() % 2000;
// Do some sort of check to make sure each element of intervals is not
// within 4 of another element and that no elements are repeated
}
// Sort the intervals array in ascending order
int current_interval_index = 0;
std::string str;
str.reserve(N);
for (int index = 0; index < N; index++)
{
if (index == intervals[current_interval_index])
{
str += alphabet;
current_interval_index++;
index += 3;
}
else
{
str += alphabet[rand() % (alphabet.length())];
}
}
The solution I came up with uses a std::vector to contain all the random sets of 4 chars including the 100 special sequence. I then shuffle that vector to distribute the 100 special sequence randomly throughout the string.
To make the distribution of letters even I create an alternative alphabet string called weighted that contains a relative abundance of alphabet characters according to what has already been included from the 100 special sequence.
int main()
{
std::srand(std::time(0));
using std::size_t;
const size_t N = 20000;
std::string alphabet("ACGT");
// stuff the ballot
std::vector<std::string> v(100, "CCGT");
// build a properly weighted alphabet string
// to give each letter equal chance of appearing
// in the final string
std::string weighted;
// This could be scaled down to make the weighted string much smaller
for(size_t i = 0; i < (N - 200) / 4; ++i) // already have 200 Cs
weighted += "C";
for(size_t i = 0; i < (N - 100) / 4; ++i) // already have 100 Ns & Gs
weighted += "GT";
for(size_t i = 0; i < N / 4; ++i)
weighted += "A";
size_t remaining = N - (v.size() * 4);
// add the remaining characters to the weighted string
std::string s;
for(size_t i = 0; i < remaining; ++i)
s += weighted[std::rand() % weighted.size()];
// add the random "4 char" sequences to the vector so
// we can randomly distribute the pre-loaded special "4 char"
// sequence among them.
for(std::size_t i = 0; i < s.size(); i += 4)
v.push_back(s.substr(i, 4));
// distribute the "4 char" sequences randomly
std::random_shuffle(v.begin(), v.end());
// rebuild string s from vector
s.clear();
for(auto&& seq: v)
s += seq;
std::cout << s.size() << '\n'; // should be N
}
I like the answer by #Andy Newman and think that is probably the best way - the code below is a compilable example of what they suggested.
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
srand(time(0));
int N = 20000;
std::string alphabet("ACGT");
std::string str;
str.reserve(N);
int int_array[19700];
// Populate int array
for (int index = 0; index < 19700; index++)
{
if (index < 100)
{
int_array[index] = 0;
}
else
{
int_array[index] = (rand() % 4) + 1;
}
}
// Want the array in a random order
std::random_shuffle(&int_array[0], &int_array[19700]);
// Now populate string from the int array
for (int index = 0; index < 19700; index++)
{
switch(int_array[index])
{
case 0:
str += alphabet;
break;
case 1:
str += 'A';
break;
case 2:
str += 'C';
break;
case 3:
str += 'G';
break;
case 4:
str += 'T';
break;
default:
break;
}
}
// Print out to check what it looks like
std::cout << str << std::endl;
}
You should make N larger.
I take this liberty because you say 'create a string of around 20,000 characters'; but there's more to it than that.
If you're only finding around 20-30 instances in a string of 20000 characters then something is wrong. A ballpark estimate is to say that there are 20000 character positions to test, and at each of these there will be a four-letter string from an alphabet of four letters, giving a 1/256 chance of it being a specific string. The average should be (approximately; because I've oversimplified) 20000/256, or 78 hits.
It could be that your string isn't properly randomised (likely due to the use of the modulo idiom), or perhaps you're testing only every fourth character position -- as if the string were a list of non-overlapping four-letter words.
If you can bring your average hit rate back up to 78, then you can reach a little further to your 100 requirement simply by increasing N proportionally.

To find the longest substring with equal sum in left and right in C++

I was solving a question, with which I am having some problems:
Complete the function getEqualSumSubstring, which takes a single argument. The single argument is a string s, which contains only non-zero digits.
This function should print the length of longest contiguous substring of s, such that the length of the substring is 2*N digits and the sum of the leftmost N digits is equal to the sum of the rightmost N digits. If there is no such string, your function should print 0.
int getEqualSumSubstring(string s) {
int i=0,j=i,foundLength=0;
for(i=0;i<s.length();i++)
{
for(j=i;j<s.length();j++)
{
int temp = j-i;
if(temp%2==0)
{
int leftSum=0,rightSum=0;
string tempString=s.substr(i,temp);
for(int k=0;k<temp/2;k++)
{
leftSum=leftSum+tempString[k]-'0';
rightSum=rightSum+tempString[k+(temp/2)]-'0';
}
if((leftSum==rightSum)&&(leftSum!=0))
if(s.length()>foundLength)
foundLength=s.length();
}
}
}
return(foundLength);
}
The problem is that this code is working for some samples and not for the others. Since this is an exam type question I don't have the test cases either.
This code works
int getEqualSumSubstring(string s) {
int i=0,j=i,foundLength=0;
for(i=0;i<s.length();i++)
{
for(j=i;j<s.length();j++)
{
int temp = j-i+1;
if(temp%2==0)
{
int leftSum=0,rightSum=0;
string tempString=s.substr(i,temp);
// printf("%d ",tempString.length());
for(int k=0;k<temp/2;k++)
{
leftSum=leftSum+tempString[k]-48;
rightSum=rightSum+tempString[k+(temp/2)]-48;
}
if((leftSum==rightSum)&&(leftSum!=0))
if(tempString.length()>foundLength)
foundLength=tempString.length();
}
}
}
return(foundLength);
}
The temp variable must be j-i+1. Otherwise the case where the whole string is the answer will not be covered. Also, we need to make the change suggested by Scott.
Here's my solution that I can confirm works. The ones above didn't really work for me - they gave me compile errors somehow. I got the same question on InterviewStreet, came up with a bad, incomplete solution that worked for 9/15 of the test cases, so I had to spend some more time coding afterwards.
The idea is that instead of caring about getting the left and right sums (which is what I initially did as well), I will get all the possible substrings out of each half (left and right half) of the given input, sort and append them to two separate lists, and then see if there are any matches.
Why?
Say the strings "423" and "234" have the same sum; if I sorted them, they would both be "234" and thus match. Since these numbers have to be consecutive and equal length, I no longer need to worry about having to add them up as numbers and check.
So, for example, if I'm given 12345678, then on the left side, the for-loop will give me:
[1,12,123,1234,2,23,234,3,34]
And on the right:
[5,56,567,5678,...]
And so forth.
However, I'm only taking substrings of a length of at least 2 into account.
I append each of these substrings, sorted by converting into a character array then converting back into a string, into ArrayLists.
So now that all this is done, the next step is to see if there are identical strings of the same numbers in these two ArrayLists. I simply check each of temp_b's strings against temp_a's first string, then against temp_a's second string, and so forth.
If I get a match (say, "234" and "234"), I'll set the length of those matching substrings as my tempCount (tempCount = 3). I also have another variable called 'count' to keep track of the greatest length of these matching substrings (if this was the first occurrence of a match, then count = 0 is overwritten by tempCount = 3, so count = 3).
As for the odd/even string length with the variable int end, the reason for this is because in the line of code s.length()/2+j, is the length of the input happened to be 11, then:
s.length() = 11
s.length()/2 = 11/5 = 5.5 = 5
So in the for-loop, s.length()/2 + j, where j maxes out at s.length()/2, would become:
5 + 5 = 10
Which falls short of the s.length() that I need to reach for to get the string's last index.
This is because the substring function requires an end index of one greater than what you'd put for something like charAt(i).
Just to demonstrate, an input of "47582139875" will generate the following output:
[47, 457, 4578, 24578, 57, 578, 2578, 58, 258, 28] <-- substrings from left half
[139, 1389, 13789, 135789, 389, 3789, 35789, 789, 5789, 578] <-- substrings from right half
578 <-- the longest one that matched
6 <-- the length of '578' x 2
public static int getEqualSumSubtring(String s){
// run through all possible length combinations of the number string on left and right half
// append sorted versions of these into new ArrayList
ArrayList<String> temp_a = new ArrayList<String>();
ArrayList<String> temp_b = new ArrayList<String>();
int end; // s.length()/2 is an integer that rounds down if length is odd, account for this later
for( int i=0; i<=s.length()/2; i++ ){
for( int j=i; j<=s.length()/2; j++ ){
// only account for substrings with a length of 2 or greater
if( j-i > 1 ){
char[] tempArr1 = s.substring(i,j).toCharArray();
Arrays.sort(tempArr1);
String sorted1 = new String(tempArr1);
temp_a.add(sorted1);
//System.out.println(sorted1);
if( s.length() % 2 == 0 )
end = s.length()/2+j;
else // odd length so we need the extra +1 at the end
end = s.length()/2+j+1;
char[] tempArr2 = s.substring(i+s.length()/2, end).toCharArray();
Arrays.sort(tempArr2);
String sorted2 = new String(tempArr2);
temp_b.add(sorted2);
//System.out.println(sorted2);
}
}
}
// For reference
System.out.println(temp_a);
System.out.println(temp_b);
// If the substrings match, it means they have the same sum
// Keep track of longest substring
int tempCount = 0 ;
int count = 0;
String longestSubstring = "";
for( int i=0; i<temp_a.size(); i++){
for( int j=0; j<temp_b.size(); j++ ){
if( temp_a.get(i).equals(temp_b.get(j)) ){
tempCount = temp_a.get(i).length();
if( tempCount > count ){
count = tempCount;
longestSubstring = temp_a.get(i);
}
}
}
}
System.out.println(longestSubstring);
return count*2;
}
Heres my solution to this question including tests. I've added an extra function just because I feel it makes the solution way easier to read than the solutions above.
#include <string>
#include <iostream>
using namespace std;
int getMaxLenSumSubstring( string s )
{
int N = 0; // The optimal so far...
int leftSum = 0, rightSum=0, strLen=s.size();
int left, right;
for(int i=0;i<strLen/2+1;i++) {
left=(s[i]-int('0')); right=(s[strLen-i-1]-int('0'));
leftSum+=left; rightSum+=right;
if(leftSum==rightSum) N=i+1;
}
return N*2;
}
int getEqualSumSubstring( string s ) {
int maxLen = 0, substrLen, j=1;
for( int i=0;i<s.length();i++ ) {
for( int j=1; j<s.length()-i; j++ ) {
//cout<<"Substring = "<<s.substr(i,j);
substrLen = getMaxLenSumSubstring(s.substr(i,j));
//cout<<", Len ="<<substrLen;
if(substrLen>maxLen) maxLen=substrLen;
}
}
return maxLen;
}
Here are a few tests I ran. Based upon the examples above they seem right.
int main() {
cout<<endl<<"Test 1 :"<<getEqualSumSubstring(string("123231"))<<endl;
cout<<endl<<"Test 2 :"<<getEqualSumSubstring(string("986561517416921217551395112859219257312"))<<endl;
cout<<endl<<"Test 3:"<<getEqualSumSubstring(string("47582139875"))<<endl;
}
Shouldn't the following code use tempString.length() instead of s.length()
if((leftSum==rightSum)&&(leftSum!=0))
if(s.length()>foundLength)
foundLength=s.length();
Below is my code for the question... Thanks !!
public class IntCompl {
public String getEqualSumSubstring_com(String s)
{
int j;
int num=0;
int sum = 0;
int m=s.length();
//calculate String array Length
for (int i=m;i>1;i--)
{
sum = sum + m;
m=m-1;
}
String [] d = new String[sum];
int k=0;
String ans = "NULL";
//Extract strings
for (int i=0;i<s.length()-1;i++)
{
for (j=s.length();j>=i+1;k++,j--)
{
num = k;
d[k] = s.substring(i,j);
}
k=num+1;
}
//Sort strings in such a way that the longest strings precede...
for (int i=0; i<d.length-1; i++)
{
for (int h=1;h<d.length;h++)
{
if (d[i].length() > d[h].length())
{
String temp;
temp=d[i];
d[i]=d[h];
d[h]=temp;
}
}
}
// Look for the Strings with array size 2*N (length in even number) and such that the
//the sum of left N numbers is = to the sum of right N numbers.
//As the strings are already in decending order, longest string is searched first and break the for loop once the string is found.
for (int x=0;x<d.length;x++)
{
int sum1=0,sum2=0;
if (d[x].length()%2==0 && d[x].length()<49)
{
int n;
n = d[x].length()/2;
for (int y=0;y<n;y++)
{
sum1 = sum1 + d[x].charAt(y)-'0';
}
for (int y=n;y<d[x].length();y++)
{
sum2 = sum2 + d[x].charAt(y)-'0';
}
if (sum1==sum2)
{
ans = d[x];
break;
}
}
}
return ans;
}
}
Here is the complete Java Program for this question.
Complexity is O(n^3)
This can however be solved in O(n^2).For O(n^2) complexity solution refer to this link
import java.util.Scanner;
import static java.lang.System.out;
public class SubStringProblem{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
out.println("Enter the Digit String:");
String s = sc.nextLine();
int n = (new SubStringProblem()).getEqualSumSubString(s);
out.println("The longest Sum SubString is "+n);
}
public int getEqualSumSubString(String s){
int N;
if(s.length()%2==0)
{
//String is even
N = s.length();
}
else{
//String is odd
N=s.length()-1;
}
boolean flag =false;
int sum1,sum2;
do{
for(int k=0;k<=s.length()-N;k++){
sum1=0;
sum2=0;
for(int i =k,j=k+N-1;i<j;i++,j--)
{
sum1=sum1 + Integer.parseInt(s.substring(i,i+1));
sum2+=Integer.parseInt(s.substring(j,j+1));
}
if(sum1==sum2){
return N;
}
}
N-=2;
flag =true;
}while(N>1);
return -1;
}
}
What is your rationale for the number 48 on these two lines?
for(int k=0;k<temp/2;k++)
{
leftSum=leftSum+tempString[k]-48;
rightSum=rightSum+tempString[k+(temp/2)]-48;
}
I am just overly curious and would like to hear the reasoning behind it, because I have a similar solution, but without the 48 and it still works. However, I added the 48 an still got the correct answer.
Simple solution. O(n*n). s - input string.
var longest = 0;
for (var i = 0; i < s.length-1; i++) {
var leftSum = rightSum = 0;
for (var j = i, k = i+1, l = 2; j >=0 && k < s.length; j--, k++, l+=2) {
leftSum += parseInt(s[j]);
rightSum += parseInt(s[k]);
if (leftSum == rightSum && l > longest) {
longest = l;
}
}
}
console.log(longest);

How many palindromes can be formed by selections of characters from a string?

I'm posting this on behalf of a friend since I believe this is pretty interesting:
Take the string "abb". By leaving out
any number of letters less than the
length of the string we end up with 7
strings.
a b b ab ab bb abb
Out of these 4 are palindromes.
Similarly for the string
"hihellolookhavealookatthispalindromexxqwertyuiopasdfghjklzxcvbnmmnbvcxzlkjhgfdsapoiuytrewqxxsoundsfamiliardoesit"
(a length 112 string) 2^112 - 1
strings can be formed.
Out of these how many are
palindromes??
Below there is his implementation (in C++, C is fine too though). It's pretty slow with very long words; he wants to know what's the fastest algorithm possible for this (and I'm curious too :D).
#include <iostream>
#include <cstring>
using namespace std;
void find_palindrome(const char* str, const char* max, long& count)
{
for(const char* begin = str; begin < max; begin++) {
count++;
const char* end = strchr(begin + 1, *begin);
while(end != NULL) {
count++;
find_palindrome(begin + 1, end, count);
end = strchr(end + 1, *begin);
}
}
}
int main(int argc, char *argv[])
{
const char* s = "hihellolookhavealookatthis";
long count = 0;
find_palindrome(s, strlen(s) + s, count);
cout << count << endl;
}
First of all, your friend's solution seems to have a bug since strchr can search past max. Even if you fix this, the solution is exponential in time.
For a faster solution, you can use dynamic programming to solve this in O(n^3) time. This will require O(n^2) additional memory. Note that for long strings, even 64-bit ints as I have used here will not be enough to hold the solution.
#define MAX_SIZE 1000
long long numFound[MAX_SIZE][MAX_SIZE]; //intermediate results, indexed by [startPosition][endPosition]
long long countPalindromes(const char *str) {
int len = strlen(str);
for (int startPos=0; startPos<=len; startPos++)
for (int endPos=0; endPos<=len; endPos++)
numFound[startPos][endPos] = 0;
for (int spanSize=1; spanSize<=len; spanSize++) {
for (int startPos=0; startPos<=len-spanSize; startPos++) {
int endPos = startPos + spanSize;
long long count = numFound[startPos+1][endPos]; //if str[startPos] is not in the palindrome, this will be the count
char ch = str[startPos];
//if str[startPos] is in the palindrome, choose a matching character for the palindrome end
for (int searchPos=startPos; searchPos<endPos; searchPos++) {
if (str[searchPos] == ch)
count += 1 + numFound[startPos+1][searchPos];
}
numFound[startPos][endPos] = count;
}
}
return numFound[0][len];
}
Explanation:
The array numFound[startPos][endPos] will hold the number of palindromes contained in the substring with indexes startPos to endPos.
We go over all pairs of indexes (startPos, endPos), starting from short spans and moving to longer ones. For each such pair, there are two options:
The character at str[startPos] is not in the palindrome. In that case, there are numFound[startPos+1][endPos] possible palindromes - a number that we have calculated already.
character at str[startPos] is in the palindrome (at its beginning). We scan through the string to find a matching character to put at the end of the palindrome. For each such character, we use the already-calculated results in numFound to find number of possibilities for the inner palindrome.
EDIT:
Clarification: when I say "number of palindromes contained in a string", this includes non-contiguous substrings. For example, the palindrome "aba" is contained in "abca".
It's possible to reduce memory usage to O(n) by taking advantage of the fact that calculation of numFound[startPos][x] only requires knowledge of numFound[startPos+1][y] for all y. I won't do this here since it complicates the code a bit.
Pregenerating lists of indices containing each letter can make the inner loop faster, but it will still be O(n^3) overall.
I have a way can do it in O(N^2) time and O(1) space, however I think there must be other better ways.
the basic idea was the long palindrome must contain small palindromes, so we only search for the minimal match, which means two kinds of situation: "aa", "aba". If we found either , then expand to see if it's a part of a long palindrome.
int count_palindromic_slices(const string &S) {
int count = 0;
for (int position=0; position<S.length(); position++) {
int offset = 0;
// Check the "aa" situation
while((position-offset>=0) && (position+offset+1)<S.length() && (S.at(position-offset))==(S.at(position+offset+1))) {
count ++;
offset ++;
}
offset = 1; // reset it for the odd length checking
// Check the string for "aba" situation
while((position-offset>=0) && position+offset<S.length() && (S.at(position-offset))==(S.at(position+offset))) {
count ++;
offset ++;
}
}
return count;
}
June 14th, 2012
After some investigation, I believe this is the best way to do it.
faster than the accepted answer.
Is there any mileage in making an initial traversal and building an index of all occurances of each character.
h = { 0, 2, 27}
i = { 1, 30 }
etc.
Now working from the left, h, only possible palidromes are at 3 and 17, does char[0 + 1] == char [3 -1] etc. got a palindrome. does char [0+1] == char [27 -1] no, No further analysis of char[0] needed.
Move on to char[1], only need to example char[30 -1] and inwards.
Then can probably get smart, when you've identified a palindrome running from position x->y, all inner subsets are known palindromes, hence we've dealt with some items, can eliminate those cases from later examination.
My solution using O(n) memory and O(n^2) time, where n is the string length:
palindrome.c:
#include <stdio.h>
#include <string.h>
typedef unsigned long long ull;
ull countPalindromesHelper (const char* str, const size_t len, const size_t begin, const size_t end, const ull count) {
if (begin <= 0 || end >= len) {
return count;
}
const char pred = str [begin - 1];
const char succ = str [end];
if (pred == succ) {
const ull newCount = count == 0 ? 1 : count * 2;
return countPalindromesHelper (str, len, begin - 1, end + 1, newCount);
}
return count;
}
ull countPalindromes (const char* str) {
ull count = 0;
size_t len = strlen (str);
size_t i;
for (i = 0; i < len; ++i) {
count += countPalindromesHelper (str, len, i, i, 0); // even length palindromes
count += countPalindromesHelper (str, len, i, i + 1, 1); // odd length palindromes
}
return count;
}
int main (int argc, char* argv[]) {
if (argc < 2) {
return 0;
}
const char* str = argv [1];
ull count = countPalindromes (str);
printf ("%llu\n", count);
return 0;
}
Usage:
$ gcc palindrome.c -o palindrome
$ ./palindrome myteststring
EDIT: I misread the problem as the contiguous substring version of the problem. Now given that one wants to find the palindrome count for the non-contiguous version, I strongly suspect that one could just use a math equation to solve it given the number of distinct characters and their respective character counts.
Hmmmmm, I think I would count up like this:
Each character is a palindrome on it's own (minus repeated characters).
Each pair of the same character.
Each pair of the same character, with all palindromes sandwiched in the middle that can be made from the string between repeats.
Apply recursively.
Which seems to be what you're doing, although I'm not sure you don't double-count the edge cases with repeated characters.
So, basically, I can't think of a better way.
EDIT:
Thinking some more,
It can be improved with caching, because you sometimes count the palindromes in the same sub-string more than once. So, I suppose this demonstrates that there is definitely a better way.
Here is a program for finding all the possible palindromes in a string written in both Java and C++.
int main()
{
string palindrome;
cout << "Enter a String to check if it is a Palindrome";
cin >> palindrome;
int length = palindrome.length();
cout << "the length of the string is " << length << endl;
int end = length - 1;
int start = 0;
int check=1;
while (end >= start) {
if (palindrome[start] != palindrome[end]) {
cout << "The string is not a palindrome";
check=0;
break;
}
else
{
start++;
end--;
}
}
if(check)
cout << "The string is a Palindrome" << endl;
}
public String[] findPalindromes(String source) {
Set<String> palindromes = new HashSet<String>();
int count = 0;
for(int i=0; i<source.length()-1; i++) {
for(int j= i+1; j<source.length(); j++) {
String palindromeCandidate = new String(source.substring(i, j+1));
if(isPalindrome(palindromeCandidate)) {
palindromes.add(palindromeCandidate);
}
}
}
return palindromes.toArray(new String[palindromes.size()]);
}
private boolean isPalindrome(String source) {
int i =0;
int k = source.length()-1;
for(i=0; i<source.length()/2; i++) {
if(source.charAt(i) != source.charAt(k)) {
return false;
}
k--;
}
return true;
}
I am not sure but you might try whit fourier. This problem remined me on this: O(nlogn) Algorithm - Find three evenly spaced ones within binary string
Just my 2cents