pattern matching (codejam round 1A previous year) solution not working - c++

I am trying previous year's codejam question of round 1A
link to question
i have submitted this code(start reading from main method, for ease)-
#include <bits/stdc++.h>
using namespace std;
#define range(t) for (int i = 0; i < t; i++)
#define rangeG(i, t) for (i = 0; i < t; i++)
#define printVec(vec) \
for (auto c : vec) \
{ \
cout << c << endl; \
}
vector<string> separate(string s)
{
vector<string> result;
range(s.size())
{
if (s[i] == '*')
{
string temp = s.substr(0, i + 1);
if (temp.size() > 1)
{
result.push_back(temp);
}
s = s.substr(i, s.size());
i = 0;
}
else if (i == (s.size() - 1))
{
string temp = s.substr(0, i + 1);
result.push_back(temp);
s = s.substr(i, s.size());
}
}
return result;
}
void removeAsterisk(string &s)
{
s.erase(remove(s.begin(), s.end(), '*'), s.end());
}
bool setStart(string s, string &start)
{
bool possible = 1;
removeAsterisk(s);
range(min(s.size(), start.size()))
{
if (s[i] != start[i])
{
possible = 0;
}
}
if (possible)
{
if (s.size() >= start.size())
{
start = s;
}
}
return possible;
}
bool setEnd(string s, string &end)
{
bool possible = 1;
removeAsterisk(s);
range(min(s.size(), end.size()))
{
if (s[s.size() - 1 - i] != end[end.size() - 1 - i])
{
possible = 0;
}
}
if (possible)
{
if (s.size() >= end.size())
{
end = s;
}
}
return possible;
}
void solve()
{
int n;
cin >> n;
vector<string> allS;
bool possible = 1;
string start = "";
string end = "";
string middle = "";
string result = "";
while (n--)
{
string str;
cin >> str;
if (count(str.begin(), str.end(), '*') == 0)
{
result = str;
}
vector<string> temp = separate(str);
for (string s : temp)
{
if (s[0] != '*')
{
possible = setStart(s, start);
}
if (s[s.size() - 1] != '*')
{
possible = setEnd(s, end);
}
if (possible && count(s.begin(), s.end(), '*') == 0)
{
result = s;
break;
}
if (s[0] == '*' && s[s.size() - 1] == '*')
{
removeAsterisk(s);
middle += s;
}
}
}
if (possible)
{
if (result.size() == 0)
{
result = start + middle + end;
}
cout << result << "\n";
}
else
{
cout << "*\n";
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t = 0;
cin >> t;
range(t)
{
cout << "Case #" << i + 1 << ": ";
solve();
}
return 0;
}
it seems correct to me and i have tested many times for many examples, but it is losing in test set-1(exactly one * (asterisk) character and and always the first character of string). Can anyone tell what's wrong?
you can consider code of first ranked here (it has all solutions,check only for "pattern matching" task) for help. I know that the wrong answer is an edge case and if it passes test set 1 then it will pass others.

Related

getting "_throw_bad_array_new_lengthv" when trying to use std::vector::push_back inside a class

I'm creating a custom language parser in C++, I'm struggling with a runtime error, where I have a std::vector<std::string> member of a class with a constructor.
The full error is:
The procedure entry point
_ZSt28__throw_bad_array_new_lengthv could no be located
in the dynamic link library
"path_to_executable"
This error is throw whenever I try to use std::vector::push_back in my code, but shouldn't std::vector be a dynamically sized data container? Why is this error occurring?
Some of my codes:
//"lib/cursor.h"
#ifndef T_CURSOR
#define T_CURSOR
#include <iostream>
struct Cursor
{
private:
std::string input;
int inputLength;
char getChar(int p);
public:
char character;
int pos;
int line;
int column;
bool eof;
bool lineBreak;
Cursor(std::string i);
void walk(bool back = false);
void walkTimes(int times, bool back = false);
void move(int toPos);
void skipIgnore();
std::string toString();
};
#endif
//"lib/cursor.cpp"
#include <sstream>
#include "cursor.h"
Cursor::Cursor(std::string i)
{
this->input = i;
this->inputLength = i.length();
this->character = i.at(0);
this->pos = 0;
this->line = 0;
this->column = 0;
this->eof = false;
this->lineBreak = false;
}
char Cursor::getChar(int pos)
{
if (pos < 0 || pos >= this->inputLength)
{
return EOF;
}
return this->input.at(pos);
}
void Cursor::walk(bool back)
{
if (back)
{
this->pos--;
this->column--;
if (this->lineBreak)
{
this->line--;
this->column = 0;
for (int i = this->pos - 1; i >= 0; i--)
{
if (this->getChar(i) == '\n')
break;
this->column++;
}
}
}
else
{
this->pos++;
this->column++;
if (this->lineBreak)
{
this->line++;
this->column = 0;
}
}
this->character = this->getChar(this->pos);
this->eof = this->character == EOF;
this->lineBreak = this->character == '\n';
}
void Cursor::walkTimes(int times, bool back)
{
for (int i = 0; i < times; i++)
{
this->walk(back);
}
}
void Cursor::move(int pos)
{
if (pos < 0)
pos = 0;
if (pos > this->inputLength - 1)
pos = this->inputLength - 1;
this->pos = 0;
this->character = this->input.at(0);
this->line = 0;
this->column = 0;
this->eof = false;
this->lineBreak = this->character == '\n';
while (this->pos < pos)
this->walk();
}
void Cursor::skipIgnore()
{
while (this->character == ' ' ||
this->character == '\n' ||
this->character == '\t')
this->walk();
if (this->character == '#')
{
while (!this->eof && this->character != '\n')
this->walk();
}
while (this->character == ' ' ||
this->character == '\n' ||
this->character == '\t')
this->walk();
}
std::string Cursor::toString()
{
std::stringstream ss("");
ss << "(P:" << this->pos;
ss << " L:" << this->line;
ss << " C:" << this->column;
ss << " \"" << this->character << "\")";
return ss.str();
}
//"lib/lexer.h"
#ifndef T_LEXER
#define T_LEXER
#include <iostream>
#include <vector>
#include "cursor.h"
class Lexer
{
private:
std::string input;
protected:
Cursor cursor;
std::vector<std::string> matchStack;
std::vector<std::vector<Cursor>> cursorStack;
public:
Lexer(std::string input);
std::string getStr(int pos);
void setStr(int pos, std::string str);
Cursor getCursorStart(int pos);
Cursor getCursorEnd(int pos);
bool match(std::string str);
};
#endif
//"lib/lexer.cpp"
#include "lexer.h"
Lexer::Lexer(std::string input) : cursor(input)
{
this->input = input;
}
std::string Lexer::getStr(int pos)
{
if (this->matchStack.size() == 0)
return this->input;
while (pos < 0)
pos += this->matchStack.size();
while (pos >= this->matchStack.size())
pos -= this->matchStack.size();
return this->matchStack[pos];
}
void Lexer::setStr(int pos, std::string str)
{
if (this->matchStack.size() == 0)
return;
while (pos < 0)
pos += this->matchStack.size();
while (pos >= this->matchStack.size())
pos -= this->matchStack.size();
this->matchStack[pos] = str;
}
Cursor Lexer::getCursorStart(int pos)
{
if (this->cursorStack.size() == 0)
return Cursor(this->input);
while (pos < 0)
pos += this->cursorStack.size();
while (pos >= this->cursorStack.size())
pos -= this->cursorStack.size();
return this->cursorStack[pos][0];
}
Cursor Lexer::getCursorEnd(int pos)
{
if (this->cursorStack.size() == 0)
return Cursor(this->input);
while (pos < 0)
pos += this->cursorStack.size();
while (pos >= this->cursorStack.size())
pos -= this->cursorStack.size();
return this->cursorStack[pos][1];
}
bool Lexer::match(std::string str)
{
this->cursor.skipIgnore();
const std::string ss = this->input.substr(this->cursor.pos, str.length());
if (ss == str)
{
this->matchStack.push_back(ss); // Getting error if I include this line
const Cursor startCursor = this->cursor;
this->cursor.walkTimes(str.length());
const Cursor endCursor = this->cursor;
this->cursorStack.push_back({startCursor, endCursor});
return true;
}
return false;
}
//"test.cpp"
#include "lib/cursor.h"
#include "lib/lexer.h"
#include <iostream>
using namespace std;
int main()
{
string input = "Something to test";
Lexer lexer = Lexer(input);
cout << "Start" << endl;
cout << lexer.match("Something") << endl;
return 0;
}
I'm compiling my program with g++ on Windows: g++ test.cpp lib/cursor.cpp lib/lexer.cpp -o test.exe
I got the same error when compiling in command line using g++. But it works well in code blocks. To solve this problem try compiling with -static-libstdc++. It should solve the problem.

visual C++ string subscript out of range

I am stuck with the error "string subscript out of range".
After testing, I am pretty sure that it's because of this function, which is used for reading values in a file, but have no idea what's wrong:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
string read(string value) {
ifstream input;
string line="", output="";
size_t pos;
bool a = true;
int i = 0;
input.open("pg_options.txt");
if (!input.is_open()) {
cout << "pg_options.txt missing.";
return "error";
}
while (getline(input, line)) { //get file lines
pos = line.find(value);
if (pos == string::npos) { //if value in line
while (a == true) {
if (line[i] == '=') { //after "="
i++;
break;
}
else {
i++;
}
}
for (i; line[i] != ' '; i++) {
output += line[i]; //put value to output
}
}
}
input.close();
return output;
}
pg_options.txt:
include_special_characters=true
include_upper_case=true
include_lower_case=true
include_numbers=true
digits=10
cout << read("digits") returns the error mentioned above.
Thank you for your comments. I solved this by editing the for loop:
string read(string value) {
ifstream input;
int olength;
string line = "", output = "";
size_t pos;
bool a = true;
int i = 0;
input.open("pg_options.txt");
if (!input.is_open()) {
cout << "pg_options.txt missing.";
return "error";
}
while (getline(input, line)) {
pos = line.find(value);
if (pos != string::npos) {
while (a == true) {
if (line[i] == '=') {
i++;
break;
}
else {
i++;
}
}
olength = line.length() - value.length() - 1;
for (int i2 = 0; i2 < olength; i2++) {
output += line[i];
i++;
}
}
}
input.close();
return output;
}

How do I find the size of a char array?

How should I go about finding the length of a char array in C++? I've tried two methods already, but they both have resulted in the wrong number of characters in the array. I've used strlen and the sizeof operator so far, to no avail.
void countOccurences(char *str, string word)
{
char *p;
string t = "true";
string f = "false";
vector<string> a;
p = strtok(str, " ");
while (p != NULL)
{
a.push_back(p);
p = strtok(NULL, " ");
}
int c = 0;
for (int i = 0; i < a.size(); i++)
{
if (word == a[i])
{
c++;
}
}
int length = sizeof(str); //This is where I'm having the problem
string result;
cout << length << "\n";
if (length % 2 != 0)
{
if (c % 2 == 0)
{
result = "False";
}
else
{
result = "True";
}
}
else
{
if (c % 2 == 0)
{
result = "True";
}
else
{
result = "False";
}
}
if (strlen(str) != 0)
{
cout << result;
}
}
int boolean()
{
char str[1000];
cin.getline(str, sizeof(str));
string word = "not";
countOccurences(str, word);
return 0;
}
sizeof(str) is wrong. It gives you the size of a pointer (str is a pointer), which is a fixed number, normally either 4 or 8 depending at your platform.
std::strlen(str) is correct, but strtok inserts a bunch of \0 into your array before you try to obtain the size. strlen will stop at the first \0, and give you the number of characters preceeding it.
Call strlen before strtok and save its return value to a variable.
Here you can find a modern c++ solution:
#include <iostream>
#include <string_view>
#include <string>
#include <type_traits>
template<typename String>
inline std::size_t StrLength(String&& str)
{
using PureString = std::remove_reference_t<std::remove_const_t<String>>;
if constexpr(std::is_same_v<char, PureString>){
return 1;
}
else
if constexpr(std::is_same_v<char*, PureString>){
return strlen(str);
}
else{
return str.length();
}
}
template<
typename String,
typename Lambda,
typename Delim = char
>
void ForEachWord(String&& str, Lambda&& lambda, Delim&& delim = ' ')
{
using PureStr = std::remove_reference_t<std::remove_reference_t<String>>;
using View = std::basic_string_view<typename PureStr::value_type>;
auto start = 0;
auto view = View(str);
while(true)
{
auto wordEndPos = view.find_first_of(delim, start);
auto word = view.substr(start, wordEndPos-start);
if (word.length() > 0){
lambda(word);
}
if (wordEndPos == PureStr::npos)
{
break;
}
start = wordEndPos + StrLength(delim);
}
}
int main() {
std::string text = "This is not a good sentence.";
auto cnt = 0;
ForEachWord(
text,
[&](auto word)
{
//some code for every word... like counting or printing
if (word == "not" ){
++cnt;
}
},
' '
);
std::cout << cnt << "\n";
}
The "end of a string" is the char '\0' check for that character to stop the search.

Delete first and last 'X' character from character array

I'm trying to delete first 'w' and last 'w' from a string.
I deleted the first 'w', but couldn't delete the last one, and here is my code:
char str1[80], *pstr1, *pstr2;
cout << "Enter a String:\n";
gets_s(str1);
pstr1 = str1;
pstr2 = new char[strlen(str1)];
int n = strlen(str1) + 1, k = 0, i = 0;
bool s = true;
while (k < n+1)
{
if (strncmp((pstr1 + k), "w", 1) != 0)
{
*(pstr2 + i) = *(pstr1 + k);
i++;
k++;
}
else if(s == true)
{
k++;
s = false;
}
else
{
*(pstr2 + i) = *(pstr1 + k);
i++;
k++;
}
}
Make your life easy and use std::string with find_first_of, find_last_of and erase.
#include <string>
void erase_first_of(std::string& s, char c)
{
auto pos = s.find_first_of(c);
if (pos != std::string::npos)
{
s.erase(pos, 1);
}
}
void erase_last_of(std::string& s, char c)
{
auto pos = s.find_last_of(c);
if (pos != std::string::npos)
{
s.erase(pos, 1);
}
}
#include <iostream>
int main()
{
std::string s = "hellow, worldw\n";
erase_first_of(s, 'w');
erase_last_of(s, 'w');
std::cout << s;
}

Seg Fault with Prefix

I am getting a segmentation fault when trying to convert an infix expression into prefix order. I have a postfix using the same logic that works fine the issue seems to be where i try to read the infix expression in reverse but I am not exactly sure why it is faulting. Any help would greatly appreciated Here is the relevant code:
int ParseTree::prefix(string infix)
{
vector<string> exp;
stringstream ss(infix);
string tok;
while(getline(ss,tok,' '))
{
exp.push_back(tok);
}
vector<string> prefix;
stack<string> s;
for(unsigned int i = exp.size() - 1; i >= 0 ; i--)
{
if(parseTry(exp[i]))
{
prefix.push_back(exp[i]);
}
if(exp[i] == "(")
{
s.push(exp[i]);
}
if(exp[i] == ")")
{
while(!s.empty() && s.top() != "(")
{
prefix.push_back(s.top());
s.pop();
}
s.pop();
}
if(isOperator(exp[i]) == true)
{
while(!s.empty() && priority(s.top()) >= priority(exp[i]))
{
prefix.push_back(s.top());
s.pop();
}
s.push(exp[i]);
}
}
while(!s.empty())
{
prefix.push_back(s.top());
s.pop();
}
for(unsigned int i = 0; i < prefix.size(); i++)
{
cout << prefix[i] << " ";
}
return 0;
}
int ParseTree::priority(const string &s)
{
if(s == "*" || s == "/")
{
return 2;
}
if(s == "+" || s == "-")
{
return 1;
}
else
{
return 0;
}
}
bool ParseTree::parseTry(const string &s)
{
bool number = false;
for(unsigned int i = 0; i < s.size(); i++)
{
if(!isdigit(s[i]))
{
number = false;
}
else
{
number = true;
}
}
return number;
}
bool ParseTree::isOperator(const string &s)
{
return (s == "+" || s == "-" || s == "*" || s == "/");
}