I found this question on Hackerrank where I have to write a method to say whether or not a given string is a pangram. A sentence is a pangram if it contains all 26 letters of the alphabet. The input will only contain characters that are alphabetical (uppercase or lowercase) and spaces.
Here's the code I've gotten so far, where I use a set to keep track of which letters are present in the string. However, the code just keeps running infinitely in the while loop below.
string pangrams(string s) {
set<char> set{};
int i=0;
while (i!=s.length()) {
if(s[i]!='\0') {
set.insert(tolower(s[i]));
}
}
if (set.size() == 27) {
return "pangram";
} else {
return "not pangram";
}
}
Your function needs a slight modification. Firstly, you aren't incrementing i which makes your function go into infinite loop. Other modification is explained in code below -
string pangrams(string s) {
set<char> set{};
int i=0;
while (i!=s.length()) {
if(s[i]!=' ') { # if character is space, ignore it
set.insert(tolower(s[i]));
}
i++; # Main reason of runtime error - you missed incrementing i
}
if (set.size() == 26) { # 26 and not 27. There may be strings without space that are pangrams. So we wont add space into our set.
return "pangram";
} else {
return "not pangram";
}
}
Also, you don't need to check s[i]!='\0' since a c++ string isn't terminated with \0 character. Only checking i!=s.length() will be enough.
Hope this clears your issue !
You're never incrementing i, so your code will run infinitely. I would recommend a for loop for (int i = 0; i < s.length(); i ++) or a for-each loop for (char c : s)
Instead of using a set, you could also try this, where each character corresponds to an index in a bool[]
bool exists[27];
for (char c : s) {
if ('a' <= c && c <= 'z') {
exists[c - 'a'] = true;
} else if ('A' <= c && c <= 'A') {
exists[c - 'A'] = true;
} else if (c == ' ') {
exists[26] = true;
}
}
for (bool b : exists) {
if (!b) return false;
}
return true;
Related
Here is the question:
A bracket sequence is called regular if it is possible to obtain correct arithmetic expression by inserting characters + and 1 into this sequence. For example, sequences (())(), () and (()(())) are regular, while )(, (() and (()))( are not. Let's call a regular bracket sequence "RBS".
You are given a sequence s of n characters (, ), and/or ?. There is exactly one character ( and exactly one character ) in this sequence.
You have to replace every character ? with either ) or ( (different characters ? can be replaced with different brackets). You cannot reorder the characters, remove them, insert other characters, and each ? must be replaced.
Determine if it is possible to obtain an balanced sequence or not after these replacements.
EX:
5
()
(?)
(??)
??()
)?(?
Output:
YES
NO
YES
YES
NO
Here is my code:
#include <bits/stdc++.h>
using namespace std;
bool checkValidString(string s) {
stack<char>st;
for(int i=0;i<s.length();i++)
{
if(!st.empty() && (((st.top() == '(') && s[i] == '?') || ((st.top() == '?') && s[i] == ')') || st.top() == '(' && s[i] == ')'))
{
st.pop();
}
else
{
st.push(s[i]);
}
}
if(st.empty())
{
return true;
}
int si = st.size();
bool odd = false;
if(si%2!=0)
{
odd = true;
}
while(!st.empty())
{
char c = st.top();
if(c!='?')
{
return false;
}
st.pop();
}
if(odd)
{
return false;
}
return true;
}
int main() {
// your code goes here
int n;
cin>>n;
while(n--)
{
string s;
cin>>s;
bool ans = checkValidString(s);
if(ans == 1)
{
cout<<"YES"<<endl;
}
else
{
cout<<"NO"<<endl;
}
}
return 0;
}
However it is giving wrong answer,Can you help where I am going wrong?Thanks.
This kind of problem won't work by the logic for checking valid parenthesis.
Example: The test case where input string = (?)? will fail in your case. But it is a valid string as it can take the form (()).
So now, how do you approach such a problem?
Let's figure out what are all the possible input strings can look like.
Test Cases:
If number if question marks are odd, then it's an invalid string.
If Opening bracket appears before closing one, and we have odd number of question marks between them:
(???)? or ?(???) => Both are valid strings, as they can take the form ((())).
If Opening bracket appears before closing one, and we have even number of question marks between them:
(????) or ??(??)?? => These kind of strings are always valid.
If Opening parenthesis comes closing parenthesis:
?)(? => This string is also valid as it can take the from ()().
The only thing we need to worry about is if ) is the first position or ( is at the last position:
)??( => Always an invalid string.
)?(? => Always an invalid string.
?)?( => Always an invalid string.
Therefore, the problem gets simplified to 3 main conditions:
The length of the string should be even: For this to be true, the number of ? characters in the string should be even.
The string should not start with ).
The string should not end with (.
Have a look at the following code which has Accepted status on Codeforces:
#include <iostream>
#include <string>
int main(){
int t;
scanf("%d", &t);
while(t--){
std::string s;
std::cin>>s;
int len = s.length();
int countQuestion = 0;
for(int i=0;i<len;i++){
if(s[i]=='?'){
countQuestion++;
}
}
//Check 1: If question count is even?
if(countQuestion & 1){
printf("NO\n");
}else{
if(s[0] == ')' || s[len-1] == '('){
printf("NO\n");
}else{
printf("YES\n");
}
}
}
return 0;
}
Verdict:
If you wanted to check a string of brackets to see if it was valid, you'd keep a counter of open brackets as you walk through the string. You'd start it at 0, increment it for every ( and decrement it for every ). You'd check to make sure that it never goes negative and that it ends at 0.
If some of the brackets are replaced by question marks, you can imagine doing the same thing, but at every position you can calculate all the possible non-negative values of the counter. If that set of values ever goes empty, then a valid bracket string is impossible. If that set doesn't include 0, then a valid bracket string is impossible.
It turns out (and you can prove by induction), that the set of possible values always includes every 2nd number between two numbers x and y.
After ?, [x,y] -> [x-1,y+1], excluding numbers < 0
After (, [x,y] -> [x+1,y+1]
After ), [x,y] -> [x-1,y-1], excluding numbers < 0
So you can test any sequence of brackets and question marks by running through the string, starting with [0,0] and modifying the range according to the above rules for each character. Make sure it never goes empty and includes 0 at the end.
bool checkValidString(string s) {
int l=0, h=0;
for(int i=0;i<s.length();i++) {
switch(s[i]) {
case '(':
++l;++h;
break;
case ')':
if (h<=0) {
return false;
}
--h;
l += (l>0 ? -1:1);
break;
default:
++h;
l += (l>0 ? -1:1);
break;
}
}
return l==0;
}
I'm programming a hash table thing in C++, but this specific piece of code will not run properly. It should return a string of alpha characters and ' and -, but I get cases like "t" instead of "art" when I try to input "'aRT-*".
isWordChar() return a bool value depending on whether the input is a valid word character or not using isAlpha()
// Words cannot contain any digits, or special characters EXCEPT for
// hyphens (-) and apostrophes (') that occur in the middle of a
// valid word (the first and last characters of a word must be an alpha
// character). All upper case characters in the word should be convertd
// to lower case.
// For example, "can't" and "good-hearted" are considered valid words.
// "12mOnkEYs-$" will be converted to "monkeys".
// "Pa55ive" will be stripped "paive".
std::string WordCount::makeValidWord(std::string word) {
if (word.size() == 0) {
return word;
}
string r = "";
string in = "";
size_t incr = 0;
size_t decr = word.size() - 1;
while (incr < word.size() && !isWordChar(word.at(incr))) {
incr++;
}
while (0 < decr && !isWordChar(word.at(decr))) {
decr--;
}
if (incr > decr) {
return r;
}
while (incr <= decr) {
if (isWordChar(word.at(incr)) || word.at(incr) == '-' || word.at(incr) == '\'') {
in =+ word.at(incr);
}
incr++;
}
for (size_t i = 0; i < in.size(); i++) {
r += tolower(in.at(i));
}
return r;
}
Assuming you can use standard algorithms its better to rewrite your function using them. This achieves 2 goals:
code is more readable, since using algorithms shows intent along with code itself
there is less chance to make error
So it should be something like this:
std::string WordCount::makeValidWord(std::string word) {
auto first = std::find_if(word.cbegin(), word.cend(), isWordChar);
auto last = std::find_if(word.crbegin(), word.crend(), isWordChar);
std::string i;
std::copy_if(first, std::next(last), std::back_inserter(i), [](char c) {
return isWordChar(c) || c == '-' || c == '\'';
});
std::string r;
std::transform(i.cbegin(), i.cend(), std::back_inserter(r), std::tolower);
return r;
}
I am going to echo #Someprogrammerdude and say: Learn to use a debugger!
I pasted your code into Visual Studio (changed isWordChar() to isalpha()), and stepped it through with the debugger. Then it was pretty trivial to notice this happening:
First loop of while (incr <= decr) {:
Second loop:
Ooh, look at that; the variable in does not update correctly - instead of collecting a string of the correct characters it only holds the last one. How can that be?
in =+ word.at(incr); Hey, that is not right, that operator should be +=.
Many errors are that easy and effortless to find and correct if you use a debugger. Pick one up today. :)
Let a word be defined as any string of consecutive alphanumerics. Words are parsed by any non alphanumeric. Ex.
"Hi my 1st name#is#Kevin :)"
output: 6
I know would could simply go through the string using a for loop but what would be the most efficient way to return the right output using the full extent of the c++ 11 library?
My current iteration:
int findWords(string line) {
regex AN("[[:alnum:]]");
int count = 0;
bool state = false;
for (char c : line) {
string s(1, c);
bool match = regex_match(s, AN);
if (match && !state) {
state = true;
}
else if (!match && state) {
count++;
state = false;
}
else {
continue;
}
}
if (state == true) { //won't count last word otherwise
count++;
}
return count;
}
To my knowledge there is no specific function in c++ library that counts words consisting solely of alphanumerics. For example, an istream::iterator in conjunction with distance would count "words" separated by white spaces, but would count he is aged 45 as 4 words. One could also think of strtok or regular expressions, but the overhead would be much (much) more than a simple loop. So try, for example, the following. Unless you use this method billion times during program execution, it should perform good enough. If not, let me know :-).
Here you go:
#include <iostream>
int main()
{
string line = "Hi my 1st name#is#Kevin :)";
bool isInAlphaMode = false;
int count = 0;
const char* str = line.c_str();
while (char c = *str) {
if (isalpha(c) && !isInAlphaMode) {
count++;
isInAlphaMode = true;
}
else if (!isalpha(c) && isInAlphaMode) {
isInAlphaMode = false;
}
str++;
}
printf("string '%s' contains %d words", line.c_str(), count);
// output: string 'Hi my 1st name#is#Kevin :)' contains 6 words
return 0;
}
I wrote a function in c++ to remove parenthesis from a string, but it doesn't always catch them all for some reason that I'm sure is really simple.
string sanitize(string word)
{
int i = 0;
while(i < word.size())
{
if(word[i] == '(' || word[i] == ')')
{
word.erase(i,1);
}
i++;
}
return word;
}
Sample result:
Input: ((3)8)8)8)8))7
Output: (38888)7
Why is this? I can get around the problem by calling the function on the output (so running the string through twice), but that is clearly not "good" programming. Thanks!
if(word[i] == '(' || word[i] == ')')
{
word.erase(i,1);
}
i++;
If you erase a parenthesis, the next character moves to the index previously occupied by the parenthesis, so it is not checked. Use an else.
if(word[i] == '(' || word[i] == ')')
{
word.erase(i,1);
} else {
i++;
}
while(i < word.size())
{
if(word[i] == '(' || word[i] == ')')
{
word.erase(i,1);
}
i++;
}
When you remove an element the next element is moved to that location. If you want to test it, you will have to avoid incrementing the counter:
while (i < word.size()) {
if (word[i] == '(' || word[i] == ')' ) {
word.erase(i,1);
} else {
++i;
}
}
That can also be done with iterators, but either option is bad. For each parenthesis in the string, all elements that are after it will be copied, which means that your function has quadratic complexity: O(N^2). A much better solution is use the erase-remove idiom:
s.erase( std::remove_if(s.begin(), s.end(),
[](char ch){ return ch==`(` || ch ==`)`; })
s.end() );
If your compiler does not have support for lambdas you can implement the check as a function object (functor). This algorithm has linear complexity O(N) as the elements that are not removed are copied only once to the final location.
It's failing because your incrementing the index in all cases. You should only do that if you're not deleting the character, since the deletion shifts all the characters beyond that point back by one.
In other words, you'll have this problem wherever you have two or more consecutive characters to delete. Rather than deleting them both, it "collapses" the two into one.
Running it through your function twice will work on that particular input string but you'll still get into trouble with something like "((((pax))))" since the first call will collapse it to "((pax))" and the second will give you "(pax)".
One solution is to not advance the index when deleting a character:
std::string sanitize (std::string word) {
int i = 0;
while (i < word.size()) {
if(word[i] == '(' || word[i] == ')') {
word.erase(i,1);
continue;
}
i++;
}
return word;
}
However, I'd be using the facilities of the language a little more intelligently. C++ strings already have the capability to search for a selection of characters, one that's possibly far more optimised than a user loop. So you can use a much simpler approach:
std::string sanitize (std::string word) {
int spos = 0;
while ((spos = word.find_first_of ("()", spos)) != std::string::npos)
word.erase (spos, 1);
return word;
}
You can see this in action in the following complete program:
#include <iostream>
#include <string>
std::string sanitize (std::string word) {
int i = 0;
while ((i = word.find_first_of ("()", i)) != std::string::npos)
word.erase (i, 1);
return word;
}
int main (void) {
std::string s = "((3)8)8)8)8))7 ((((pax))))";
s = sanitize (s);
std::cout << s << '\n';
return 0;
}
which outputs:
388887 pax
Why not just use strtok and a temporary string?
string sanitize(string word)
{
int i = 0;
string rVal;
char * temp;
strtok(word.c_str(), "()"); //I make the assumption that your values should always start with a (
do
{
temp = strtok(0, "()");
if(temp == 0)
{
break;
}
else { rVal += temp;}
}while(1);
return rVal;
}
This is the requirement: Read a string and loop it, whenever a new word is encountered insert it into std::list. If the . character has a space, tab, newline or digit on the left and a digit on the right then it is treated as a decimal point and thus part of a word. Otherwise it is treated as a full stop and a word separator.
And this is the result I run from the template program:
foo.bar -> 2 words (foo, bar)
f5.5f -> 1 word
.4.5.6.5 -> 1 word
d.4.5f -> 3 words (d, 4, 5f)
.5.6..6.... -> 2 words (.5.6, 6)
It seems very complex for me in first time dealing with string c++. Im really stuck to implement the code. Could anyone suggest me a hint ? Thanks
I just did some scratch ideas
bool isDecimal(std::string &word) {
bool ok = false;
for (unsigned int i = 0; i < word.size(); i++) {
if (word[i] == '.') {
if ((std::isdigit(word[(int)i - 1]) ||
std::isspace(word[(int)i -1]) ||
(int)(i - 1) == (int)(word.size() - 1)) && std::isdigit(word[i + 1]))
ok = true;
else {
ok = false;
break;
}
}
}
return ok;
}
void checkDecimal(std::string &word) {
if (!isDecimal(word)) {
std::string temp = word;
word.clear();
for (unsigned int i = 0; i < temp.size(); i++) {
if (temp[i] != '.')
word += temp[i];
else {
if (std::isalpha(temp[i + 1]) || std::isdigit(temp[i + 1]))
word += ' ';
}
}
}
trimLeft(word);
}
I think you may be approaching the problem from the wrong direction. It seems much easier if you turn the condition upside down. To give you some pointers in a pseudocode skeleton:
bool isSeparator(const std::string& string, size_t position)
{
// Determine whether the character at <position> in <string> is a word separator
}
void tokenizeString(const std::string& string, std::list& wordList)
{
// for every character in string
// if(isSeparator(character) || end of string)
// list.push_back(substring from last separator to this one)
}
I suggest to implement it using flex and bison with c++ implementation