i already studied c++ in school and during the last days i have been doing the beginner c++ course of codecademy. On codecademy there is an exercise in which i have to identify palindrome words and return true or false. I haven't been able to resolve it so i saw the solution and it was:
#include <iostream>
// Define is_palindrome() here:
bool is_palindrome(std::string text) {
std::string reversed_text = "";
for (int i = text.size() - 1; i >= 0; i--) {
reversed_text += text[i];
}
if (reversed_text == text) {
return true;
}
return false;
}
int main() {
std::cout << is_palindrome("madam") << "\n";
std::cout << is_palindrome("ada") << "\n";
std::cout << is_palindrome("lovelace") << "\n";
}
My only doubt is with this line:
for (int i = text.size() - 1; i >= 0; i--) {
reversed_text += text[i];
i know it has to do with index values but i can't understand why it has a -1.
Could somebody explain this to me?
i thanks in advance whoever read this post. i'm sorry for my english or my poor using of stacksoverflow, i'm italian and that's my first time using this site.
for (int i = text.size() - 1; i >= 0; i--) {
reversed_text += text[i];
text is basically the string that you receive as input via function. size() is function that returns the size of the string i.e text.size() so in our test cases it will return
5 for madam
3 for ada
8 for lovelace
If you think about the strings as an array with exact above size then the index range will become
0-4 for madam
0-2 for ada
0-7 for lovelace
So that's why the text.size()-1 is using as the starting index of loop. text.size() will return the actual size of string and then minus 1 to get the index of last character in string.
so behind the scene, your loop iteration will look something like below
for (int i = 4; i >= 0; i--) { //for madam
}
//aca
for (int i = 2; i >= 0; i--) {
}
//lovelace
for (int i = 7; i >= 0; i--) {
}
I hope it clear out your confusion.
Thanks,
i know it has to do with index values but i can't understand why it has a -1.
If a string is n characters long, the characters in it are indexed from 0 to n−1.
Since the loop works with characters from the end of the string to the beginning, it starts with index text.size() - 1.
However, the solution you have shown is nominally inefficient. There is no reason to make a reversed copy of the string. It suffices merely to test whether each character in the first half of the string equals the character in the reflected position:
bool is_palindrome(std::string text)
{
size_t e = text.size();
for (int i = 0; i < e/2; ++i)
if (text[i] != text[e-1-i])
return false;
return true;
}
If using a for loop to reverse the string is confusing, you could also use the reverse function
std::string reversed_text = text;
reverse(reversed_text.begin(),reversed_text.end());
which just helps flip the entire string reversed_text and can achieve the same result in a simpler way.
I'm taking my first cs course and I'm currently learning the different ways to validate numerical inputs. Below is a bool function I wrote to check comma positions, but when I enter 65,000 it thinks the comma is in the wrong place.
bool commas(string input) {
bool commas = true;
long len = input.length();
int counter = 0;
for(int z = len-1; z >= 0; --z) {
if(counter == 3) {
if(input[z] != ',') {
commas = false;
counter = 0;
}
}
else {
if(input[z] == ',') {
commas = false;
}
else {
++counter;
}
}
}
return commas;
}
The easiest way to figure out if the comma is in the correction position is to go backwards (starting from the rightmost character) within the string.
The reason why this is easier is that if you were to start from the leftmost character and go forward, when you encounter a ,, you don't really know at that point whether that comma is in a valid position. You will only know until later on within the iteration process.
On the other hand, when you go from right-to-left, you know that if you encounter a comma, that comma is in a valid position -- there is no need to wait until you've gone further in the string to determine if the comma is valid.
To do this, it takes an adjustment in the loop to go backwards, and an additional counter to track the current group of 3 digits, since a comma can only occur after a group of 3 digits has been processed.
This is an untested example (except for the simple tests in main):
#include <string>
#include <cctype>
#include <iostream>
bool commas(std::string input)
{
// if the string is empty, return false
if (input.empty())
return false;
// this keeps count of the digit grouping
int counter = 0;
// loop backwards
for (int z = static_cast<int>(input.size()) - 1; z >= 0; --z)
{
// check if the current character is a comma, and if it is in
// position where commas are supposed to be
if (counter == 3)
{
if (input[z] != ',')
return false;
// reset counter to 0 and process next three digits
counter = 0;
}
else
// this must be a digit, else error
if (input[z] == ',')
return false;
else
// go to next digit in group of 3
++counter;
}
// the first character must be a digit.
return isdigit(static_cast<unsigned char>(input[0]));
}
int main()
{
std::string tests[] = { "123,,345",
"123,345",
"123,345,678",
"12,345",
"1223,345",
",123,345",
"1",
"",
"65,00",
"123"};
const int nTests = sizeof(tests) / sizeof(tests[0]);
for (int i = 0; i < nTests; ++i)
std::cout << tests[i] << ": " << (commas(tests[i]) ? "good" : "no good") << "\n";
}
Output:
123,,345: no good
123,345: good
123,345,678: good
12,345: good
1223,345: no good
,123,345: no good
1: good
: no good
65,00: no good
123: good
The way this works is simple -- we just increment a counter and see if the current position we're looking at (position z) in the string is a position where a comma must exist.
The count simply counts each group of 3 digits -- when that group of 3 digits has been processed, then the next character (when going backwards) must be a comma, otherwise the string is invalid. We also check if the current position is where a comma cannot be placed.
Note that at the end, we need to check for invalid input like this:
,123
This is simply done by inspecting the first character in the string, and ensuring it is a digit.
This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 3 years ago.
I am trying to create an email validation program without using the regex library. In one of my functions, I want to return a Boolean to check if there is an # sign in the email address and also if it is in a valid position (the # sign cannot be one of the first three characters of the string). However I am having problems with it because every time I run the program by entering in an email address with the # sign in an invalid position, it keeps telling me that the email is valid. Please help!
valid = checkEmail(email); //function call
if(valid == true)
cout << "Your email is valid!" << endl;
else
cout << "Your email is invalid!" << endl;
bool checkEmail(string email)
{
int counter;
int length;
bool firstThree; //checks to make sure # is not in the first three chars
counter = 0;
length = email.length();
firstThree = false;
for(int i = 0; i < length; i++)
{
if(email[i] == '#')
counter++;
}
for(int y = 0; y < length; y++)
{
if(email[0] == '#' || email[1] == '#' || email[2] == '#')
firstThree = true;
else
firstThree = false;
}
cout << "\n" << counter << endl; //check to see if counter works
if(counter != 1 && firstThree == true)
return false;
else
return true;
}
I guess you need to define the function bool checkEmail(string email) at the begining of the program. Basically flip if else and the function definition.
bool checkEmail(string email)
{
int counter;
int length;
bool firstThree; //checks to make sure # is not in the first three chars
counter = 0;
length = email.length();
firstThree = false;
for(int i = 0; i < length; i++)
{
if(email[i] == '#')
counter++;
}
for(int y = 0; y < length; y++)
{
if(email[0] == '#' || email[1] == '#' || email[2] == '#')
firstThree = true;
else
firstThree = false;
}
valid = checkEmail(email); //function call
if(valid == true)
cout << "Your email is valid!" << endl;
else
cout << "Your email is invalid!" << endl;
There seem to be a lot of beginner mistakes here, so I suggest learning the basics of programming and c++ first and like others suggested, use a debugger. Here are some of the mistakes:
Function definition
c++ is not like other common languages in the sense that functions need to be defined before they can be used. This means that you either need to move your checkEmail function above the function call, or create a separate definition above the function call like:
bool checkemail(string email);
as an exmaple.
Incorrect if-statement logic; Unnecessary for loop:
I'm assuming that based on how emails are formatted, you want the checkEmail function to return false if it doesn't match the correct formatting, and based on what your function currently does, that means that it will return false if the first three characters are # or if there isn't exactly one # symbol in the email. However, you used a && operator, which signifies and, meaning it will return true even when you don't want it to (much like how #Yastanub stated in his first comment). Better yet, that entire logic and if statement can be simplified greatly using std::string::find with a while loop and a vector (similar to this method):
vector<size_t> posVec;
size_t pos = email.find('#', 0); //note that this can be an int instead of size_t, but it can cause stack overflow with bigger numbers
while(pos != string::npos){
posVec.push_back(pos);
pos = email.find('#', pos+1);
}
switch(posVec.size()){
//if there is only one # symbol found
case 1:
bool firstThree = false;
for(int i = 0; i <= 2; i++)
//if there is only one # but it's in the first 3 positions, the email isn't valid
if(posVec[0] == i)
firstThree = true;
return !firstThree;
//otherwise the email doesn't work
default:
return false;
}
Remember to include the required libraries in order for this part to work:
#include <string>
#include <vector>
This also eliminates the second for loop in your function that is useless because the variable y is not being used, and the counter that was being used for testing
Another note
Using if (valid == true) is unnecessary as well. You can just use if (valid) because of how booleans work with if-statements.
Given a string S.We need to tell if we can make it to palindrome by removing exactly one letter from it or not.
I have a O(N^2) approach by modifying Edit Distance method.Is their any better way ?
My Approach :
int ModifiedEditDistance(const string& a, const string& b, int k) {
int i, j, n = a.size();
int dp[MAX][MAX];
memset(dp, 0x3f, sizeof dp);
for (i = 0 ; i < n; i++)
dp[i][0] = dp[0][i] = i;
for (i = 1; i <= n; i++) {
int from = max(1, i-k), to = min(i+k, n);
for (j = from; j <= to; j++) {
if (a[i-1] == b[j-1]) // same character
dp[i][j] = dp[i-1][j-1];
// note that we don't allow letter substitutions
dp[i][j] = min(dp[i][j], 1 + dp[i][j-1]); // delete character j
dp[i][j] = min(dp[i][j], 1 + dp[i-1][j]); // insert character i
}
}
return dp[n][n];
}
How to improve space complexity as max size of string can go upto 10^5.
Please help.
Example : Let String be abc then answer is "NO" and if string is "abbcbba then answer is "YES"
The key observation is that if the first and last characters are the same then you needn't remove either of them; which is to say that xSTRINGx can be turned into a palindrome by removing a single letter if and only if STRING can (as long as STRING is at least one character long).
You want to define a method (excuse the Java syntax--I'm not a C++ coder):
boolean canMakePalindrome(String s, int startIndex, int endIndex, int toRemove);
which determines whether the part of the string from startIndex to endIndex-1 can be made into a palindrome by removing toRemove characters.
When you consider canMakePalindrome(s, i, j, r), then you can define it in terms of smaller problems like this:
If j-i is 1 then return true; if it's 0 then return true if and only if r is 0. The point here is that a 1-character string is a palindrome regardless of whether you remove a character; a 0-length string is a palindrome, but can't be made into one by removing a character (because there aren't any to remove).
If s[i] and s[j-1] are the same, then it's the same answer as canMakePalindrome(s, i+1, j-1, r).
If they're different, then either s[i] or s[j-1] needs removing. If toRemove is zero, then return false, because you haven't got any characters left to remove. If toRemove is 1, then return true if either canMakePalindrome(s, i+1, j, 0) or canMakePalindrome(s, i, j-1, 0). This is because you're now testing whether it's already a palindrome if you remove one of those two characters.
Now this can be coded up pretty easily, I think.
If you wanted to allow for removal of more than one character, you'd use the same idea, but using dynamic programming. With only one character to remove, dynamic programming will reduce the constant factor, but won't reduce the asymptotic time complexity (linear in the length of the string).
Psudocode (Something like this I havn't tested it at all).
It is based on detecting the conditions that you CAN remove a character, ie
There is exactly 1 wrong character
It is a palendrome (0 mismatch)
O(n) in time, O(1) in space.
bool foo(const std::string& s)
{
int i = 0;
int j = s.size()-1;
int mismatch_count = 0;
while (i < j)
{
if (s[i]==s[j])
{
i++; j--;
}
else
{
mismatch_count++;
if (mismatch_count > 1) break;
//override first preference if cannot find match for next character
if (s[i+1] == s[j] && ((i+2 >= j-1)||s[i+2]==s[j-1]))
{
i++;
}
else if (s[j-1]==s[i])
{
j--;
}
else
{
mismatch_count++; break;
}
}
}
//can only be a palendrome if you remove a character if there is exactly one mismatch
//or if a palendrome
return (mismatch_count == 1) || (mismatch_count == 0);
}
Here's a (slightly incomplete) solution which takes O(n) time and O(1) space.
// returns index to remove to make a palindrome; string::npos if not possible
size_t willYouBeMyPal(const string& str)
{
size_t toRemove = string::npos;
size_t len = str.length();
for (size_t c1 = 0, c2 = len - 1; c1 < c2; ++c1, --c2) {
if (str[c1] != str[c2]) {
if (toRemove != string::npos) {
return string::npos;
}
bool canRemove1 = str[c1 + 1] == str[c2];
bool canRemove2 = str[c1] == str[c2 - 1];
if (canRemove1 && canRemove2) {
abort(); // TODO: handle the case where both conditions are true
} else if (canRemove1) {
toRemove = c1++;
} else if (canRemove2) {
toRemove = c2--;
} else {
return string::npos;
}
}
}
// if str is a palindrome already, remove the middle char and it still is
if (toRemove == string::npos) {
toRemove = len / 2;
}
return toRemove;
}
Left as an exercise is what to do if you get this:
abxyxcxyba
The correct solution is:
ab_yxcxyba
But you might be led down a bad path:
abxyxcx_ba
So when you find the "next" character on both sides is a possible solution, you need to evaluate both possibilities.
I wrote a sample with O(n) complexity that works for the tests I threw at it. Not many though :D
The idea behind it is to ignore the first and last letters if they are the same, deleting one of them if they are not, and reasoning what happens when the string is small enough. The same result could be archived with a loop instead of the recursion, which would save some space (making it O(1)), but it's harder to understand and more error prone IMO.
bool palindrome_by_1(const string& word, int start, int end, bool removed = false) // Start includes, end excludes
{
if (end - start == 2){
if (!removed)
return true;
return word[start] == word[end - 1];
}
if (end - start == 1)
return true;
if (word[start] == word[end - 1])
return palindrome_by_1(word, start + 1, end - 1, removed);
// After this point we need to remove a letter
if (removed)
return false;
// When two letters don't match, try to eliminate one of them
return palindrome_by_1(word, start + 1, end, true) || palindrome_by_1(word, start, end - 1, true);
}
Checking if a single string is palindrome is O(n). You can implement a similar algorithm than moves two pointers, one from the start and another from the end. Move each pointer as long as the chars are the same, and on the first mismatch try to match which char you can skip, and keep moving both pointers as long as the rest chars are the same. Keep track of the first mismatch. This is O(n).
I hope my algorithm will pass without providing code.
If a word a1a2....an can be made a palindrome by removing ak, we can search for k as following:
If a1 != an, then the only possible k would be 1 or n. Just check if a1a2....an-1 or a2a3....an is a palindrome.
If a1 == an, next step is solving the same problem for a2....an-1. So we have a recursion here.
public static boolean pal(String s,int start,int end){
if(end-start==1||end==start)
return true;
if(s.charAt(start)==s.charAt(end))
return pal(s.substring(start+1, end),0,end-2);
else{
StringBuilder sb=new StringBuilder(s);
sb.deleteCharAt(start);
String x=new String(sb);
if(x.equals(sb.reverse().toString()))
return true;
StringBuilder sb2=new StringBuilder(s);
sb2.deleteCharAt(end);
String x2=new String(sb2);
if(x2.equals(sb2.reverse().toString()))
return true;
}
return false;
}
I tried the following,f and b are the indices at which characters do not match
int canwemakepal(char *str)//str input string
{
long int f,b,len,i,j;
int retval=0;
len=strlen(str);
f=0;b=len-1;
while(str[f]==str[b] && f<b)//continue matching till we dont get a mismatch
{
f++;b--;
}
if(f>=b)//if the index variable cross over each other, str is palindrome,answer is yes
{
retval=1;//true
}
else if(str[f+1]==str[b])//we get a mismatch,so check if removing character at str[f] will give us a palindrome
{
i=f+2;j=b-1;
while(str[i]==str[j] && i<j)
{
i++;j--;
}
if(i>=j)
retval=1;
else
retval=0;
}
else if(str[f]==str[b-1])//else check the same for str[b]
{
i=f+1;j=b-2;
while(str[i]==str[j] && i<j)
{
i++;j--;
}
if(i>=j)
retval=1;
else
retval=0;
}
else
retval=0;
return retval;
}
I created this solution,i tried with various input giving correct result,still not accepted as correct solution,Check it n let me know if m doing anything wrong!! Thanks in advance.
public static void main(String[] args)
{
Scanner s = new Scanner(System.in);
int t = s.nextInt();
String result[] = new String[t];
short i = 0;
while(i < t)
{
String str1 = s.next();
int length = str1.length();
String str2 = reverseString(str1);
if(str1.equals(str2))
{
result[i] = "Yes";
}
else
{
if(length == 2)
{
result[i] = "Yes";
}
else
{
int x = 0,y = length-1;
int counter = 0;
while(x<y)
{
if(str1.charAt(x) == str1.charAt(y))
{
x++;
y--;
}
else
{
counter ++;
if(str1.charAt(x) == str1.charAt(y-1))
{
y--;
}
else if(str1.charAt(x+1) == str1.charAt(y))
{
x++;
}
else
{
counter ++;
break;
}
}
}
if(counter >= 2)
{
result[i] = "No";
}
else
result[i]="Yes";
}
}
i++;
} // Loop over
for(int j=0; j<i;j++)
{
System.out.println(result[j]);
}
}
public static String reverseString(String original)
{
int length = original.length();
String reverse = "";
for ( int i = length - 1 ; i >= 0 ; i-- )
reverse = reverse + original.charAt(i);
return reverse;
}
So i am implementing a BigNum Class to deal with large integers and am currently trying to fix my string constructor class. I have to be able to read Strings such as "-345231563567" in an array with the numbers being read in backwards (i.e. 765365132543). The first part of the code attached checks the first character to see if it is positive or negative and sets positive to true or false. The next part of the code checks for leading zeros in the number that may occur as well as if the number is zero itself. the last part is what is loading the number into the array and for some reason i can not get the code to work. any help with a solution is much appreciated.
BigNum::BigNum(const char strin[])
{
size_t size = strlen(strin);
positive = true;
used=0;
if(strin[0] == '+')
{
positive = true;
used++;
}
else if(strin[0] == '-')
{
positive = false;
used++;
}
else
{
positive = true;
}
// While loop that trims off the leading zeros
while (used < size)
{
if (strin[used] != '0')
{
break;
}
used++;
}
// For the case of the number having all zeros
if(used == size)
{
positive = true;
digits = new size_t[1];
capacity = 1;
digits[0] = 0;
used = 1;
}
// Reads in the digits of the number in reverse order
else
{
int index = 0;
digits = new size_t[DEFAULT_CAPACITY];
capacity = size - used;
while(used < size)
{
digits[index] = strin[size - 1] - '0';
index++;
size--;
}
used = index + 1;
}
}
The BigNum.h can be found here
http://csel.cs.colorado.edu/%7Eekwhite/CSCI2270Fall2011/hw2/revised/BigNum.h
and the Test file i am trying to use can be found here. I fail test 7
http://csel.cs.colorado.edu/%7Eekwhite/CSCI2270Fall2011/hw2/revised/TestBigNum.cxx
Seems like you allocate DEFAULT_CAPACITY bytes which you have defined as 20 and continue to put 22 digits in it.
I just tried to run your code and there seems to be a problem with the digit= line. It is a pointer that you are setting equal to a value. Might that be your problem?