Remove only one element to make a string palindrome - c++

I will be given string. I can remove only 1 element from it. After removing it if the new string becomes palindrome I have to print "Yes" otherwise "No".
For example, I am given a string "abdbca". Here I can remove 5th index 'c' and make it palindrome and i have to print "Yes". On the other hand if the string is something like "abcd" I can not make it palindrome by removing only one character. Hence I have to print "No".
I tried to do it but my code is not efficient enough. Can anybody please suggest me a efficient way to do it? I have to check strings of 10^5 length in less than 2.5 seconds.
the way I tried to do it is shown bellow :
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#define REP(i,n) for(int i=0;i<n;i++)
#define MAX 100010
using namespace std;
bool isPalindrome(char abc[]){
int len = strlen(abc), lem = len/2;
for(int i=0,n=len-1;i<=lem;i++,n--) if(abc[i]!=abc[n]) return false;
return true;
}
int main()
{
int tc;
char str[MAX];
scanf("%d",&tc);
while(tc--){
scanf("%s", str);
int length = strlen(str), len = length - 1, z = length % 2, res = 0, ans = 0, b=0,lem = length / 2;
for(int i = 0;i<length;i++){
int n=0, m=1;
for(int x = 0, y = len;x<i && y!=i;x++,y--){
n++;
if(str[x]!=str[y]){
m=0; ++res;
break;
}
}
if(i>lem) for(int x=n,y=len-n-1;x<y;x++,y--){
if(str[x]!=str[y]){
m=0; ++res;
break;
}
}
else for(int x=n+1,y=len-n;x<y;x++,y--){
if(str[x]!=str[y]){
m=0; ++res;
break;
}
}
if(m==1) {printf("YES\n");b++;break;}
}
//if(length <= res) printf("NO\n");
if(b==0) printf("NO\n");
}
return 0;
}

Since you you only need to remove one character, you can do so in linear time by modifying palindrome checking. The idea is that you compare characters from the beginning to characters from the end and stop at the first mismatch. If you remove one character from the mismatching pair and get a palindrome, then return true, otherwise return false. I implemented the idea in C++ below.
#include<iostream>
#include<string>
using namespace std;
bool palindromeExists(string s)
{
int i = 0;
int j = s.length()-1;
while(i < j)
{
if(s[i] != s[j]) //first mismatch
break;
i++;
j--;
}
int tempj = j-1; //remove s[j]
int tempi = i;
while(tempi < tempj)
{
if(s[tempi] != s[tempj])
break;
tempi++;
tempj--;
}
if(tempi >= tempj) //palindrome found?
return true;
tempi = i+1; //remove s[i]
tempj = j;
while(tempi < tempj)
{
if(s[tempi] != s[tempj])
return false;
tempi++;
tempj--;
}
return true;
}
int main()
{
string s = "abca";
if(palindromeExists(s))
cout << "YES" << endl;
else
cout << "NO" << endl;
return 0;
}
This should return true if the string is already a palindrome, or if it can be a palindrome after the removal of one character. I hope I didn't miss any corner cases.

You can refer complete program in c++ here. Input the string to get the index of character to be removed. String reversal is performed in palim() function. It returns -1 if string is already palindrome.
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
bool palim(string s)
{
string s2;
s2=string(s.rbegin(),s.rend());
if(s2==s)
{
return true;
}
else
{
return false;
}
}
int check(string s)
{
int x;
if(s.length()%2==0)
{
for(int i=0,j=s.length()-1;i<s.length()/2,j>=s.length()/2;i++,j--)
{
if(s[i]!=s[j])
{
string s1=s;
s1.erase(j,1);
if(palim(s1))
{
x=j;
break;
}
else
{
string s1=s;
s1.erase(i,1);
if(palim(s1))
{
x=i;
break;
}
}
}
}
}
else
{
for(int i=0,j=s.length()-1;i<s.length()/2,j>s.length()/2;i++,j--)
{
if(s[i]!=s[j])
{
string s1=s;
s1.erase(j,1);
if(palim(s1))
{
x=j;
break;
}
else
{
string s1=s;
s1.erase(i,1);
if(palim(s1))
{
x=i;
break;
}
}
}
}
}
return x;
}
int main()
{
string s;
cin>>s;
if(palim(s))
{
cout<<"-1"<<endl;
}
else
{
cout<<check(s)<<endl;
}
return 0;
}

