While on SO someone posted this question and I gave it a quick try. My solution passed all the testcases.
Link to the problem: Problem: (A) Mike and palindrome
Question:
Mike has a string s consisting of only lowercase English letters. He wants to change exactly one character from the string so that the resulting one is a palindrome.
A palindrome is a string that reads the same backward as forward, for example strings "z", "aaa", "aba", "abccba" are palindromes, but strings "codeforces", "reality", "ab" are not.
Input
The first and single line contains string s (1 ≤ |s| ≤ 15).
Output
Print "YES" (without quotes) if Mike can change exactly one character so that the resulting string is palindrome or "NO" (without quotes) otherwise.
Examples
input: abccaa output: YES
input: abbcca output: NO
input: abcda output: YES
CODE
#include <string>
#include <iostream>
int main(){
std::string str;
std::cin >> str;
int i{0}, j{str.length() - 1}, cnt{0};
// Check from both the ends if characters are equal.
while(i < j){
if (str[i]!= str[j]) ++cnt;
++i;
--j;
}
// If there's one mismatch.
if ( cnt == 1 ) std::cout << "YES";
// Odd length string with 0 mismatches e.g: abcba, can change middle char.
else if ( cnt == 0 && str.length()&1 ) std::cout << "YES";
else std::cout << "NO";
}
1 Answer 1
Formatting: Don't be so stingy with the indentation, give your code some room to breathe!
Validating input: You should check if std::cin
was successful.
It is always good if you can split out complexities into functions. Your main
function does it all, read input, calc result, and write the output. I would suggest you created a separate function to determine if the string is a palindrome:
bool isPalindromeWithOneChange(const std::string& str) {
// ...
// ...
return cnt == 1 || (cnt == 0 && length % 2);
}
And change main
to the following:
int main() {
std::string str;
std::cin >> str;
if (std::cin.fail() || std::cin.bad()) {
std::cerr << "Input failure";
return 1;
}
if (isPalindromeWithOneChange(str))
std::cout << "YES";
else
std::cout << "NO";
}
Note that the underlying data type for array indexes and length is size_t
.
This is just personal preferences, but I find the following easier to read with the decleration on seperate lines:
const std::size_t length = str.length();
std::size_t i = 0;
std::size_t j = length - 1;
std::size_t cnt = 0;
With the decleration of length
you can replace this line:
else if ( cnt == 0 && str.length()&1 ) std::cout << "YES";
With the following
else if ( cnt == 0 && length % 2) std::cout << "YES";
You can break out of the while
loop as soon as cnt
is larger than one.
Final nitpicking / brain farts
Whether you use length & 1
or length % 2
is entirely up to you but one thing you lose with & 1
is the intention. You should write what you want your code to do and rely on the compiler to handle it correctly.
-
\$\begingroup\$ Any decent compiler will generate exactly the same code for
& 1
and% 2
if optimizations are turned on, at least if it can see thatlength
is an unsigned number. \$\endgroup\$G. Sliepen– G. Sliepen2021年10月18日 15:27:30 +00:00Commented Oct 18, 2021 at 15:27 -
\$\begingroup\$ @upkajdt Thank you for the review.
length&1
is a force of habit. \$\endgroup\$Ch3steR– Ch3steR2021年10月18日 16:24:51 +00:00Commented Oct 18, 2021 at 16:24 -
1\$\begingroup\$ @upkajdt Do you know why the formatting does not work correctly in the last paragraph? Apparently, If you put a newline after
<br>
it should work \$\endgroup\$Ch3steR– Ch3steR2021年10月18日 16:26:05 +00:00Commented Oct 18, 2021 at 16:26 -
\$\begingroup\$ @Ch3steR, thanks, that fixed it. I would suggest you have a look at codegolf.stackexchange.com if you like these sorts of challenges. \$\endgroup\$jdt– jdt2021年10月18日 16:47:29 +00:00Commented Oct 18, 2021 at 16:47
-
\$\begingroup\$ BTW: Nearly always, prefer
std::string_view
overstd::string const&
for parameter-type. The exception is if you might need zero-termination, or called code expects that exact type. \$\endgroup\$Deduplicator– Deduplicator2021年10月18日 16:50:08 +00:00Commented Oct 18, 2021 at 16:50