Finding the largest palindrome in string implementation - c++

I'm trying to solve a problem that asks to find the largest palindrome in a string up to 20,000 characters. I've tried to check every sub string whether it's a palindrome, that worked, but obviously was too slow. After a little googling I found this nice algorithm
http://stevekrenzel.com/articles/longest-palnidrome. I've tried to implement it, however I can't get it to work. Also the given string contains illegal characters, so I have to convert it to only legal characters and output the longest palindrome with all characters.
Here's my attempt:
int len = original.length();
int longest = 0;
string answer;
for (int i = 0; i < len-1; i++){
int lower(0), upper(0);
if (len % 2 == 0){
lower = i;
upper = i+1;
} else {
lower = i;
upper = i;
}
while (lower >= 0 && upper <= len){
string s2 = original.substr(lower,upper-lower+1);
string s = convert(s2);
if (s[0] == s[s.length()-1]){
lower -= 1;
upper += 1;
} else {
if (s.length() > longest){
longest = s.length();
answer = s2;
}
break;
}
}
}
I can't get it to work, I've tried using this exact algorithm on paper and it worked, please help. Here's full code if you need it : http://pastebin.com/sSskr3GY
EDIT:
int longest = 0;
string answer;
string converted = convert(original);
int len = converted.length();
if (len % 2 == 0){
for (int i = 0; i < len - 1; i++){
int lower(i),upper(i+1);
while (lower >= 0 && upper <= len && converted[lower] == converted[upper]){
lower -= 1;
upper += 1;
}
string s = converted.substr(lower+1,upper-lower-1);
if (s.length() > longest){
longest = s.length();
answer = s;
}
}
} else {
for (int i = 0; i < len; i++){
int lower(i), upper(i);
while (lower >= 0 && upper <= len && converted[lower] == converted[upper]){
lower -= 1;
upper += 1;
}
string s = converted.substr(lower+1,upper-lower-1);
if (s.length() > longest){
longest = s.length();
answer = s;
}
}
}
Okay so I fixed the problems, it works perfectly fine but only if the length of converted string is odd. Please help.

I can see two major errors:
Whether you initialise your upper/lower pointers to i,i or i,i+1 depends on the parity of the palindrome's length you want to find, not the original string. So (without any further optimisations) you'll need two separate loops with i going from 0 to len (len-1), one for odd palindrome lengths and another one for even.
The algorithms should be executed on the converted string only. You have to convert the original string first for it to work.
Consider this string: abc^ba (where ^ is an illegal character), the longest palindrome excluding illegal characters is clearly abcba, but when you get to i==2, and move your lower/upper bounds out by one, they will define the bc^ substring, after conversion it becomes bc, and b != c so you concede this palindrome can't be extended.

#include <iostream>
using namespace std;
int main()
{
string s;
cin >> s;
signed int i=1;
signed int k=0;
int ml=0;
int mi=0;
bool f=0;
while(i<s.length())
{
if(s[i]!=s[i+1])
{
for(k=1;;k++)
{
if(!(s[i-k]==s[i+k] && (i-k)>=0 && (i+k)<s.length()))
{
break;
}
else if(ml < k)
{
ml=k;
mi=i;
f=1;
}
}
}
i++;
}
i=0;
while(i<s.length())
{
if(s[i]==s[i+1])
{
for(k=1;;k++)
{
if(!(s[i-k]==s[k+1+i] && (i-k)>=0 && (k+i)<s.length()))
{
break;
}
else if(ml < k)
{
ml=k;
mi=i;
}
}
}
i++;
}
if(ml < 1)
{
cout << "No Planidrom found";
return 0;
}
if(f==0)
{
cout << s.substr(mi-ml,2*ml+2);
}
else
{
cout << s.substr(mi-ml,2*ml+1);
}
return 0;
}
#biziclop : As you said.. i used 2 while loops. one for even and one for old palindrom string. finally i was able to fix it. thanks for your suggestion.

public void LongestPalindrome()
{
string str = "abbagdghhkjkjbbbbabaabbbbbba";
StringBuilder str1=new StringBuilder();
StringBuilder str2= new StringBuilder();
for (int i = 0; i < str.Length; i++)
{
str1.Append((str[i]));
for (int j = i + 1; j < str.Length; j++)
{
str1.Append((str[j]));
if (Checkpalindrome(str1))
{
str2.Append(str1);
str2.Append(" ");
}
}
str1.Clear();
}
var Palstr = str2.ToString().Split(' ');
var Longestpal = Palstr.Where(a => a.Length >= (Palstr.Max(y => y.Length)));
foreach (var s in Longestpal)
{
Console.WriteLine(s);
}
}
public bool Checkpalindrome(StringBuilder str)
{
string str1 = str.ToString();
StringBuilder str2=new StringBuilder();
var revstr = str1.Reverse();
foreach (var c in revstr )
{
str2.Append(c);
}
if (str1.Equals(str2.ToString()))
{
return true;
}
return false;
}

