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 == ' ');
});
}
Related
This is what I have right now (str is a dynamic, null-terminating char array):
bool String::operator<(const String& rhs) const {
if (str == rhs.str)
return false;
int i = 0;
while (str[i] != '\0' && rhs[i] != '\0') {
if (str[i] > rhs[i])
return false;
++i;
}
return true;
}
This passes most tests, but it fails on:
String s1("abc");
String s2("abcde");
assert(!(s2 < s1));
No matter how I alter the function it always seem to fail one test or another. How would YOU overload this operator? Basically I just need to compare two null-terminating char arrays and see which one is the lesser (without any libraries).
You can take advantage of null-terminated strings to simplify the basic algorithm to:
While the nth character of both strings are the same (incrementing n starting with 0):
If the nth character of both strings is '\0' the strings are obviously the same, otherwise:
Otherwise, compare the nth characters as unsigned values, to determine the result of the comparison.
If you change your loop to:
int i = 0;
while (true) {
char l = str[i];
char r = rhs.str[i++];
if( l < r ) return true;
if( l == 0 || l > r ) return false;
}
it should work. Note if you need to handle national alphabets properly, that usually has values > 127, you need to change l and r type to unsigned char
But easier solution would be:
return strcmp( str, rhs.str ) < 0;
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;
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.
#include <iostream>
using namespace std;
Int main() {
cout<<"Give me a letter" <<endl;
char letter;
cin>>letter;
cout<<letter;
(Int)letter;
letter+=2;
cout<<(char)letter;
(Int)letter;
letter-=25;
cout<<(char)letter;
return 0;
}
How would I manipulate the numbers in a way so that the numbers will always output a letter.
ie: if the letter z was chosen and adding 2 is a symbol how would I manipulate it in a way so that it will always stay between the numbers for capital numbers and uncapitalized numbers. Thanks. Please try to keep answers at a beginner level please I am new to this.
if(letter > 'z') {
//do stuff
}
if(letter < 'a' && letter > 'Z') {
//do stuff
}
if(letter < 'A') {
//do stuff
}
It just depends on how you want to handle the character when it goes into one of the three ranges on the ASCII chart in which the characters are not letters.
As a side note, you don't have to cast a char to an int to do math with it.
char myChar = 'a' + 2;
cout << myChar;
This will print: c
c has an ASCII value of 2 more than a.
The surest method is to use a table for each category, and do
your arithmetic on its index, modulo the size of the table.
Thus, for just lower case letters, you might do something like:
char
transcode( char original )
{
char results = original;
static std::string const lower( "abcdefghijklmnopqrstuvwxyz" );
auto pos = std::find( lower.begin(), lower.end(), results );
if ( pos != lower.end() ) {
int index = pos - lower.begin();
index = (index + 2) % lower.size();
results = lower[ index ];
}
return results;
}
This solution is general, and will work regardless of the sets
of letters you want to deal with. For digits (and for upper and
lower case, if you aren't too worried about portability), you
can take advantage of the fact that the code points are
contiguous, and do something like:
char
transcode( char original )
{
char results = original;
if ( results >= '0' && results <= '9' ) {
char tmp = results - '0'
tmp = (tmp + 2) % 10;
results = tmp + '0';
}
return results;
}
An alternative implementation would be to use something like:
results = results + 2;
if ( results > '9' ) {
results -= 10;
}
in the if above. These two solutions are mathematically
equivalent.
This is only guaranteed to work for digits, but will generally
work for upper or lower case if you limit yourself to the
original ASCII character set. (Be aware that most systems today
support extended character sets.)
You can test directly against ASCII chars by using 'x' notation. Further, you can test things together using && ("and" respectively"):
if ('a' <= letter && letter <= 'z') {
// Letter is between 'a' and 'z'
} else if ('A' <= letter && letter <= 'Z')) {
// Letter is between 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}
Or you can use the standard library function std::isalpha which handles this for you:
if (std::isalpha(letter)) {
// Letter is between 'a' and 'z' or 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}
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