How can I fix this c++ palindrome code? [closed] - c++

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
So I'm trying to write a c++ palindrome program. I've come up with two functions so far.
void isPal(string str)
{
int a = 0, b = str.length();
string checker1 = "", checker2 = "";
for (; a != str.length(); a++)
checker1 += str[a];
for (; b >= 0; b--)
checker2 += str[b];
cout << checker1 << " " << checker2 << endl;
if (checker1 == checker2)
cout << "Palindrome baby!" << endl;
if (checker1 != checker2)
cout << "Not palindrome!" << endl;
}
bool isit(string str)
{
int x = str.length(), counter = 0;
if (str.length() <= 1)
return true;
else
{
while (counter != str.length())
{
string strNew = str.erase(0, 1);
strNew = strNew.erase(strNew.length() - 1);
string strNewer = str.replace(1, x, strNew);
return str[0] == str[str.length()] && isit(strNewer);
counter++;
}
}
}
Why does the first function always returns the "Not palindrome!" if-statement?
I'll admit that the second is a mess. I'm not even sure I completely understand my thinking when I wrote it. My intentions was to come up with a similar answer to the recursive Python palindrome code.
In python the inductive case was simply
return str[0] == str[-1] and isit( str[1:-1] )
How can I write an inductive c++ palindrome code?
Update: -4 for a beginner's question!! really ? :)

The simplest way to check whether a string is palindrome is to write
if ( s == std::string( s.rbegin(), s.rend() ) ) std::cout << "The string is palimdrome." << std::endl;
As for your approach with recursion then the function could look the following way
bool isPal( const std::string &s )
{
return ( s.size() < 2 || ( s[0] == s[s.size() - 1] && isPal( s.substr( 1, s.size() - 2 ) ) ) );
}

You have a lot of problems in both of your functions. To test for a palindrome, you only need to loop through the string once:
bool isPalindrome(const std::string& s)
{
for (int i = 0; i < s.length() / 2; ++i)
{
if (s[i] != s[s.length() - 1 - i])
{
return false;
}
}
return true; // if every element has a mirror, it is a palindrome
}
In your second version:
return str[0] == str[str.length()] && isit(strNewer);
counter++;
The second line will never get executed.
Writing a recursive version of the function would be a waste, but would require either copying the substrings, or providing an index to the function:
Copy Version
bool isPalindrome(const std::string& s)
{
if (s.length() <= 1)
return true;
if (s[0] != s[s.length() - 1]) // or s.front() != s.back() in C++11
return false;
std::string t = s.substr(1, s.length() - 2));
return isPalindrome(t);
}
Indexed Version
bool isPalindrome(const std::string& s, int index = 0)
{
if (index <= s.length() / 2)
{
return s[index] == s[s.length() - 1 - index] && isPalindrome(s, ++index);
}
return true;
}

There are two key things you should know about how strings work:
Every quoted string, aka "c-string" or "string literal", consists of an array of 0 or more char followed by a null character '\0', e.g. the string "bar" has three printable characters ( 'b', 'a', & 'r' ) and one non-printing character '\0' (the null character). So, str.c_str() would be equivalent to char str[4] = {'b','a','r','\0'} in this case.
The length() of a string is equal to the number of printable characters.
The first iterator for (; a != str.length(); a++) counts from a=0 up to a=(str.length()-1) (as it should). That means that only the characters of the string (and not the null-terminus) will be appended by your checker1 += str[a]; line. Internally, a '\0' will be automatically put at the end.
The second iterator -- for (; b >= 0; b--) -- is does not properly mirror the first. It counts from b=str.length() down to b=0. Following from points 1 and 2, it should not be obvious that the character at str[str.length()] will always be '\0'. That means that your appended string, checker2 is first assigned the null-terminator, and then the rest of the string. That means that when you check the two for inequality, is will appear as if it were a zero-length string, i.e. "". As such, it will always evaluate as != for any non-zero-length str, and your function will always print "Not palindrome!".

Related

My recursive function to reverse the chars of a string does not work