Related

leetcode problem 1255 Maximum Score Words Formed by Letters

Given a list of words, a list of single letters (might be repeating), and score of every character.
Return the maximum score of any valid set of words formed by using the given letters (words[i] cannot be used two or more times).
It is not necessary to use all characters in letters and each letter can only be used once. Score of letters 'a', 'b', 'c', ... ,'z' is given by score[0], score[1], ... , score[25] respectively
My approach is
finding score of a word
then can that word be formed or not
and finally, get the result code is given below
class Solution {
public:
// score finder func
int scoreFinder(vector<int>& score , string s){
int ans = 0;
for(int i = 0; i < s.size(); i++){
char ch = s[i];
ans += score[ch -'a'];
}
return ans;
}
// word can be formed or not
bool canFormed(string s , unordered_map<char,int>& myMap){
for(int i = 0; i < s.size(); i++){
if(myMap.count(s[i]) <= 0){
return false;
break;
}else{
myMap[s[i]]--;
}
}
return true;
}
int maxScoreWords(vector<string>& words, vector<char>& letters, vector<int>& score){
// freq Count of letters
/* unordered_map<char,int> map;
for(int i = 0; i < letters.size(); i++){
map[letters[i]]++;
}*/
int result = 0; // final score is stored in it
int idx = 0;
while(idx < words.size()){
// creating new map every time so that check for all possible words combinations
unordered_map<char,int> myMap;
for(int j = 0; j < letters.size(); j++){
myMap[letters[j]] ++; //= map[letters[j]];
}
int tempResult = 0;
for(int i = idx; i < words.size(); i++){
string temp = words[i];
if(canFormed(temp , myMap)){
tempResult += scoreFinder(score , temp);
}
}
result = max(result , tempResult);
idx++;
}
return result;
}
};
Input:
words = ["dog","cat","dad","good"],
letters = ["a","a","c","d","d","d","g","o","o"],
score = [1,0,9,5,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0]
Output:
23
but I am getting the wrong output and I am unable to find the error in my code, my output is 33 for this testcase.
There is a minor bug in your code.
In the function canFormed you decrement the counter als in the case where it is 0 already. We could simply add an additional if-statement or rewrite the whole condition.
Please see one possible solution below:
// word can be formed or not
bool canFormed(string s, unordered_map<char, int>& myMap) {
for (int i = 0; i < s.size(); i++) {
if (myMap.count(s[i]) <= 0) {
return false;
}
else {
if (myMap[s[i]] > 0) {
myMap[s[i]]--;
}
else return false;
}
}
return true;
}
Then it should work.
Solved with backtracking in JAVA
public int maxScoreWords(String[] words, char[] letters, int[] score) {
int[] counts = new int[26];
for (char letter : letters) {
counts[letter - 'a']++;
}
return wordHelper(words, counts, score, 0);
}
static int wordHelper(String[] words, int[] counts, int[] score, int index) {
// base case
if (index > words.length - 1) {
return 0;
}
// recursive case - exclude
int excludedSum = wordHelper(words, counts, score, index + 1);
// recursive case - include
int includedSum = 0;
boolean recursionCall = true;
int wordScore = 0;
for (char c : words[index].toCharArray()) {
counts[c - 'a']--;
if (counts[c - 'a'] < 0) {
recursionCall = false;
}
wordScore += score[c - 'a'];
}
if (recursionCall) {
includedSum = wordScore + wordHelper(words, counts, score, index + 1);
}
for (char c : words[index].toCharArray()) {
counts[c - 'a']++;
}
return Math.max(excludedSum, includedSum);
}

Make palindromic string non-palindromic by rearranging its letters

