Kickstart 2020 RoundG Problem A Runtime Error - c++

I am trying to solve the problem "Kick Start" from round G from last year. In short you need to count the number of appearances of the substring "KICK....START" with any number of characters in between the two words. The input is a string with only capital letters.
I wrote some code and the sample works fine. But after sending the code I get a runtime error in the first test case. I Have tried many different things like using the at() function from string, or substring but nothing has solved the problem. Any ideas what the problem could be?
So my function that gets the error looks like this:
long long fragment_count = 0;
long long open_count = 0;
string text;
cin >> text;
for (int i = 0; i < text.size() - 4; ++i) {
if (text[i] == 'K') {
if (text[i + 1] == 'I' && text[i + 2] == 'C' && text[i + 3] == 'K') {
open_count++;
}
} else if (text[i] == 'S') {
if (text[i + 1] == 'T' && text[i + 2] == 'A' && text[i + 3] == 'R' && text[i + 4] == 'T') {
fragment_count += open_count;
}
}
}
cout << fragment_count << "\n";
Edit: Outside of this function is the template I use for the kickstart problems. At the start there are two lines that I read that speed up io:
ios::sync_with_stdio(0);
cin.tie(0);
Then I just read a number with cin, that signifies the test cases and call the fucntion above for every test case.

text.size() is of type std::size_t, which is an unsigned type. If the length of the text is less than 4, text.size() - 4 wraps around and becomes a huge positive number.
Replace the comparison with i + 4 < text.size().

Related

converting string to sentence case in c++