I was trying to make different recursive functions for the same problem i.e. to reverse the letters of a word. While all my solutions with a void return type (where i just printed letters in reverse) worked, I've been trying to make one using the string return type but am running into a problem. When entered hello, the following code gives me l. And I can't seem to figure out why...
string reverse(string s)
{
int len = s.length();
if (len <= 1)
{
return s;
}
swap(s[0], s[len-1]);
return reverse(s.substr(1, len-2));
}
You're calling your function with a substring each time and only returning the final character. In your lower return statement ( return reverse(s.substr(1, len-2)); ) you need to include the first and last characters as well.
Something like:
return s[0] + reverse(s.substr(1,len-2)) + s[len-1];
The word "Hello" has an odd number of letters. So the last recursive call of the function returns the letter 'l' due to this if statement
if (len <= 1)
{
return s;
}
that is the return value of all the recursive calls of the function.
You should write at least like
string reverse(string s)
{
auto len = s.length();
if (len <= 1)
{
return s;
}
swap(s[0], s[len-1]);
return s[0] + reverse(s.substr(1, len-2)) + s[len-1];
}
In fact using the function swap is redundant. You could write
string reverse(string s)
{
return s.length() < 2 ? s
: s[s.length() - 1] + reverse( s.substr( 1, s.length() - 2 ) ) + s[0];
}
Without the recursion the function can look for example the following way
string reverse( const string &s )
{
return { s.rbegin(), s.rend() };
}
use this code as to get some proper logic. I am passing string and its 0th index and its last index as parameters. Then just used the swapping technique and made a recursive call. For better understanding i will recommend debug the code and watch every itration.
#include <iostream>
using namespace std;
string reverse(string str, int i, int j)
{
if (i >= j)
return str;
char temp = str[i];
str[i] = str[j];
str[j] = temp;
return reverse(str, i + 1, j - 1);
}
int main()
{
string str = "Hello";
cout << "Reverse string is: " << reverse(str, 0, str.length() - 1);
return 0;
}

C++ Palindrome program always giving 0 (false) as an output problem; Where is my code wrong?