Q: Make palindromic string non-palindromic by rearranging its letters.
I just want to know why my solution is failing (wrong answer) for some test cases when i submit the code. I am sure there is an easy solution such as sorting the whole string?
void makeNonPalindrome(string& s)
{
bool ans = false;
int l = s.length();
if(l % 2 == 0)
{
for(int i = l/2; i < l; i++)
{
if(s[l/2 - 1] != s[i])
{
swap(&s[l/2 - 1],&s[i]);
ans = true;
break;
}
}
if(!ans)
{
for(int i = 0; i < l/2-1; i++)
{
if(s[l/2 - 1] != s[i])
{
ans = true;
break;
}
}
}
}
else
{
for(int i = l/2 + 1; i < l; i++)
{
if(s[l/2 - 1] != s[i])
{
swap(&s[l/2 - 1],&s[i]);
ans = true;
break;
}
}
if(!ans)
{
for(int i = 0; i < l/2-1; i++)
{
if(s[l/2 - 1] != s[i])
{
ans = true;
break;
}
}
}
if(!ans)
{
if(s[l/2] != s[0])
{
swap(&s[l/2],&s[0]);
ans = true;
}
}
}
if(ans)
cout << s << '\n';
else
cout << -1 << '\n';
}
Rearranging a palindrome so it become non-palindromic can be done quite fast, by simply trying to swap two adjacent letters in the string if they are different.
For instance, in 'bob', you'd need to find the first distinct adjacent letters (that is b and o in our case), and swap them. The result would then be 'obb', which is not a palindrome.
void makeNonPalindrome(std::string& s) {
char tmp;
for (unsigned i = 0; i < s.length() - 1; i++) {
if (s[i] != s[i+1]) { // then swap s[i] and s[i+1]
tmp = s[i];
s[i] = s[i+1];
s[i+1] = tmp;
std::cout << s << '\n';
return;
}
}
std::cout << -1 << '\n';
}
This is a simpler way to make a palindrome non palindromic.
NB: this function assumes that the input is indeed a palindrome, so if you feed it a string like 'oob', it will output 'bob' which is a palindrome.
Given the input palindrome string s you can just use find_first_not_of to determine if the string can be rearranged into a non-palindrome at all, and if so what characters should be swapped to do this. For example:
const auto foo = s.find_first_not_of(s[0], 1);
If foo == string::npos it means that there isn't a possible non-palindrome rearrangement. Otherwise swap(s[0], s[foo]) will break the palindrome.
Live Example

Print all the possible palindromes that can be generated only moving 1 index

I am trying to do a program which print all possible palindromes that can be generated rearrangement involves that a character changes its position with maximum 1 index, meaning only interchanges of adjacent characters are allowed.
I tried a lot of codes but the best one I had is the next one.
Only I could get all possible palindromes rearranged but with all changes (not only one)
CODE
#include <bits/stdc++.h>
using namespace std;
#define M 26
bool caNformPalindrome(string str, int* count_array)
{
//Initialize array with zeroes
for (int i = 0; i < 26; ++i)
{
count_array[i] = 0;
}
int length = str.length();
/* Updating frequency according to given string */
for (int i = 0; i < length; i++)
{
count_array[str[i] - 'a']++;
}
int odd_count = 0;
//Find odd_count
for (int i = 0; i < M; i++)
{
if (count_array[i] % 2 == 1)
{
odd_count++;
}
}
//if length is odd_count then only one letter's frequency must be odd_count
if ((length % 2 == 1 && odd_count == 1 ) || (length %2 == 0 && odd_count == 0))
{
return true;
}
else//if length is even no letter should have odd_count frequency
{
return false;
}
}
//Function to reverse the string
string reverse(string str)
{
string rev = str;
reverse(rev.begin(), rev.end());
return rev;
}
//Function to print
void printPalIndromes(string str)
{
int count_array[M];
// checking whether letter can make palindrome or not
if (!caNformPalindrome(str, count_array))
{
return;
}
int length = str.length();
// half will contain half part of all palindromes,
// that is why pushing half count_array of each letter
string half = "";
char mid;//store odd count charcter
for (int i = 0; i < M; i++)
{
if(count_array[i] % 2 == 1)
{
mid = i + 'a';
}
half += string(count_array[i] / 2, i + 'a');
}
string palindrome_string;
do
{
palindrome_string = half;
if (length % 2 == 1)
{
palindrome_string += mid;
}
palindrome_string += reverse(half);
cout<<palindrome_string<<endl;
}
while (next_permutation(half.begin(), half.end()));
}
//Main function
int main()
{
string str = "aabbc";
cout<<"Possible Permutations for Input_string only with 1 change"<<str<<" are: "<<endl;
printPalIndromes(str);
return 0;
}

count the ocurrences of substrings