I wrote this code for converting string to sentence case but i don't know where is the problem
for (int i = 0; s[i] != '\0'; i++)
{
if (i == 0 && s[i] >= 'a' && s[i] <= 'z')
{
s[i] -= 32;
cout << s[i];
}
else if (s[i] == '.')
{
if (s[i+1] == ' ')
{
if (s[i + 2] >= 'a' && s[i + 2] <= 'z')
{
s[i + 2] -= 32;
cout << s[i + 2];
}
}
else
{
if (s[i + 1] >= 'a' && s[i] <= 'z')
{
s[i + 1] -= 32;
cout << s[i + 1];
}
}
}
cout << s[i];
}
the problem is for example if i give the
video provides a powerful way to help you prove your point. when you
click online video, you can paste in the embed code for the video you
want to add. you can also type a keyword to search online for the
video that best fits your document. to make your document look
professionally produced, word provides header, footer, cover page, and
text box designs that complement each other. for example, you can add
a matching cover page, header, and sidebar.
the output is like this
VVideo provides a powerful way to help you prove your pointW. When you
click online video, you can paste in the embed code for the video you
want to addY. You can also type a keyword to search online for the
video that best fits your documentT. To make your document look
professionally produced, word provides header, footer, cover page, and
text box designs that complement each otherF. For example, you can add
a matching cover page, header, and sidebar.video provides a powerful
way to help you prove your point. when you click online video, you can
paste in the embed code for the video you want to add. you can also
type a keyword to search online for the video that best fits your
document. to make your document look professionally produced, word
provides header, footer, cover page, and text box designs that
complement each other. for example, you can add a matching cover page,
header, and sidebar.
so basically one time it print the first letter of each sentence before dot and then upper case the first letter of sentence and after that repeats the input
Just comment out or remove two lines(becuase they are generating that extra character) and the code will work as you want :
cout << s[i + 2]; and
cout << s[i + 1];
Here's is the example for the same :
for (int i = 0; s[i] != '\0'; i++)
{
if (i == 0 && s[i] >= 'a' && s[i] <= 'z')
{
s[i] -= 32;
cout << s[i];
i++;
}
else if (s[i] == '.')
{
if (s[i+1] == ' ')
{
if (s[i + 2] >= 'a' && s[i + 2] <= 'z')
{
s[i + 2] -= 32;
// cout << s[i + 2];
}
}
else
{
if (s[i + 1] >= 'a' && s[i] <= 'z')
{
s[i + 1] -= 32;
//cout << s[i + 1];
}
}
}
cout << s[i];
}
I think you are over thinking it. You should have a flag for start of sentence and set it to true to start. Then after displaying the letter in upper case reset the flag.
void tosentence(const char *s)
{
auto startsentense = true;
for (auto i = 0; s[i]; i++)
{
if (startsentense && isalnum(s[i]))
{
std::cout << static_cast<char>(toupper(s[i]));
startsentense = false;
}
else if (s[i] == '.')
{
std::cout << s[i];
startsentense = true;
}
else
{
std::cout << s[i];
}
}
}
Here is another solution, I think it is more readable. It also uses a lambda with capture and STL algorithm.
#include <string>
#include <algorithm>
// returning function
std::string make_sentence(std::string const &str) {
std::string ans;
ans.reserve(str.size()); // we already know the size of the answer - optomization to allocate only once
bool search{true}; // our state variable - initially true
// we use std::back_inserter to populate our answer string
std::transform(std::begin(str), std::end(str), std::back_inserter(ans),
[search] (auto &s) mutable // note the mutable here, by default captured search is const
{
// s is a char
if (s == ' ') return s;
if (s == '.') {
search = true; // change state to true after dot
return s;
}
if (search) {
// if we were searching for the start of a sentence
search = false; // stop search
// use either of this return statements, but in real-life beware encodings. String manipulation is pain.
return std::toupper(s, std::locale());
//return static_cast<char>(std::toupper(s));
}
return s;
});
return ans;
}
// modifying function
void make_sentence2(std::string &str) {
bool search{true}; // our state variable - initially true
// we use the same iterator std::begin(str) to modify the same string - it is safe to do so since we do not invalidate iterators
std::transform(std::begin(str), std::end(str), std::begin(str),
[search] (auto &s) mutable // note the mutable here, by default captured search is const
{
// s is a char
if (s == ' ') return s;
if (s == '.') {
search = true; // change state to true after dot
return s;
}
if (search) {
// if we were searching for the start of a sentence
search = false; // stop search
return std::toupper(s, std::locale());
}
return s;
});
}
int main() {
const std::string str = "video provides a powerful way to help you prove your point. when you click online video, you can paste in the embed code for the video you want to add. you can also type a keyword to search online for the video that best fits your document. to make your document look professionally produced, word provides header, footer, cover page, and text box designs that complement each other. for example, you can add a matching cover page, header, and sidebar.";
auto str2{str}
auto ans = make_sentence(str);
make_sentence2(str2);
std::cout << ans << '\n;
std::cout << str2 << '\n';
return 0;
}

C++ How to output the letters or numbers from input of letters or numbers

