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;
}
Related
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;
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. :)
bool isInt(string input) { //checks if string input is an int
if (input[0] == '-') { //checks if negative number
for (int a = 1; a < input.length(); a++) {
if (isdigit(input[a])) {
return true;
}
else {
return false;
}
}
}
for (int b = 0; b < input.length(); b++) {
if (isdigit(input[b])) {
return true;
} else {
return false;
}
}
}
So my code here is to check the string input the user enters and sees if its an integer. It works except cases where if the first character is either - or a number, but if thats followed by characters such as -23ab or -4b, my program won't catch that as an error as it isn't a valid number. I know the error is due to my return true/false statements, but I don't know of any method of how to fix it.
Any ideas?
It doesn't work at all!!
It only cares about the first character in the string because you return no matter the state of the character. You need to store a result in a variable and continue searching until the first failure.
You are returning true as soon as you see 1 digit. You should return true only if you make it to the end of the string w/o an error. You can return false early but for this problem, you should only return true at the end.
As others here said, you're only checking the first character and returning whether the first character is a digit or not....what you'll want to do instead is check if the character is a digit....if so then continue you on to the next digit. The only reason you'll return is if you either went through all the characters or if you found a non digit character.
for each character
if character is a digit
do nothing
else
return that it is false.
return true //you will only get to this statement if all characters are digits
This is what you have...
for each character
if character is a digit
return true
else
return false
So its basically returning before it checks the rest of the characters
Your code is trying too hard. You're testing for both success and failure rather than just looking for a fail case.
The following code takes a position index of 0, if the string isn't empty, it checks for a leading '-' and increments the index position to 1 if it finds that.
Then it simply checks through the string for a non-numeric character and fails if it finds one.
If it reaches the end of the string, then the string is all numeric.
bool isInt(const std::string& in)
{
size_t pos = 0;
if (!in.empty() && in[0] == '-')
pos = 1;
if (pos >= in.size()) // catch "" and "-"
return false;
do {
if (!isdigit(in[pos]))
return false;
} while (++pos < in.length());
return true;
}
This resolves your current problem but there is possible problem still: Is the string "123456789123456789" an int? It's too big to store in an int.
I attended a quiz, I gave the code but the auto-test shows that one of the eight test cases failed.
I myself tested my code many times, but all passed. I can't find where is the problem.
The question is to design a algorithm to check whether the brackets in a string match.
1) Just consider rounded brackets () and square brackets [], omit ohter chars.
2) Each pair brackets should match each other. That means ( matches ), and [ matches ].
3) Intercrossing is not allowed, such as : ([)]. There are two pairs of brackets, but they intercross each other.
To solve the problem, my method is described as follows:
Search each char in the whole input string, the index from 0 to str.size() - 1.
Use two stacks to record the opening tag (, and [, each type in one stack. When encountering one of them, push its index in the corresponding stack.
When encouterning the closing tag ) and ], we pop the corresponding stack.
Before popping, check the top of two stacks, the current stack should have the max index, otherwise that means there are unmatched opening tag with the other type, so the intercrossing can be checked this way.
My Code is Here:
#include <iostream>
#include <stack>
using namespace std;
int main()
{
string str;
cin >> str;
stack<int> s1, s2;
int result = 0;
for (int ix = 0, len = str.size(); ix < len; ix++)
{
if (str[ix] == '(')
{
s1.push(ix);
}
else if (str[ix] == '[')
{
s2.push(ix);
}
else if (str[ix] == ')')
{
if (s1.empty() || (!s2.empty() && s1.top() < s2.top()))
{
result = 1;
break;
}
s1.pop();
}
else if (str[ix] == ']')
{
if (s2.empty() || (!s1.empty() && s2.top() < s1.top()))
{
result = 1;
break;
}
s2.pop();
}
else
{
// do nothing
}
}
if (!s1.empty() || !s2.empty())
{
result = 1;
}
cout << result << endl;
}
As methoned before, this question can be solved by just on stack, so I modified my code, and here is the single stack version. [THE KEY POINT IS NOT TO ARGUE WHITCH IS BETTER, BUT WHAT'S WRONG WITH MY CODE.]
#include <iostream>
#include <stack>
using namespace std;
int main()
{
string str;
cin >> str;
stack<char> s;
const char *p = str.c_str();
int result = 0;
while (*p != '\0')
{
if (*p == '(' || *p == '[')
{
s.push(*p);
}
else if (*p == ')')
{
if (s.empty() || s.top() != '(')
{
result = 1;
break;
}
s.pop();
}
else if (*p == ']')
{
if (s.empty() || s.top() != '[')
{
result = 1;
break;
}
s.pop();
}
else
{
// do nothing
}
p++;
}
if (!s.empty())
{
result = 1;
}
cout << result << endl;
}
When using formatted input to read a std::string only the first word is read: after skipping leading whitespate a string is read until the first whitespace is encountered. As a result, the input ( ) should match but std::cin >> str would only read (. Thus, the input should probably look like this:
if (std::getline(std::cin, str)) {
// algorithm for matching parenthesis and brackets goes here
}
Using std::getline() still makes an assumption about how the input is presented, namely that it is on one line. If the algorithm should process the entire input from std::cin I would use
str.assign(std::istreambuf_iterator<char>(std::cin),
std::istreambuf_iterator<char>());
Although I think the algorithm is unnecessary complex (on stack storing the kind of parenthesis would suffice), I also think that it should work, i.e., the only problem I spotted is the way the input is obtained.
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