I am stuck and cant seem to figure out where I should go from here.
I would appreciate any hints or tips on how I should approach this problem. Been trying to figure this out for over 9 hrs no luck.
The question is as follows:
A string s is said to be palindromic if it reads the same backwards and forwards. A decomposition of s is a set of non-overlapping sub-strings of s whose concatenation is s.
Write a C++ program that takes as input a string and computes all its palin-
dromic decompositions. For example.if s is the string 0204451881 then the
decomposition 020, 44 5 1881 is a palindromic decomposition. So is
0 2 0 4 4 5 1 8 8 1
0 2 0 4 4 5 1 88 1
0 2 0 4 4 5 1881
0 2 0 44 5 1 8 8 1
0 2 0 44 5 1 88 1
020 4 4 5 1 8 8 1
020 4 4 5 1 88 1
020 4 4 5 1881
020 44 5 1 8 8 1
020 44 5 1 88 1
020 44 5 1881
this is a class project.
so far I have:
#include <iostream>
#include <string>
using namespace std;
void palDecom(string str1);
bool isPal(const string &str);
void subPal(string str1);
int main()
{
string s = "0204451881";
palDecom(s);
subPal(s);
return 0;
}
//shows the decomposition as the single char of the string
//takes a string as input
void palDecom(string str1)
{
int stringLastIndex = (str1.length());
for (int i = 0; i < stringLastIndex; i++)
{
cout<< str1[i] <<" ";
}
cout<<endl;
}
void subPal(string str1)
{
int stringLastIndex = (str1.length());
for (int curIndx = 0; curIndx < stringLastIndex; curIndx++)
{
for(int comparIndx = 1; comparIndx < stringLastIndex; comparIndx++)
{
//cout<< "i was in this loop"<<endl;
if (isPalindrome((str1,curIndx,comparIndx)))
//cout<<str1.substr(0,curIndx-1)<<" "<< str1.substr(curIndx,comparIndx) <<" "<< str1.substr(comparIndx,stringLastIndex)<<endl;
}
}
}
bool isPal(const string &str)
{
int start=0, end=str.length()-1;
while (start < end) {
if (str[start++] != str[end--])
return false;
}
return true;
}
Actually, I just managed to realize this:
Palindromes decompose to combination splits.
What this means is that each palindrome will "split" into additional sub-palindromes based on how many "layers" of palindrome it possesses.
For example: The sequence
12213443
-> 1221 + 3443
-> 1 + 22 + 1 + 3 + 44 + 3
-> 1 + 2 + 2 + 1 + 3 + 44 + 3
As you parse down the string, the possibilities will just increase by the amount of palindromes a larger one can decompose to until you have palindromes of 1 character width.
Granted, I realize that palindromes can overlap:
1221221
-> 1221 + 22 + 1
OR -> 1 + 22 + 1221
This is an additional quandary, but is definitely solvable.
Additionally, you can choose to think about smaller palindromes coming together to create larger ones.
Personally, I think this line of thought will lead to a better algorithm and method of solving from the above, as composing new palindromes while iterating in one direction is probably easier than decomposing them in just one direction.
I think the best course is to start playing with palindromes and map out the possible decompositions. By analysing this, you should be able to find a repetitive pattern that can then be mapped to a recursive solution.
Regardless, this answer definitely can use recursion. There is a clear pattern here; you just need to explore it more and find it.
I wish I had a more definitive answer but I myself am struggling with the problem. I hope someone else can edit this and pick up the threads?
Use recursion to solve this problem by scanning the string from left to right.
Keep a stack of the previous palindrome partitions that have already been found "to the left" of the "current position" in the overall string. This stack could be an array or std::vector of pointers to the ends (i.e. - one past the last character) of each previously found palindrome. In this case, the "current position" is indicated by the top element of the stack, or the beginning of the string if the stack is empty.
The base/exit case of the recursion is when the current position refers to the end of the entire string. In that case you've already exhausted the string. Print out the palindromes as indicated by the palindrome stack (starting from the bottom) and then return. (Hint: Don't alter the original string to insert nul terminators to print each palindrome as a string. Instead, just print each palindrome character-by-character according to the partitions on the stack, print spaces between the palindromes and a newline at the end of the stack.)
Otherwise, have a loop that goes from 1 up through the number of characters remaining in the string starting from the current position. At each iteration, test if the current position is a palindrome of length equal to your loop index. If it is such a palindrome, then push a partition for that palindrome onto the stack and recurse down to one level deeper.
That should do it.
I wouldn't use a std::stack to implement the stack. Instead use a std::vector or an array. If you use std::vector, then don't do structural operations (e.g. - push_back, pop_back, etc.) on it in the recursion. Instead, just resize() it to hold up to strlen(str) partition elements before you begin recursing because the deepest stack will be when each character of the string is a palindrome. Then in your recursion, you simply pass the logical, current size of the stack. This tells you the index where the next palindrome partition should be placed (i.e. - at index size) and allows you to access any previously existing top element of the stack (i.e. - at index size - 1). This approach will work for an array or a std::vector.
If you do want to use std::vector::push_back() (or std::stack), then you just need to remember to std::vector::pop_back() after you return from each recursion. This approach would allow you to not need to pass the "logical" size of the stack explicitly around as the vector itself would know its correct size.
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <iomanip>
using std:: cin;
using std:: cout;
using std:: endl;
using std:: setw;
const int MAX_LEN = 100;
int palDecom(const char str[]);
bool isPal(const char str[], int start, int end);
int main()
{
char str[MAX_LEN];
cin >> setw(MAX_LEN) >> str;
cout << palDecom(str) ;
return EXIT_SUCCESS;
}
int palDecom(const char str[])
{
int counter=0;
for (int i = 1; i < strlen(str) ; i++)
for(int lastindex = strlen(str)-1; lastindex < strlen(str) ; lastindex--)
{
if(isPal(str, i , lastindex-1))
counter ++;
}
return counter;
}
bool isPal(const char str[], int start, int end)
{
if(start == strlen(str))
return 1;
if (str[start] == str[end]){
isPal(str, str[start], str[end-1]);
return true;
}
return false;
}
Related
This is the question Im trying to solve: Link
Im running this code in an online editor and it gives a memory limit exceeded, even though I have used str+=c instead of str=str+c. And I cant seem to figure out why. Could anyone help me wth this?
#include <bits/stdc++.h>
using namespace std;
void solve(){
int a,b,x;
cin>>a>>b>>x;
string res="";
res+='0';
a--;
while(x--){
cout<<res;
res+=res.back()=='0'?'1':'0';
if(res.back()=='0')
a--;
else
b--;
}
string ans="";
for(char ch: res){
ans+=ch;
if(ch=='0'){
while (a--){
ans+='0';
}
}
else{
while(b--){
ans+='1';
}
}
}
cout<<ans;
}
int main() {
int t;
t=1;
while(t--){
solve();
}
return 0;
}
The input I give is 3 3 3
and output I expect is 101100
Basically your solution idea is nearly correct.
The most important requirement here is the number of tansitions. So, when we go from a 1 to a 0 or from a 0 to a 1. These transitions must exist. And the number of transisitions also determines the minimum numbers of 0es or 1s needed.
If more 0es or 1s should be present, then you can simply repeat any 0 or 1 with the same value. This will have no impact on the transistion.
Let's have a closer look. Below is an example for the minimum number of 0es or 1s for a given number of transitions
Transitions Sequence Min 0es Min 1s
1 01 1 1
2 010 2 1
3 0101 2 2
4 01010 3 2
5 010101 3 3
6 0101010 4 3
You immediately see that there is a simple mathematical relation between the number of transitions and the minimum number of needed 1s or 0es. It is:
(Number of Transitions + 1)/2 rounded up
(Number of Transitions + 1)/2 rounded down
For odd number of transisitions, the minimum numbers of 1s or 0es are always the same. For even numbers of transitions however, it depends on the starting value.
The reverse conclusion is that it does not matter for odd transitions, if you start with a 0 or a 1. For an even number of transitions it is important.
Example:
Input 1 2 2, meaning one 0, two 1s and 2 transitions.
With the above formula, we calculate that we need two digits of the one and 2 digits for the other, so theoretically 010 or 101, But since we shall use only one 0, it can only be 101
Resulting in: If we have an even number of transitions, then the start value may depend from other input parameters. And more precicely: If the minimum number needed for a digit is equal to the given number for that digit, then we must start with the other digit.
Example:
1 2 2 must be 101
2 2 2 can be 0110 or 1001
Knowing that we can now draft an algorithm. We will work only one one of the many solutions.
Check, if the number of transitions is odd or even
If even, then determine the start digit with above condition
create a sequence of 010101... or 10101... depending on the start digit and the given number of sequences
Add the not yet consumed 0es or 1s to the sequence by simply duplicating or repeating existing 0es or ones.
This can then be implemented in a similar way like your approach:
#include <iostream>
#include <string>
int main() {
// Here we will store the input parameters
int numberOfZeroes{}, numberOfOnes{}, numberOfTransitions{};
// The input will always be correct, so need to check it
std::cin >> numberOfZeroes >> numberOfOnes >> numberOfTransitions;
// Start digit
char digit{ '0' };
// Check, if the number of transitions is even, then we need a special additional check
if (numberOfTransitions % 2 == 0) {
// Calculate the minimum number of needed 0es or 1s
const int minimum = (numberOfTransitions + 1) / 2;
// Check, if we need to start with digit 1
if (minimum == numberOfZeroes)
digit = '1';
}
// Now we want to create a string starting made of alternating 0es and 1s, so transitions
std::string sequenceWithTransitions{};
do {
// Build string
sequenceWithTransitions += digit;
// Update counters and digits
if (digit == '1') {
digit = '0'; // Make transition
--numberOfOnes; // Update counter
}
else {
digit = '1'; // Make transition
--numberOfZeroes; // Update counter
}
} while (numberOfTransitions--);
// Fill in the remaining 0es and 1s
std::string result{};
for (char c : sequenceWithTransitions) {
result += c; // Copy value
if (c == '1') // Potential replications of 1
while (numberOfOnes-- > 0)
result += '1';
if (c == '0') // Potential replications of 0
while (numberOfZeroes-- > 0)
result += '0';
}
std::cout << result << '\n';
}
Of course this code can be optimzied in many ways
In the C++ Standard std:string follows an exponential growth policy, therefore I suppose the capacity() of string during concatenation will always be increased when necessary. However, when I test test.cpp, I found that in the for-loop, only every two times will the capacity() be shrunk back to length() during assignment.
Why isn't this behavior depending on the length of string, but depending on how frequent I change the string? Is it some kind of optimization?
The following codes are tested with g++ -std=c++11.
test.cpp:
#include <iostream>
int main(int argc, char **argv) {
std::string s = "";
for (int i = 1; i <= 1000; i++) {
//s += "*";
s = s + "*";
std::cout << s.length() << " " << s.capacity() << std::endl;
}
return 0;
}
And the output will be like this:
1 1
2 2
3 4
4 4
5 8
6 6 // why is capacity shrunk?
7 12
8 8 // and again?
9 16
10 10 // and again?
11 20
12 12 // and again?
13 24
14 14 // and again?
15 28
16 16 // and again?
17 32
...
996 996
997 1992
998 998 // and again?
999 1996
1000 1000 // and again?
When you do this:
s = s + "*";
You're doing two separate things: making a new temporary string, consisting of "*" concatenated onto the end of the contents s, and then copy-assigning that new string to s.
It's not the + that's shrinking, it's the =. When copy-assigning from one string to another, there's no reason to copy the capacity, just the actual used bytes.
Your commented-out code does this:
s += "*";
… is only doing one thing, appending "*" onto the end of s. So, there's nowhere for the "optimization" to happen (if it happened, it would be a pessimization, defeating the entire purpose of the exponential growth).
It's actually not convered by the C++ standard what happens to capacity() when strings are moved, assigned, etc. This could be a defect. The only constraints are those derivable from the time complexity specified for the operation.
See here for similar discussion about vectors.
Okay, I'm done banging my head against my desk. I'm trying to compute huge powers of 2 [beyond what's capable of being held in the uint64_t data type] by holding digits in a vector of 'char's. Here is my program, followed by my actual outputs:
/*
This program doubles a very large number by using a vector of char types
Usage: program.exe [number]
Output will be 2^[number]
*/
#include <iostream>
#include <vector>
#include <stdlib.h>
using namespace std;
int main(int argc, char *argv[])
{
vector<char> BigNum;
BigNum.push_back('2');
int carry=0, digit;
int power=atoi(argv[1]);
power-=1;
for(int x=0;x<power;x++) //Example: going from 16 to 32. x==4
{
for(int y=BigNum.size()-1;y>=0;y--) //Go from BigNum[1] to BigNum[0] ('6' then '1')
{
digit=atoi(&BigNum[y]); //digit = 6, then digit=1
BigNum[y]=(char)(((digit*2+carry)%10)+48); //BigNum[1]=(char)(6*2+0)%10+48 = '2' in char
//BigNum[0]=(char)(1*2+1)%10+48 = '3' in char
carry=digit*2/10; //carry=1, then 0
}
if(carry==1) //does not execute. BigNum=={'3','2'}
{
BigNum.push_back('0');
for(int y=BigNum.size()-1;y>0;y--)
{
BigNum[y]=BigNum[y-1];
}
BigNum[0]='1';
carry=0;
}
}
for(int x=0;x<BigNum.size();x++) cout<<BigNum[x];
}
Compiled with:
g++ program.cpp -o program
So here are my results when I run the program:
C:\MyApps\program 2
4
C:\MyApps\program 3
8
C:\MyApps\program 4
16
Okay, looks good so far... even my "if(carry==1)" section, where I push a number to the FRONT of the vector works, since we "carried the 1" to get into double digits. Let's continue:
C:\MyApps\program 5
52
What?
C:\MyApps\program 6
26
What what?
C:\MyApps\program 654
84
C:\MyApps\program 654444
00
It never gets to triple digits... and what the heck is going on?
You're applying atoi to something that isn't a null-terminated string. In practice, it may well look in memory like a null-terminated string, but not the one you actually want it to look like.
The cleanest way to fix this is probably to store actual digit values 0..9 rather than ASCII '0'..'9' in your vector. You'll find that the code is nicer that way too.
Just need general project help.
Basically I need to do this for 8 players. The numbers come from a file im supposed to call in. The first 5 numbers for for the first 5 games, the next for rebounds, and then for blocks. Im assuming I need to call in a loop to read the first name, last name, points, rebounds and blocks, process that info and then output the information.Any tips/ suggestions?
ex from the text file:
Thomas Robinson 17 28 10 16 10 11 12 13 8 9 1 1 1 0 1
ex from what I'm supposed to return that information to
Game Log
-----------------------------------------------------------------------------
Player Name : Thomas Robinson
-----------------------------------------------------------------------------
Game # Points Rebounds Blocks
-----------------------------------------------------------------------------
1 17 11 1
2 28 12 1
3 10 13 1
4 16 8 0
5 10 9 1
-----------------------------------------------------------------------------
I think this is homework, but since I don't know which functions can be used, and which functions can't, my answers may be can't fit the request.
At a first look, I got three ideas.
1) using ifstream::get()
ifstream in_file;
in_file.open("your_file_name.txt");
char ch;
string str = "";
while(in_file.get() != '\n')
{
str = "";
while((ch = in_file.get()) != ' ')
{
// add ch to str.
str += string(&ch, 1);
}
// push str into an array, vector, stack, etc.
/*...*/
}
in_file.close();
2) read the line into a string, and then use a split function, you can find how to implement a split function everywhere.
3) use the ifstream::getline() function, it provides a delemiter parameter.
you can find the usage of ifstream::get() and ifstream::getline() here and here
The code I provide in 1) is probably not a good practice, you should check the 'EOF' stream error, in_file.open()'s exceptions etc.
btw, the code I first wrote was an error code, you can't use str += string(ch), you should either write str += string(&ch, 1) or str += string(1, ch) or str += ch you can find string's constructors here. Sorry for the error code again.
You can parse the file with the ">>" operator pretty nicely if everything is separated by spaces and newlines. Which is how the ">>" operator works. So, yes, you need a loop. Basically you want the loop to work like this:
(I never knew you could do this in Comp Sci 1. It would've saved me so much trouble...I used to do things like what the other answer is doing.)
(I'm also assuming you know how to open a txt file as an ifstream. If not, see http://www.cplusplus.com/reference/iostream/ifstream/open/.)
int temp;
int n = 0;
int x = 1;
while(textfile >> temp) // Each time through the loop, this will make temp
// the next value in the file. It will stop when
// there's nothing more to read.
{
/* Now it's going to go from left to right through the file, so you
need some logic to put it in the right place. you know that every
five numbers start a new column, so:*/
array[x][n] = temp; //Start x at 1 because you're skipping the first column
n++;
if (n == 5) {
n = 0;
x++; //Every five values, move on to the next column
}
Now your array will have the stuff where it needs to be. Just output it according to plan.
I got the code below from a C++ book, and I cannot figure out how the initialization works.
From what I can see, there is an outer for loop cycling trough the rows, and the inner loop
cycling trough the column. But its is the assignment of the values into the array that I do not understand.
#include <iostream>
using namespace std;
int main()
{
int t,i, nums[3][4];
for(t=0; t < 3; ++t) {
for(i=0; i < 4; ++i) {
nums[t][i] = (t*4)+i+1; //I don't understand this part/line
cout << nums[t][i] << ' ';
}
cout << '\n';
}
return 0;
}
so here are some questions.
I cannot understand the initialization of the 2D int array nums[3][4]. What separates the (t*4)+i+1, so that the compiler knows what to assign where?
How do I know what values will be stored in the rows and columns, based on what values have been assigned?
Why is there an asterisk?
What are the parentheses around t*4 for?
I understand that initialization two-dimensional arrays look like the following example.
#include <iostream>
using namespace std;
int main() {
char str[3][20] = {{"white" "rabbit"}, {"force"}, {"toad"}}; //initialize 2D character array
cout << str[0][0] << endl; //first letter of white
cout << str[0][5] << endl; //first letter of rabbit
cout << str[1][0] << endl; //first letter of force
cout << str[2][0] << endl; //first letter of toad
return 0;
}
And from what I know, like this in memory.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 w h i t e r a b b i t 0
1 f o r c e 0
2 t o a d 0
Thank you.
(t*4)+i+1
Is an arithmetic expression. t and i are ints, the * means multiply. So for row 1, column 2, t = 1, i = 2, and nums[1][2] = 1x4+2+1 = 7.
Oh, forgot a couple things. First, the () is to specify the order of operations. So the t*4 is done first. Note that in this case the () is unnecessary, since the multiply operator takes precedence over the plus operator anyway.
Also, I couldn't tell from your question if you knew this already or not, but the meaning of rows[t][i] is array notation for accessing rows at row t and column i.
For the first part, isn't it just assigning the a value equal to the row number * 4 plus the column number? I.E. the end result of the assignment should be:
1 2 3 4
5 6 7 8
9 10 11 12
So the expression (t*4)+i+1 means "4 multiplied by the row number plus the column number plus 1". Note that the row number and column numbers in this case start from 0.
nums[t][i] is the one spot in the array it is assigning the value of (t*4)+i+1.
So if t = 1 and i = 1 then the spot num[1][1] will equal (1*4)+1+1 which is 6.
See above.
Asterisk is for multiplying.
You do what's in the ( ) first just like in any mathematical equation.
Lets see, you have
int t,i, nums[3][4];
where we reserve space for the 2d array. The values inside the array will have random values since you only reserved space.
The line :
nums[t][i] = (t*4)+i+1; //I don't understand this part/line
Assigns the values to the array. You have t and i which are loop counters, and the line (t*4)+i+1 means, take value of t, multiply with 4, plus i and plus 1.
So for t=0, i =0, you get that nums[0][0] has value (0*4) + 0 + 1 which is 1.. etc for everything else.
And ofcourse the () are just basic math parentheses.