Similar to turingcomplete, but with sub functions:
bool isPalindrome(std::string::const_iterator& start, std::string::const_iterator& end)
{
while (start < end) {
--end;
if (*start != *end) {
return false;
}
++start;
}
return true;
}
bool test(const std::string& s)
{
auto start = s.begin();
auto end = s.end();
if (isPalindrome(start, end)) {
// If we remove the middle character of a palindrome,
// We still have a palindrome.
return true;
}
// Now test if there is a palindrome
// if we skip the mismatch char from the start or from the end.
auto start2 = start;
auto end2 = end;
++start2;
--end;
return isPalindrome(start, end) || isPalindrome(start2, end2);
}
Live example

Related

Checking if a word is a palindrome by reversing a stack without using any prewritten functions

#include <iostream>
#include <string>
using namespace std;
#define Max 100000
class Stack {
private:
int top =-1;
char letters[Max];
public:
void setTop(int t) {
top = t;
}
int getTop() {
return top;
}
bool isEmptyStack() {
if (top == -1) {
return true;
}
else{ return false;
}
}
char push(char x,int s) {
if (top != s - 1){
top++;
x = letters[top];
return x;
}
}
char pop() {
if ((isEmptyStack())==false){
cout << "the deleted value is: " << l[top]<<endl;
top--;
return l[top];
}
}
};
void reverse(char letters[], char temp[], int size, Stack stack) {
int i=0;
for (i = 0; i < size; i++) {
stack.push(letters[i],size);
}
i = 0;
cout << temp<<endl;
while (stack.isEmptyStack() == false)
{
letters[-1] = stack.getTop();
stack.pop();
stack.push(letters[i],size);
i++;
}
/* for (int i = 0; i < size; i++) {
cout << temp[i];
}*/
}
int myStringLength(const char* letter)
{
for (int i = 0, c = 0; letter[i] != '\0'; i++, c++) {
if (letter[i] != '\0')
for (; letter[i] != '\0'; i++, c++)
if (letter[i] == '\0') break;
return c;
}
}
int main()
//initializes the main function
{
Stack stack;
string w;
std::cout << "Enter a Word: ";
getline(cin,w);
char* letters = &w[0];
// sets the character text array to set the number of characters equal to the size of the string
//calls the processData function
std::cout << letters<<endl;
int size = myStringLength(letters);
reverse(letters, letters, size, stack);
return 0;//returns the function at 0.
}
I set out to create a program that will check if a word is a palindrome(meaning it is spelled the same normally and if the word is reversed.) I am not yet at that point that is just the final objective. In my code, I have created a stack class because I wanted to feel the satisfaction of getting the same result using my own code. My problem is the stack is not reversing it is returning some weird characters that I don't have the keys on my keyboard to replicate.
The desired outcome should be word's reversed characters.
if the word is food the function should be returning doof. I have already compared the reversed stack to the original and printed the final statement. I fixed the char letters[];
If you're open to using a simple function instead of a Stack then you could use the following program since it is much more simple than your Stack version and hence less-error prone.
#include <iostream>
#include <string>
bool checkIfPalindroom(const std::string &str)
{
for(int i=0;i<(str.size()/2);i++)
{
if (str[i] != str[str.size() - i - 1])
{
return false;//if this if is satisfied even once, return false
}
}
return true;//if the control flow reaches here this will mean that no if was satisfied and hence return true
}
int main()
{
std::string myString = "Somearbitrarystring";
if(checkIfPalindroom(myString))//call the function
{
std::cout<<"The given string: "<<myString <<" is a palindrome"<<std::endl;
}
else
{
std::cout<<"The given string: "<<myString<<" is not a palindrome"<<std::endl;
}
return 0;
}

Remove adjacent Duplicates from a String which have count greater than or equal to burst Length