The problem is that it always outputs 0 (false) as a result. Probably the problem is in the isPalindrome function, but I cannot figure where exactly. Would be grateful if someone helped.
#include <iostream>
#include <cmath>
#include <string>
using namespace std;
bool isPalindrome(string word)
{
bool result;
for (int i = 0; i <= word.length() - 1; i++)
{
if (word.at(i) == word.length() - 1)
{
result = true;
}
else
{
result = false;
}
return result;
}
}
int main()
{
string word1;
int count;
cout << "How many words do you want to check whether they are palindromes: " << flush;
cin >> count;
for (int i = 0; i < count; i++)
{
cout << "Please enter a word: " << flush;
cin >> word1;
cout << "The word you entered: " << isPalindrome(word1);
}
}
Try this one:
bool isPalindrome(string word)
{
bool result = true;
for (int i = 0; i < word.length() / 2; i++) //it is enough to iterate only the half of the word (since we take both from the front and from the back each time)
{
if (word[i] != word[word.length() - 1 - i]) //we compare left-most with right-most character (each time shifting index by 1 towards the center)
{
result = false;
break;
}
}
return result;
}
In this statement
if (word.at(i) == word.length() - 1)
the right side expression of the comparison operator is never changed and have the type std::string::size_type instead of the type char. You mean
if (word.at(i) == word.at( word.length() - 1 - i ))
However there is no sense to use the member function at. You could us the subscript operator. For example
if ( word[i] == word[word.length() - 1 - i ] )
And the loop should have word.length() / 2 iterations.
Also within the loop you are overwriting the variable result. So you are always returning the last value of the variable. It can be equal to true though a string is not a palindrome.
Also the parameter should be a referenced type. Otherwise a redundant copy of the passed argument is created.
The function can be defined the following way
bool isPalindrome( const std::string &word )
{
std::string::size_type i = 0;
std::string::size_type n = word.length();
while ( i < n / 2 && word[i] == word[n - i - 1] ) i++;
return i == n / 2;
}
Another approach is the following
bool isPalindrome( const std::string &word )
{
return word == std::string( word.rbegin(), word.rend() );
}
Though this approach requires to create a reverse copy of the original string.
The simplest way is to use the standard algorithm std::equal. Here is a demonstrative program
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
bool isPalindrome( const std::string &word )
{
return std::equal( std::begin( word ),
std::next( std::begin( word ), word.size() / 2 ),
std::rbegin( word ) );
}
int main()
{
std::cout << isPalindrome( "123454321" ) << '\n';
return 0;
}
I hope this one helps you also (corrected also warnings):
bool isPalindrome(string word)
{
bool result = false;
int lengthWord = (int)word.length();
for (int i = 0; i <= (lengthWord / 2); ++i)
{
if (word.at(i) == word.at(lengthWord - i -1))
{
result = true;
continue;
}
result = false;
}
return result;
}
Two possible problems.
You appear to be comparing a character to a number
if (word.at(i) == word.length() - 1)
shouldn't this be
if (word.at(i) == word.at(word.length() - i)) ?
There are 3 returns within the if statement, so no matter what the outcome it's only going to compare one character before returning to the calling function.
As a point of technique, repeated calls to .length inside the loop, which always returns the same value, wastes time and makes the code more difficult to understand.
You need to return as soon as you find a mismatch. If you are looking for a palindrome you only need to compare the first half of the word with the second half in reverse order. Something like
bool isPalindrome(string word)
{
for (int i = 0, j= word.length() - 1; i<j; i++, j--)
// i starts at the beginning of the string, j at the end.
// Once the i >= j you have reached the middle and are done.
// They step in opposite directions
{
if (word[i] != word[j])
{
return false;
}
}
return true;
}
The loop in the function isPalindrome will only execute once, because the return statement is unconditionally executed in the first iteration of the loop. I am sure that this is not intended.
To determine whether a string is a palindrome, the loop must be executed several times. Only after the last character has been evaluated (in the last iteration of the loop) will it be time to use the return statement, unless you determine beforehand that the string is not a palindrome.
Also, in the function isPalindrome, the following expression is nonsense, as you are comparing the ASCII Code of a letter with the length of the string:
word.at(i) == word.length() - 1
Therefore, I suggest the following code for the function:
bool isPalindrome(string word)
{
for (int i = 0; i < word.length() / 2; i++)
{
if (word.at(i) != word.at( word.length() - i - 1) ) return false;
}
return true;
}
As discussed in the comments under your question. You made some mistakes in the code.
Your function should more or less look like this:
bool isPalindrome(string word) {
bool result = true;
for (int i = 0; i <= word.length() - 1; i++)
{
if (word.at(i) != word.at(word.length() - 1 -i))
{
return false;
}
}
return result;
}

How does strings comparison in C++ work?

