string removeNonAlphas(string original)
{
for(int i = 0; i < original.size(); ++i){
if(!(original[i] > 64 && original[i] < 91) &&
!(original[i] > 96 && original[i] < 124)){
original[i] = original[i] - original[i];
}
}
return original;
}
//test1.cpp
string test = "abc abc";
cout << removeNonAlphas(test) << endl; // output = "abcabc"
assert(removeNonAlphas(test) == "abcabc"); // assertion failed
//Why does assertion fail above? removeNonAlphas result("abcabc") is same as
//rhs "abcabc"
original[i] = original[i] - original[i];
What this makes is that it repaces the character with '\0' but does not remove it. Because of that the output is not "abcabc" but "abc\0abc". '\0' is non-printable so you won't see it in the output but it is present when you compare it with ==.
Instead of replacing charactes in a string, create a new string while iterating the old one:
string removeNonAlphas(string const& original)
{
std::string result;
for(char c : original)
if((c > 64 && c < 91) ||
(c > 96 && c < 124))
result.push_back(c);
return result;
}
Note: prefer using std::isalpha instead of hard-coded values.
Both values are NOT the same, but the difference is a non-printing character, so you can't see any difference with cout and your naked eye.
Try a proper tool, like a debugger, and you will see the extra \0 character present in the function result.
You're not actually erasing any characters from your string. You're just assigning them the value 0. It just looks like it works - which is just the worst. The '\0' is just a non-printable character, which is why it looks like it prints the same. The == will actually check every character, even the non-printable ones, so it'll catch what you can't see.
Thankfully, the string class makes it easy to erase characters by providing just such a member function:
original.erase(i, 1); // erase a single character starting at i
Now that alone isn't enough. You erase a character, and now i is "pointing" to the next element - but you won't check it. If we had "abc12abc", after erasing the 1, we'd skip the 2. So we need to change how we iterate:
for (std::string::iterator it = original.begin();
it != original.end();
/* nothing */)
{
// here's a better way to do checking
if (!(*it >= 'A' && *it <= 'Z') &&
!(*it >= 'a' && *it <= 'z'))
{
// erase(iterator ) will return the next iterator
it = original.erase(it);
}
else
{
++it;
}
}
That'll work. It's also very verbose. And error-prone. Which is why we have the erase-remove idiom:
original.erase(
std::remove_if(original.begin(),
original.end(),
[](char c) { return !std::isalpha(c); }),
original.end()
);
return original;
Related
https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/
In this Leetcode question, I tried to do it without using the concept of a stack. But according to the answer, I get the loop is not getting completed, why is that the case here?
class Solution {
public:
string removeDuplicates(string s) {
for (int i = 0; i<s.length(); i++) {
if(s[i] == s[i+1]){
s.erase(i,2);
i=0;
}
}
return s;
}
};
This is the error I am getting:
Your loop boundary, i < s.length(), is wrong since it'll let s[i + 1] access the string out of bounds*.
You need to reset i when a match is found, which you do, but it's followed by i++ directly, so it will never find a match at s[0] == s[1] again.
Fixed:
string removeDuplicates(string s) {
for (unsigned i = 0; i + 1 < s.length();) { // corrected loop bounds
if (s[i] == s[i + 1]) {
s.erase(i, 2);
i = 0;
} else ++i; // only add 1 if no match is found
}
return s;
}
* The out of bounds access will really access the terminating \0 (since C++11, undefined behavior before that), but it's unnecessary since you can't erase it anyway.
A somewhat quicker version would be to not reset i to 0, but to continue searching at the current position. You may also use std::adjacent_find to simplify the algorithm:
string removeDuplicates(string s) {
for(auto it = s.begin(); (it = std::adjacent_find(it, s.end())) != s.end();) {
it = s.erase(it, it + 2);
if(it != s.begin()) --it;
}
return s;
}
The main problem of this for loop
for (int i = 0; i<s.length(); i++) {
if(s[i] == s[i+1]){
s.erase(i,2);
i=0;
}
}
is that after erasing two adjacent elements the variable i is set to 0 within the if statement and then at once is incremented in the for statement. So in the next iteration of the loop the variable i is equal to 1.
Consider the following string
"abba'
after erasing "bb" the string becomes equal to "aa" but after that the variable i is equal to 1 and in the next iteration of the loop you are comparing s[1] and s[2] that are 'a' and '\0'.
Rewrite the loop at least the following way
for ( std::string::size_type i = 0; i < s.length(); )
{
if ( s[i] == s[i+1] )
{
s.erase(i,2);
i=0;
}
else
{
++i;
}
}
Pay attention to that according to the C++ Standard s[s.length()] is equal to '\0'. So you may use the comparison s[i] == s[i+1]. According to the assignment in the provided link the string contains only low case letters.
My target is to validate c++ input that it will hold only small and capital letters and empty space. Can I do that without for loop? My current code is:
bool validateInput()
char c;
string result;
cin >> result;
for (int i = 0; i < result.length(); i++) {
c = result.at(i);
if ( !( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == ' ' ) )
{
return false;
}
}
}
You can do it without a for loop, although you'll obviously still need to use a loop, I guess the modern C++ way would be to use std::find_if , ( you can also use std::none_of as pointed out by #NathanOliver which wraps std::find_if and returns a boolean instead of an iterator ). It's also probably a good idea to use std::isalpha, partly because a character set might not have alphabetical characters mapped to decimal values in order, and partly because it is easier to write :-)
bool validateInput()
{
std::string result;
std::cin >> result;
return std::none_of(result.begin(), result.end(), [](const char& c)
{
return !(std::isalpha(c) || c == ' ');
});
}
I want to check if a string contains any characters other than 0-9 or A-Z and if it does, stop the program. This is what I did:
string number_in;
for (int i = 0; number_in[i] == '\0'; i++)
{
if ( (number_in[i] < 48) || ( (number_in[i] > 57) && (number_in[i] < 65) ) || (number_in[i] > 90) )
{
cout << "\nInput number contains incorrect characters!\n";
getchar;
return 0;
}
}
But whichever string I would enter, it always skips the for loop. Why is that so?
number_in[i] == '\0' seems to be incorrect. It is the condition for the loop to continue to run.
However, there is an easier solution using std::isalnum and std::all_of:
bool stopProgramm = !std::all_of( std::begin(str), std::end(str),
[] (unsigned char c)
{ return std::isdigit(c) || std::isupper(c); } );
number_in[i] == '\0' should be number_in[i] != '\0'. The for loop to runs while the condition is true.
You should do:
#include <cctype>
// ...
char const c = number_in[i];
if ( !(isascii(c) && (isdigit(c) || isupper(c))) ) {
// ...
}
Strictly speaking, isascii(c) isn't needed, but, if you want to be cross-platform, the other is*() functions break on Windows if c isn't ASCII.
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.
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