I've a task to count the occurrences of sub string in a char String. I write this code but on certain inputs output is wrong. like string is "hassana" and sub is "as" then it outputs 2 ...some one plz help me
int CharString :: countOccurenceOf(const char* substr)
{
int count = 0;
bool find = false;
for(int i = 0; i < size1; i++)
{
if(cstr[i] == substr[0])
{
int x = i;
int c = 1;
find = true;
while ( substr[c] != '\0' && find == true && (x+1) < size1)
{
if(cstr [x+1] != substr[c])
{
find = false;
}
c++;
x++;
}
if (find == true)
{
count++;
i = i + c-1;
}
}
}
return count;
}
Got some Solution.....is that okay?
int CharString :: countOccurenceOf(const char* substr)
{
int len = 0;
if ( substr != '\0')
{
while( substr[len] != '\0')
len++;
}
int count = 0;
bool find = false;
for(int i = 0; i < size1; i++)
{
if(cstr[i] == substr[0])
{
int x = i;
int c = 1;
find = true;
while ( substr[c] != '\0' && find == true && (x+1) < size1)
{
if(cstr [x+1] != substr[c])
{
find = false;
}
c++;
x++;
}
if (find == true && c == len)
{
count++;
i = i + c-1;
}
}
}
return count;
}
The problem is that you're breaking automatically if x+1 < size1. If the first character of the substring matches the last character of the main string, then this will automatically break and "find" will still be set to true so you'll increment matches by 1. There are numerous ways to change your code to fix this problem; hopefully you can find one now that you know what the problem is.
Assuming cstr is your class internal string:
int CharString :: countOccurenceOf(const char* substr)
{
int occurrencies = 0;
unsigned char* s = cstr;
while (s) {
if (strstr(s,substr)) { occurrencies++; s+= strlen(substr); }
else s++;
}
return occurrencies;
}

how to check whether 2 strings are rotations to each other ?

Given 2 strings, design a function that can check whether they are rotations to each other without making any changes on them ? The return value is boolean.
e.g ABCD, ABDC, they are not rotations. return false
ABCD, CDAB or DABC are rotations. return true.
My solution:
shift one of them to right or left one position and then compare them at each iteration.
If they are not equal at all iterations, return false. Otherwise, return true.
It is O(n). Are there other more efficient solutions ?
What if the contents of them cannot be changed ?
thanks
Concatenate the given string with the given string.
Search for the target string in the concatenated string.
Example:
Given = CDAB
After step 1, Concatenated = CDABCDAB
After step 2, Success CDABCDAB
^^^^
Rather than shifting one of them, it might be more efficient to use two index variables. Start one at 0 each time and the other at each of the possible positions (0 to N-1) and increment it mod N.
If you can't modify the strings, just take the first character of string1 and compare it to each character of string2. When you get a match, compare the second char of string1 to the next char of string2, and so on.
Pseudocode:
len = strlen(string1);
len2 = strlen(string2);
if( len != len2 )
printf("Nope.");
for( int i2=0; i2 < len; i2++ ) {
for( int i1=0; i1<len; i1++ ) {
if( string1[i1] != string2[(i2+i1)%len] )
break;
}
if( i1 == len ) {
print("Yup.");
break;
}
}
A simple one would be:
(s1+s1).find(s2) != string::npos && s1.size() == s2.size();
#include <iostream>
#include <cstring>
#include<string>
using namespace std;
void CompareString(string, string, int);
int ComputeStringLength(string str);
int main()
{
string str = ""; string str1 = ""; int len = 0, len1 = 0;
cout << "\nenter string ";
cin >> str;
cout << "\nenter string 2 to compare:- ";
cin >> str1;
len = ComputeStringLength(str);
len1 = ComputeStringLength(str1);
if (len == len1)
CompareString(str, str1, len);
else
cout << "rotation not possible";
getchar();
return 0;
}
int ComputeStringLength(string str)
{
int len = 0;
for (int i = 0; str[i] != '\0'; i++)
{
len++;
}
return len;
}
void CompareString(string str, string str1, int n)
{
int index = 0, flag = 0, curr_index = 0, count1 = 0, flagj = 0;
for (int i = 0; i<n; i++)
{
for (int j = flagj; j<n; j++)
{
if (str[i] == str1[j])
{
index = j;
flagj =j;
count1++;
flag++;
if (flag == 1)
{
curr_index = index;
}
break;
}
}
}
int temp = count1;
if (count1 != n)
{
if (curr_index>=0)
{
int k = 0;
for (int i = n - 1; i>n - curr_index - 1; i--)
{
if (str[i] == str1[k])
{
temp++;
k++;
}
}
}
if (temp == n)
{
cout << "\n\nstring is same after rotation";
}
else
{
cout << "\n\nstring is not same after rotation";
}
}
else
{
cout << "\n\nstring is same after rotation";
}
}
https://dsconceptuals.blogspot.in/2016/10/a-program-to-check-if-strings-are.html