Given a string with repeating characters and a burst length, output the string such that the count of the same adjacent characters in the string is less than the burst length.
Input : abbccccdd, burstLen = 3
Correct Output : abbdd
My Output: abbd
Input : abbcccdeaffff, burstLen = 3
Correct Output: abbdea
My Output: abbea
//Radhe krishna ki jytoi alokik
#include <bits/stdc++.h>
using namespace std;
string solve(string s, int burstLen)
{
stack<pair<char, int>> ms;
for (int i = 0; i < s.size(); i++)
{
if (!ms.empty() && ms.top().first == s[i])
{
int count = ms.top().second;
ms.push({s[i], count + 1});
}
else
{
if(ms.empty() == true || ms.top().first != s[i])
{
if(!ms.empty() && ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
//(UPDATE)
ms.push({s[i], 1});
}
else
ms.push({s[i], 1});
}
}
}
if(!ms.empty() and ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
}
string ans = "";
while (!ms.empty())
{
ans += ms.top().first;
ms.pop();
}
reverse(ans.begin(), ans.end());
return ans;
}
int main()
{
string s;
int burstLen;
cin >> s;
cin >> burstLen;
cout << solve(s, burstLen) << "\n";
}
It would be better at least to use the container adapter std::queue instead of std::stack because there would not be a need to call the algorithm std::reverse.
Moreover if items of the stack contain the second data member that stores frequencies then you could just increase this data member for repeated characters instead of placing each repeated character in the stack.
For example this code snippet in your program
if (!ms.empty() && ms.top().first == s[i])
{
int count = ms.top().second;
ms.push({s[i], count + 1});
}
makes the function definition too complicated and unclear because the same character is pushed on the stack with different frequencies.
Nevertheless if you want to use the container adapter std::stack the function definition could look simpler. You are not using features of the class std::string.
Here is a demonstrative program that shows how the function could be written using your approach with std::stack.
#include <iostream>
#include <string>
#include <utility>
#include <stack>
#include <iterator>
#include <algorithm>
std::string solve( const std::string &s, size_t burstLen )
{
std::stack<std::pair<char, size_t>> stack;
for ( const auto &c : s )
{
if ( stack.empty() || stack.top().first != c )
{
stack.push( { c, 1 } );
}
else
{
++stack.top().second;
}
}
std::string ans;
while ( !stack.empty() )
{
if ( stack.top().second < burstLen )
{
ans.append( stack.top().second, stack.top().first );
}
stack.pop();
}
std::reverse( std::begin( ans ), std::end( ans ) );
return ans;
}
int main()
{
std::cout << solve( "abbccccdd", 3 ) << '\n';
std::cout << solve( "abbcccdeaffff", 3 ) << '\n';
}
The program output is
abbdd
abbdea
It is interesting to use the stack when after removing a sequence of characters that is not less than the burst length you get from the left and right side sub-sequences anew sequence that again is not less than burst length and you need also to remove it.
In this case you can use two stacks.
Here is a demonstrative program.
#include <iostream>
#include <string>
#include <utility>
#include <stack>
#include <iterator>
#include <algorithm>
std::string solve( const std::string &s, size_t burstLen )
{
std::stack<std::pair<char, size_t>> stack_in;
for ( const auto &c : s )
{
if ( stack_in.empty() || stack_in.top().first != c )
{
stack_in.push( { c, 1 } );
}
else
{
++stack_in.top().second;
}
}
std::stack<std::pair<char, size_t>> stack_out;
while ( !stack_in.empty() )
{
if ( !stack_out.empty() && stack_out.top().first == stack_in.top().first )
{
if ( stack_out.top().second + stack_in.top().second < burstLen )
{
stack_out.top().second += stack_in.top().second;
}
else
{
stack_out.pop();
}
}
else if ( stack_in.top().second < burstLen )
{
stack_out.push( stack_in.top() );
}
stack_in.pop();
}
std::string ans;
while ( !stack_out.empty() )
{
ans.append( stack_out.top().second, stack_out.top().first );
stack_out.pop();
}
return ans;
}
int main()
{
std::cout << solve( "abbccccdd", 3 ) << '\n';
std::cout << solve( "abbcccdeaffff", 3 ) << '\n';
std::cout << solve( "aabcddeeedccbaa", 3 );
}
The program output is
abbdd
abbdea
aabbaa
I gave it a try but it looks complicated so I suggest making a simpler function using a few functions from the standard library.
Example:
#include <algorithm>
#include <iostream>
#include <initializer_list>
#include <iterator>
std::string solve(const std::string& in, size_t burstlen) {
std::string retval;
for(std::string::const_iterator begin = in.cbegin(), bend;
begin != in.end();
begin = bend)
{
// find the first char not equal to the current char
bend = std::find_if_not(std::next(begin), in.end(),
[curr=*begin](char ch){ return ch==curr; });
if(std::distance(begin, bend) < burstlen) {
// length ok, append it
retval.append(begin, bend);
}
}
return retval;
}
int main() {
std::initializer_list<std::string> tests{
"abbccccdd", "abbcccdeaffff"};
for(auto test : tests) std::cout << solve(test, 3) << '\n';
}
Output:
abbdd
abbdea
My Approach to the Solution :
Create a Stack of pair which consists of character and character count
If the Stack is empty or the top element of the stack is not equal to the current element in the string
Case 1: if the frequency of the top element of the stack is greater than or equal to k, store it in a variable say count, Pop the element of Stack count times.
Case 2: if the Stack is Empty, then simply push the element in stack with frequency 1.
Upon Traversing the complete string, if the top element of the stack is having a frequency greater than bursten, start removing elements from the stack (count) number of times.
Now, we have leftout elements in the stack, Start popping them and store them in a string and reverse the string to preserve the order.
Return the new string.
UPDATE : SOLVED. Missing one line in this condition if(ms.empty() == true || ms.top().first != s[i]) After popping the elements, We also have to insert the present element with character frequency 1.
#include<iostream>
#include<stack>
using namespace std;
string solve(string s, int burstLen)
{
stack<pair<char, int>> ms;
for (int i = 0; i < s.size(); i++)
{
if (!ms.empty() && ms.top().first == s[i])
{
int count = ms.top().second;
ms.push({s[i], count + 1});
}
else
{
if(ms.empty() == true || ms.top().first != s[i])
{
if(!ms.empty() && ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
ms.push({s[i], 1});
}
else
ms.push({s[i], 1});
}
}
}
if(!ms.empty() and ms.top().second >= burstLen)
{
int count = ms.top().second;
while(!ms.empty() && count--)
ms.pop();
}
string ans = "";
while (!ms.empty())
{
ans += ms.top().first;
ms.pop();
}
reverse(ans.begin(), ans.end());
return ans;
}
int main()
{
int t;
cin >> t;
while(t--)
{
string s;
int burstLen;
cin >> s >>burstLen;
cout << solve(s, burstLen) << "\n";
}
}
private void solve(){
System.out.printf("%s\n", solve("abbccccdd", 3));
System.out.printf("%s\n", solve("abbcccdeaffff", 3));
}
private LinkedList<Node> addToQueue(String S){
int N = S.length();
LinkedList<Node> queue = new LinkedList<>();
queue.addFirst(new Node(S.charAt(0), 1));
for(int i=1;i<N;i++){
if(!queue.isEmpty() && queue.getFirst().val==S.charAt(i)) {
queue.getFirst().count +=1;
} else {
queue.addFirst(new Node(S.charAt(i), 1));
}
}
return queue;
}
private String solve(String S, int K){
if(S==null || S.length()==0) return "";
int N = S.length();
LinkedList<Node> queue = addToQueue(S);
StringBuilder buf = new StringBuilder();
while(!queue.isEmpty()) {
Node node = queue.removeLast();
int count = node.count;
if(count>=K) continue;
if(isSame(queue, buf)){
while(isSame(queue, buf)) {
count += queue.getLast().count;
queue.removeLast();
}
if(count>=K) buf.deleteCharAt(buf.length()-1);
else {
while(count-->0){
buf.append(node.val);
}
}
} else {
if(count>=K) continue;
while(count-->0){
buf.append(node.val);
}
}
}
return buf.toString();
}
private boolean isSame(LinkedList<Node> queue, StringBuilder buf){
if(queue.isEmpty() || buf.length()==0) return false;
return queue.getLast().val == buf.charAt(buf.length()-1);
}
class Node {
char val;
int count;
public Node(char c, int count){
this.val = c;
this.count = count;
}
}