I am trying to solve this problem.
I am implementing it with strings. Here is my code snippet
string s,ss;
// s and ss both contains integer input.
while(s <= ss )
//while( s<=ss && s.size() <= ss.size())
{
int i = inc, j = dec; // inc and dec are middle values. both equal if odd else different
while((s[j]-'0')==9 && i < len && j>=0){
// for cases like 999
s[i] = s[j] = '0';
i++;
j--;
}
if(j<0){
s = "1" + s;
int l = s[len-1] - '0';
l++;
//cout<<l<<"\n";
s[len] = (l + '0');
}
else{
int l = s[j] - '0';
l++;
s[i] = s[j] = (l+'0');
}
if(s <= ss)
cout<<"out in wild "<<s<<" and "<<ss<<"\n";
}
cout<<s<<endl;
The problem that I am facing is when input is like 999 or 9999. The outer while loop keeps on looping even when the value of s increases, but if I add while( s<=ss && s.size() <= ss.size()) it works completely fine. Why is while(s<=ss) is not working? I rarely use the string class, so I don't understand it completely. Why don't string s= 101 and ss=99 stop the while loop?
Complete code link is here
You are comparing strings with lexicographical order, not numbers , so "101" is less than "99" (because '1' < '9') , e.g.
int main(){
std::string s = "99";
std::string ss = "101";
std::cout << std::boolalpha << (s <= ss);
}
Outputs false.
Notes:
A better design for your program would be to manipulate numbers (int or double ...) and not strings in the first place, so this kind of expressions would naturally work as you expect.
E.g. "101" + "99" is "10199", not "200" ...
But if you really need strings, consider this post to sort strings containing numbers.
As pointed by #Deduplicator, a program that needlessly overuses strings is sometimes called Stringly Typed
Also see std::lexicographical_compare
Since your input explicitly only involves positive integers without leading 0, writing a comparison function is trivial, something like : (untested)
/* Returns 1 if the integer represented by s1 > the integer represented by s2
* Returns -1 if the integer represented by s1 < the integer represented by s2
* Return 0 is both are equals
*
* s1 and s2 must be strings representing positive integers without trailing 0
*/
int compare(const std::string& s1, const std::string& s2)
{
if(s1.size() > s2.size())
return 1;
if(s2.size() > s1.size())
return -1;
for(std::size_t i = 0 ; i < s1.size() ; ++i)
{
if(s1[i] - '0' < s2[i] - '0')
return 1;
if(s2[i] - '0' < s1[i] - '0')
return -1;
}
return 0;
}
While s and ss are string variables, they are compared character by character.
In the case that you mentioned being: s = "101" & ss = "99", by first hand it will check the first character in each string, and as '1' < '9' it exit up with s < ss. I would advise you to convert those values to integers before comparison.
As the s is compared with ss in lexicographical order, I would suggest you to compare one char from tail with one char from head (one by one till you reach the middle) to solve that problem.

C++ custom string trim implementation valgrind warning

recently I implemented a custom function for trimming std::strings that removes whitespace character prefixes and suffixes.
I tested the functionality and it works according to my unit tests, but when run the tests using valgrind, I get the following output:
==4486== Conditional jump or move depends on uninitialised value(s)
==4486== at 0x415DDA: is_ws_char(char) (parse.cpp:22)
==4486== by 0x415BC6: parse::trim(std::string&) (parse.cpp:34)
My input test string was
string s(" a");
I do not see what is the problem here.
The code looks like this:
inline bool is_ws_char(const char c) { // this is line 22 in my code
return (c == ' ' || c == '\n' || c == '\t' || c == '\r');
}
void parse::trim(std::string& str) {
size_t len = str.size();
size_t i = 0;
for (; i < len; ++i)
if (!is_ws_char(str[i]))
break;
const size_t start = i;
for (i = len - 1; i >= 0; --i)
if (!is_ws_char(str[i])) // this is line 34 in my code
break;
const size_t end = i;
str = str.substr(start, end - start + 1);
}
Does anybody has an idea what is the problem here?
I briefly thought that is's just a valgrind oddity, but that seems to be rather unlikely.
Thanks in advance!
This loop is invalid
for (i = len - 1; i >= 0; --i)
The condition will be always equal to true because expression --i will be always >= 0 due to the fact that i is unsigned integer.
Also when str.size() is equal to zero then len - 1 will be equal to std::string::npos.

How to convert a recursive solution to bottom up or top down solution?