So let's say we have the following case: for ”12323465723” possible answers would be ”abcbcdfegbc” (1 2 3 2 3 4 6 5 7 2 3), ”awwdfegw” (1 23 23 4 6 5 7 23), ”lcwdefgw” (12 3 23 4 6 5 7 23), in this case, the user will input numbers from 1 to 26, not divided by any space and the program itself will suggest 3 ways of interpreting the numbers, getting the most of the combinations from 1 to 26 these being the values from a to z
As you can see this is edited, as this is the last part of the problem, Thank you all who have helped me this far, I've managed to solve half of my problem, only the above mentioned one is left.
SOLVED -> Thank you
This involves a decision between 0 to 2 outcomes at each step. The base cases are there are no more characters or none of them can be used. In the latter case, we backtrack to output the entire tree. We store the word in memory like dynamic programming. This naturally leads to a recursive algorithm.
#include <stdlib.h> /* EXIT */
#include <stdio.h> /* (f)printf */
#include <errno.h> /* errno */
#include <string.h> /* strlen */
static char word[2000];
static size_t count;
static void recurse(const char *const str) {
/* Base case when it hits the end of the string. */
if(*str == '\0') { printf("%.*s\n", (int)count, word); return; }
/* Bad input. */
if(*str < '0' || *str > '9') { errno = ERANGE; return; }
/* Zero is not a valid start; backtrack without output. */
if(*str == '0') return;
/* Recurse with one digit. */
word[count++] = *str - '0' + 'a' - 1;
recurse(str + 1);
count--;
/* Maybe recurse with two digits. */
if((*str != '1' && *str != '2')
|| (*str == '1' && (str[1] < '0' || str[1] > '9'))
|| (*str == '2' && (str[1] < '0' || str[1] > '6'))) return;
word[count++] = (str[0] - '0') * 10 + str[1] - '0' + 'a' - 1;
recurse(str + 2);
count--;
}
int main(int argc, char **argv) {
if(argc != 2)
return fprintf(stderr, "Usage: a.out <number>\n"), EXIT_FAILURE;
if(strlen(argv[1]) > sizeof word)
return fprintf(stderr, "Too long.\n"), EXIT_FAILURE;
recurse(argv[1]);
return errno ? (perror("numbers"), EXIT_FAILURE) : EXIT_SUCCESS;
}
When run on your original input, ./a.out 12323465723, it gives,
abcbcdfegbc
abcbcdfegw
abcwdfegbc
abcwdfegw
awbcdfegbc
awbcdfegw
awwdfegbc
awwdfegw
lcbcdfegbc
lcbcdfegw
lcwdfegbc
lcwdfegw
(I think you have made a transposition in lcwdefgw.)
According to ASCII table we know that from 65 to 90 it A to Z.
so below is the simple logic to achieve what you're trying.
int main(){
int n;
cin>>n;
n=n+64;
char a=(char) n;
if (a>=64 && a<=90)
cout<<a;
else cout<<"Error";
return 0;
}
If you want to count the occurencs of "ab" then this will do it:
int main()
{
char line[150];
int grup = 0;
cout << "Enter a line of string: ";
cin.getline(line, 150);
for (int i = 0; line[i] != '\0'; ++i)
{
if (line[i] == 'a' && line[i+1] == 'b')
{
++grup;
}
}
cout << "Occurences of ab: " << grup << endl;
return 0;
}
If you want to convert an int to an ASCII-value you can do that using this code:
// Output ASCII-values
int nr;
do {
cout << "\nEnter a number: ";
cin >> nr;
nr += 96; // + 96 because the ASCII-values of lower case letters start after 96
cout << (char) nr;
} while (nr > 96 && nr < 123);
Here I use the C style of casting values to keep things simple.
Also bear in mind ASCII-values: ASCII Table
Hope this helps.
This could be an interesting problem and you probably tagged it wrong, There's nothing specific to C++ here, but more on algorithm.
First of all the "decode" method that you described from numerical to alphabetical strings is ambiguious. Eg., 135 could be interpreted as either "ace" or "me". Is this simply an oversight or the intended question?
Suppose the ambiguity is just an oversight, and the user will enter numbers properly separated by say a white space (eg., either "1 3 5" or "13 5"). Let nstr be the numerical string, astr be the alphabetical string to count, then you would
Set i=0, cnt=0.
Read the next integer k from nstr (like in this answer).
Decode k into character ch
If ch == astr[i], increment i
If i == astr.length(), set i=0 and increment cnt
Repeat from 2 until reaching the end of nstr.
On the other hand, suppose the ambiguous decode is intended (the numerical string is supposed to have multiple ways to be decoded), further clarification is needed in order to write a solution. For example, how many k's are there in "1111"? Is it 1 or 2, given "1111" can be decoded either as aka or kk, or maybe even 3, if the counting of k doesn't care about how the entire "1111" is decoded?

how to calculate polynomial (x^2^2^2^2+x^2^2^2)