C++ palindrome not working

I wanted to create function that returns true/false according if the input is a palindrome or not, when given abcddcba or aba it does not give true, but it should . plz help
bool checkPalindrome(char input[],int p=0) {
if(input[1]=='\0'){
return true;
}
if(sizeof(input)%2==0) {
int a = sizeof(input);
for(int i=0;i<(a/2);i++) {
if(input[0+i]==input[a-i-2]){
p++;
}
}
if(p==a/2){
return true;
} else{
return false;
}
}
else{
int a = sizeof(input);
for(int i=0;i<((a-1)/2);i++)
{
if(input[0+i]==input[a-i-2]){
p++;
}
}
if(p==(a-1)/2){
return true;
} else{
return false;
}
}
}
C++ style:
bool checkPalindrome(const std::string& str)
{
size_t len = str.size();
for (size_t i = 0; i < len/2; i++)
{
if (str[i] != str[len-1-i])
return false;
}
return true;
}
C style:
bool checkPalindrome(const char* str)
{
size_t len = str ? strlen(str) : 0;
for (size_t i = 0; i < len/2; i++)
{
if (str[i] != str[len-1-i])
return false;
}
return true;
}
In either case, you may need to evaluate (ask) if an empty string should be considered a palindrome or not.
your code is too long. There's a simple way: iterating once over the elements of the string comparing the n-1 with 0 and n-2 with 1 and so on.
If two characters are not identical return false otherwise continue checking:
bool checkPalindrome(char* str) {
const int size = strlen(str);
for(int i(0), j(size) - 1); i < size / 2; i++, j--)
if(str[i] != str[j])
return false;
return true;
}
int main(){
char* str = "level";
cout << checkPalindrome(str);
cout << endl << endl;
return 0;
}
C++ version based on strings and iterators (only for the sake of completeness, the other answers are already very nice) :
bool checkPalindrome(const string& str) {
for (auto p = str.begin(),q = str.end(); p!=q && p!=q+1; p++ )
if (*p!=*--q) // if char from front doesn't match char from rear ?
return false; // then it's not a palindrome !
return true;
}
Explanations: the iterator p starts at the front of the string and q at the rear (after the last char). p will advance and q will go backwards. If p reaches q or if p has passed q (special case if the word has an even length), it's over and we can conclude a palindrome. But if before, there is any difference between the char at p and the char preceeding q , it's not a palindrome.
Online demo, with little test suite