I am solving this problem-
Given a string consisting of a,b and c's, we can take any two adjacent
distinct characters and replace it with the third character. For
example, if 'a' and 'c' are adjacent, they can replaced with 'b'. What
is the smallest string which can result by applying this operation
repeatedly?
Now I have written the following recursive solution (far from efficient), but want to convert it to either top-down or bottom-up solution.
Problem: I am not able to come up with a tabular structure for memoization. Even though I have to output only the length of resulting string, how can I solve it without actually solving the problem. The strings are getting reduced, so how do I store them?
Any hint for DP solution or Memoization would be great!
EDIT Many people have come up with top-down memoization solution, please try bottom-up as well.
#include <iostream>
#include <string>
using namespace std;
string reduce(string s)
{
if (s.length() <= 1)
return s;
int k;
char c = s[0];
string min = s;
for (k = 1; k < s.length() && c; ++k)
if (s[k] != c)
c = 0;
if (c)
return s;
if (s.length() == 2){
if (s[0] != 'a' && s[1] != 'a')
s[0] = 'a';
else if (s[0] != 'b' && s[1] != 'b')
s[0] = 'b';
else if (s[0] != 'c' && s[1] != 'c')
s[0] = 'c';
s.resize(1);
return s;
}
for (k = 1; k < s.length(); ++k){
string s1 = reduce(s.substr(0, k));
string s2 = reduce(s.substr(k));
if (s1.length() + s2.length() < min.length())
min = s1 + s2;
if (!s1.empty() && !s2.empty() && s1.back() != s2.front()){
if (s1.back() != 'a' && s2.front() != 'a')
s1.back() = 'a';
else if (s1.back() != 'b' && s2.front() != 'b')
s1.back() = 'b';
else if (s1.back() != 'c' && s2.front() != 'c')
s1.back() = 'c';
s1 = reduce(s1 + s2.substr(1));
if (s1.length() < min.length())
min = s1;
}
}
return min;
}
int main()
{
string input;
cin >> input;
cout << reduce(input) << endl;
return 0;
}
I'm a bit too lazy to think the problem through, but I'll give you an approach to memoization that often enough works.
Instead of recursing directly, introduce mutual recursion.
std::string reduce(std::string const &s)
{
// ...
string s1 = reduce_memo(s.substr(0, k));
string s2 = reduce_memo(s.substr(k));
// ...
}
where reduce_memo maintains a hash table, i.e. an unordered_map, mapping subproblems to their solutions.
// static is incredibly ugly, but I'll use it here for simplicity
static std::unordered_map<std::string, std::string> memo;
std::string reduce_memo(std::string const &s)
{
try {
return memo.at(s);
} except (std::out_of_range const &) {
std::string r = reduce(s);
memo[s] = r;
return r;
}
}
When programming in C++98, use std::map instead of unordered_map.
This doesn't solve the problem, but I noticed:
if (s.length() == 2){
if (s[0] != 'a' && s[1] != 'a')
s[0] = 'a';
else if (s[0] != 'b' && s[1] != 'b')
s[0] = 'b';
else if (s[0] != 'c' && s[1] != 'c')
s[0] = 'c';
s.resize(1);
return s;
}
doesn't work according to the problem statement:
we can take any two adjacent distinct characters and replace it with the third character.
Consider the string s = "bb". Neither s[0] nor s[1] are equal to 'a', which means the condition s[0] != 'a' && s[1] != 'a' will evaluate to true for the string "bb". This goes for any string of consecutive characters of the same value, e.g. "bb", "cc".
Perhaps in the condition you can take the difference of the two consecutive characters, and check if they're non-zero.
You can memoize your solution by storing the result of reduce(s) in a map<string,string>.
string reduce(string s, map<string,string>& memo) {
if (memo.count(s)) {
return memo[s];
}
// The rest of your code follows...
memo[s] = min;
}
Whatever i have understood from the problem the solutions should be
length of the input - if all input characters are same like
aaaaa - 5
bbb - 3
and 1 in every other case.
Correct me if I miss some part of the problem.
The absolute minimum is 1. However, the specifics of the string and replacement rules may yield between 1 and n, where n is the length of the string.
For the specific example, then the smallest possible is n/2, as you take 2 characters and replace them with 1 (which cannot be further replaced) so even if you had "acacacacacacacac", the best possible case, you would still only achieve the factor of 2 reduction.
I solved a similar problem in competitive programming workshop,
and indeed your proposed solution weren't fast enough.
My solution was creating such vector:
string s;
cin >> s;
int length = s.length();
vector<vector<int> > v(length, vector<int>(length)); // 2d array of size length*length.
where v[i][j] will be the minimal length the substring from i to j of s can get to.
Later all you have to do is fill this table in increasing size.
Hope that helped.
"a...a" (“a" * n) == > n
"b...b" (“b" * n) == > n
"c...c" (“c" * n) == > n
any other ==> 1 or 2 with my greedy algorithm.
If we get 2 in this greedy algorithm, I can't prove it is the smallest result for the input string.
Greedy algorithm
while the last two is the same character { // the number of the same characters
find the last replaceable pair // at the tail will decrease until
reduce them // it become 1
}
while find the first replaceable pair
reduce them