I want to calculate (x^2^2^2^2+x^2^2^2) result should be [x^256+x^16]..but i am unable to do this completely..i also have written a code which is working for first half(before '+') but in other half it fails to do it...
#include<iostream>
#include<string>
#include <algorithm>
#include<sstream>
using namespace std;
int main()
{
string a;
cin >> a;
string s1 = "^";
string::size_type foud;
foud = a.find(s1);
int i = foud;
int flag = 0;
i++;
while (foud != std::string::npos)
{
flag = 0;
cout << i <<"I"<< endl;
while (flag != 1 && i < a.length())
{
if (a[i] == '(' || a[i] == '+' || a[i] == '-' || a[i] == ')')
{
flag++;
cout << "terminator" << endl;
}
else if (a[i] == '^')
{
/*int j = (int)(a[i - 1]);
j = j - 48;
int k = (int)(a[i + 1]);
k = k - 48;
i = k + 1;
int power =0;
power = pow(j, k);
;*/
int j = i;
int k = i;
k--;
j++;
string bcknumber;
while (a[k] != '^' && a[k] != '(' && a[k] != '+' && a[k] != '-' && a[k] != ')')
{
bcknumber = bcknumber + a[k];
k--;
}
cout << bcknumber << endl;
reverse(bcknumber.begin(), bcknumber.end());
cout << bcknumber << endl;
int BK;
BK = stoi(bcknumber);
int FD;
string frdnum;
while (a[j] != '^'&&a[j] != '\0' && a[j] != '(' && a[j] != '+' && a[j] != '-' && a[j] != ')')
{
frdnum = frdnum + a[j];
j++;
}
FD = stoi(frdnum);
int resil = pow(BK, FD);
frdnum.clear();
stringstream s;
string res;
s << resil;
res = s.str();
if (i == 15)
{
a.replace(14, 15, res);
}
else
{
a.replace(i - bcknumber.length(), i + frdnum.length(), res);
}
i--;
bcknumber.clear();
}
else
i++;
}
foud = a.find("^", foud + 1);
i = foud;
i++;
}
cout << a << endl;
system("pause");
}
This is not a trivial problem. You want to build an infix calculator (a + b). A prefix calculator (+ a b) or a postfix calculator (a b +) are simpler, since there are no ambiguities at all. An infix calculator can have a lot of them, depending on the degree of freedom you want the user to have.
In the problem you're exposing, one is tempted to say: well, if there is an operator next to the second operand, then I have to accumulate the last result and operate with that and the next operation. However, there are problems like precedence which will not be deal with with that approach.
I would start creating a prefix calculator. It is a lot easier:
calculate():
opr = match operator
op1 = match operand
if op1 is operator:
back
op1 = calculate
op2 = match operand
if op2 is operator:
back
op2 = calculate
return calc(opr, op1, op2)
Once you have mastered that, then there is the possibility to start with an infix calculator.
One thing to do in the last algorithm would be to change it to avoid recursion, for example.
This is a good exercise, enjoy it. Hope this helps.
This smells like homework/assignment so I will not provide code...
As I see it you want just string parser to string replacing the power part. I am assuming You still do not understand the power math or are wrongly writing/interpreting representation of the string. For example:
x^2^2^2^2 =
(((x^2)^2)^2)^2 =
(((x.x)^2)^2)^2 =
((x.x).(x.x))^2)^2 =
((x.x.x.x))^2)^2 =
((x.x.x.x).(x.x.x.x))^2 =
(x.x.x.x.x.x.x.x)^2 =
(x.x.x.x.x.x.x.x).(x.x.x.x.x.x.x.x) =
(x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x) =
x^16
And not yours x^256. You can not add parenteses where you want they must be placed according to order of math operations otherwise the resulting equation will not match the input string !!!. In case you got defined different parse rules for your parser then in standard math then you need to define them in the Question.
Now how to approach this:
read string
I would start with constant hard-coded string instead of typing it all the time while programing/debugin over and over (as many students do ... I saw few times people typing 5x5 matrix on each build :) ... which is insane)
When the program works only then use the cin reading... as you already do
detect which part of the string is power exponent
exponent=1
Search the string for first ^ and remember the start position i0 if not found goto #4.
Now depending on what follows:
If number multiply exponent by it.
If ^ skip it and goto to #2
if neither stop
Of coarse if you should support parentes then it will be much much more complicated and you need to decode the whole thing which is not trivial which you should also mention in the Question.
replace original exponent string with computed string (if computable)
so the computed string will be "^"<<exponent or "^"+exponent depends on what kind of string arithmetics you using ....
output string
with cout or whatever as you already do