Largest Palindrome 3 digits C++

I cannot figure out why this code isn't working. It doesn't even seem to be going through my for loops and nested loops. I'm very new to programing. I have been trying to answer Euler questions for practice. Sorry if my code is awful.
#include <iostream>
#include <string>
using namespace std;
bool isPalindrome(int x) {
string str = to_string(x);
for(string::reverse_iterator rit=str.rbegin(); rit!=str.rend(); ++rit) {
string pal = to_string(*rit);
if(pal == str) {
return true;
}else {
return false;
}
}
}
int main() {
int max[] = {0, 0};
for(int i=999; i>99; i--) {
for( int j =999; j>99; j--) {
int pal = i*j;
if(isPalindrome(pal) == true) {
max[1] = pal;
if(max[1] > max[0]){
max[0] = pal;
}
}
}
}
cout << max[0];
}
I think you need to return true in isPalindrome after comparing complete string. ie return true; should be outside for loop
And for checking largest 3 digit palindrome why are you passing int pal = i*j; ie for first iteration 999*999. Check this
bool isPalindrome(int x) {
string str = to_string(x);
string pal = str;
std::reverse(pal.begin(),pal.end());
if(pal == str) {
return true;
}else {
return false;
}
}

How to check if parts of a single-string input are int or char?

I have to take a string i/p of length 15. First two letters should be alphabets, next 13 digits. Eg: AB1234567891234. How can I check if the first two are only alphabets and others are only digits?
#include <regex>
const std::regex e("^[a-zA-Z][a-zA-Z][0-9]{13}$");
std::string str = "ab1234567890123";
if (std::regex_match (s,e))
std::cout << "string object matched\n";
#include <cctype>
bool is_correct(std::string const& s) {
if (s.size() != 15) return false;
if (!std::isalpha(string[0]) || !std::isalpha(string[1]))
return false;
for (std::size_t i = 2; i < 13; ++i) {
if (!std::isdigit(string[i])) return false;
}
return true;
}
You can use the functions defined in the <cctype> header file like isalpha() and isdigit().
#include<iostream>
#include<string>
int main(int argc, char *argv[])
{
std::string n_s = "AB1234567896785";
bool res = true;
std::cout<<"Size of String "<<n_s.size()<<n_s.length()<<std::endl;
int i = 0, th = 2;
while(i < n_s.length())
{
if(i < th)
{
if(!isalpha(n_s[i]))
{
res = false;
break;
}
}
else
{
if(!isdigit(n_s[i]))
{
res = false;
break;
}
}
i++;
}
if(res)
{
std::cout<<"Valid String "<<std::endl;
}
else
{
std::cout<<"InValid Strinf "<<std::endl;
}
return 0;
}