C++ Not sure how to have my program output the location of a space

Alright, so I have two questions and if anyone can help me out I would greatly appreciate it! This is my first programming class, so it would also be my first C++ class and I'm a bit stuck.
So I created a Caesar cipher that shifts the string that the user inputs to the right by a pseudo random number between 8-15. What the complete program needs to do is give the number it is shifted by at the beginning, followed by the encrypted string. If there are spaces in the string that are inputed, they need to take the letter/number that is before the space and shift it by 4. I need to terminate the encryption with an '&' character and that is followed by a '#' character and then the number location of the first space followed by another '#' character and another location of a second space if there is one and so on.
So for example, if I were encrypting a string that was being shifted by 9 and said:
Hello World 123
It should look like this when encrypted:
9qnuuxsfxaumh012&#6#12
My first and more important question. I can't figure out how to make the program output the '#' character followed by the number that tells the location of the space. I've thought of maybe doing some kind of loop that reads the string but I'm coming up blank. If I could get some advice that would be great as this is the only part holding me up from turning this in.
My second question comes from a little confusion within my own code that I would love an English interpretation on how it works since I don't understand it myself. I was first using just for loops to make it so that the character 'z' would wrap back around to 'a' but no matter what I did, I kept getting it to only wrap around after a '{' character which is the next character after 'z' on the ascii table. So I decided to change my method and I read on wikipedia under "Caesar cipher" that you could use a modulus. So I used the equation they gave me which was E(x) = (a + b) mod 26. Well it didn't work. So I started to do a google search and saw 2 different posts where people subtracted the character 'a' and then added the chracter 'a' back on at the end as well as added the variable to itself with +=. So I put it in and it worked.
It looks like this:
output += ((input[count] - 'a' + n) % 26) + 'a';
and I thought it would look like this after reading the wiki and it not working when i put this in
output = ((input[count] + n) % 26)
Same goes for wrapping the numbers as well:
output += ((input[count] - '0' + n) % 10) + '0';
So if someone could explain to me why I am adding output to itself as well as subtracting 'a' in the beginning and then re-adding 'a' at the end so I could understand what's going on. I really don't like having code in a program that I'm going to turn in that I don't even understand myself.
Anyways, I'm sorry for the long read, I just thought I would explain what's going on and what I need clearly so that anyone willing to help would completely understand what I'm saying without me having to follow up with a second post explaining.
And finally here's the full program that I have written:
#include <ctime>
#include <iostream>
#include <string>
#include <cstdlib>
#include <fstream>
using namespace std;
//random number generator between 8 and 15
int random()
{
int value;
value = rand() % (18 - 10) + 8;
return value;
}
int main()
{
//Give random() a seed
srand(time(NULL));
//Declare variables
string input;
int length;
int n = random();
string output;
//Program
cout << "Enter your secret message: " << endl;
getline (cin, input);
cout << n;
length = input.length();
for (int count = 0; count < length; count++)
{
input[count] = tolower(input[count]);
if (input[count] >= 'a' && input[count] <= 'z')
{
output += ((input[count] - 'a' + n) % 26) + 'a';
}
if (input[count] >= '0' && input[count] <= '9')
{
output += ((input[count] - '0' + n) % 10) + '0';
}
else if(input[count] == ' ')
{
if (input[count - 1] >= 'a' && input[count - 1] <= 'z')
{
output += ((input[count - 1] - 'a' + 4) % 26) + 'a';
}
else if (input[count - 1] >= '0' && input[count - 1] <= '9')
{
output += ((input[count - 1] - '0' + 4) % 10) + '0';
}
cout << output;
}
}
cout << output << endl;
return 0;
}
Thanks so much for anyone willing to help!
Two answer the second question:
input[count] - 'a'
This gives you 0 for the letter a, 1 for the letter b, ... 25 for the letter z.
input[count] - 'a' + n
Then you add the number n. Having "a" as an input and being n==2 you will get a 3. But for a "z" as input you will get a 27.
To solve the problem you use the modulus:
(input[count] - 'a' + n) % 26
The result is a 1 for the "z".
((input[count] - 'a' + n) % 26) + 'a'
Now you transfer the number from 0 to 25 back to the corresponding ASCII code.
The point of the seemingly odd expansion is to do the following:
Create a number from 0..25: input[count] - 'a'
Adjust that number by adding your shift amount: + n
Modulo the result with 26 to wrap overflow of 26+ back into 0..25: % 26
And finally, add that result back to the base character: +a``
Your idea of a shortcut:
output = ((input[count] + n) % 26)
simply takes the ascii value of the input char, adds the shift, then modulo 26. The result is a value in 0..25, nowhere near the range of 'a'..'z'.
And before you think just adding 'a' would work, it isn't that simple. For example, suppose you had a shift of 9 and in input char of 'z'
The presented formula that works: (ch - 'a' + n) % 26 + 'a'
(('z' - 'a' + 9) % 26 + 'a'
((122 - 97 + 9) % 26 + 97
34 % 26 + 97
8 + 97
105, the ascii value of 'i'
Your formula, with 'a' adjustment: (ch + n) % 26 + 'a'
('z' + 9) % 26 + 'a'
(122 + 9) % 26 + 97
131 % 26 + 97
1 + 97
98, the ascii value for 'b'.
The problem is the distance from the beginning of the char sequence that is being modulo-adjusted is never accounted for in the modulo reduction. Thus the reason for the formula you find odd.
Regarding how to accumulate a list of space locations. a ostringstream will make that trivial, as would a std::vector<int>. An example of the former looks like this:
#include <ctime>
#include <iostream>
#include <string>
#include <cstdlib>
#include <fstream>
#include <sstream> // for std::ostringstream
using namespace std;
int main()
{
//Give random() a seed
srand(static_cast<unsigned>(time(NULL)));
//Declare variables
string input;
int length;
int n = rand() % (18 - 10) + 8;
string output;
//Program
cout << "Enter your secret message: " << endl;
getline (cin, input);
cout << n;
// string stream to hold the list of space locations.
std::ostringstream oss;
length = input.length();
for (int count = 0; count < length; count++)
{
input[count] = tolower(input[count]);
if (input[count] >= 'a' && input[count] <= 'z')
{
output += ((input[count] - 'a' + n) % 26) + 'a';
}
if (input[count] >= '0' && input[count] <= '9')
{
output += ((input[count] - '0' + n) % 10) + '0';
}
else if(input[count] == ' ')
{
if (input[count - 1] >= 'a' && input[count - 1] <= 'z')
{
output += ((input[count - 1] - 'a' + 4) % 26) + 'a';
}
else if (input[count - 1] >= '0' && input[count - 1] <= '9')
{
output += ((input[count - 1] - '0' + 4) % 10) + '0';
}
// add space location with preamble to string stream
oss << '#' << count;
}
}
// append space accumulated list string to the end after '&'
cout << output << '&' << oss.str() << endl;
return 0;
}

How to convert a recursive solution to bottom up or top down solution?

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