Tips for optimizing identification of `k` consecutive equal characters - c++

I am trying to solve a question:
An operation consists of selecting k consecutive equal characters and removing them. This operation is to be performed as long as possible. Return the final word after all the operations have been performed. For e.g., for abbcccb and k=3, the output should be a.
The code that I could come up with is as follows:
#include<iostream>
#include<string>
#include<unordered_set>
using namespace std;
string helper(string& s, int k) {
if(s.size()<k) return s;
string str;
for(int i=0; i<s.size(); i++){
char currChar=s[i];
int j=i+1, count=0;
while(j<s.size() && count<=k && s[j]==currChar) {
j++;
count++;
}
if(j-i==k) {
for(int k=0; k<i; k++) str.push_back(s[k]);
for(int k=j; k<s.size(); k++) str.push_back(s[k]);
break;
}
}
if(str.empty()) return s;
return helper(str, k);
}
int main() {
// string s="abbcccb";
// string s="abcdef";
// string s="baac";
string s="aba";
cout<<helper(s, 2);
return 0;
}
Working code here.
However, I think there is a possible way to optimize the code further, especially the part where I determine if k consecutive characters are equal.
Could someone please provide few pointers/ideas/solution?
Thanks.

This is a standard problem that can be solved using stack in O(n) time. Full explanation is already given on this site. Please refer this Reduce the string by removing K consecutive identical characters

Related

I am writing a code for palindrome for integer, Why are my strings not comparing to be equal even when they are the same

1.Palindrome code using strings
#include<iostream>
using namespace std;
int main()
{
int t,n;
cin>>t;
while(t--)
{
cin>>n;
string num=to_string(n);
string rev;
//Reversed the string using for loop
for(int i=num.length();i>=0;i--)
{
rev+=num[i];
}
//Checking the strings if they are same
cout<<num<<" "<<rev<<endl;
if(num.compare(rev)==0)
cout<<"wins";
else
cout<<"loses";
}
return 0;
}
2.Output for n=101
101 101
loses
I tried to string method on a separate integer and compare it with other string and it worked.
I don't understand why is the compare method not returning 0.
You access num out of bounds since i = num.length() points at one character passed the last character in the string. It therefore access the terminating \0 character and that's the first character you'll copy and that's why the strings won't match.
Possible correction:
for(size_t i = num.length(); i--;) {
rev += num[i];
}
An alternative, less error prone, solution would be to create rev by using reverse iterators from num:
std::string rev(num.rbegin(), num.rend());

C++ : Longest Arithmetic Subarray

Given an input array, the output must be the length of the longest arithmetic subarray of the given array.
I am getting a different output other than the desired one. I don't understand where I went wrong, I'm still a beginner so please ignore the rookie mistakes and kindly help me out wherever I'm wrong. Thanks in advance.
Here's the code:
#include <iostream>
using namespace std;
int main () {
int n;
cin>>n;
int array[n];
for (int i=0;i<n;i++)
{
cin>>array[i];
}
int length = 2;
int cd = array[1] - array[0];
for(int i=2; i<n; i++){
if(array[i] - array[i-1] == cd){
length++;
}
else {
cd = array[i] - array[i-1];
length=2;
}
cout<<length<<" ";
}
return 0;
}
If you are looking for a subsequence then what you did would not accomplish that.
For example:
Input: nums = [9,4,7,2,10]
Output: 3
Explanation:
The longest arithmetic subsequence is [4,7,10].
You would require a nested loop structure (a for loop within the for loop you currently have) to accomplish that as you want to check a certain cd with the entire array and not just the next element.
If you require to find a subsequence/subarray given that the elements must be adjacent to one another then your program would work correctly.
Also a big error in your code is that you are printing the length inside the for loop. Unsure of whether that was for debugging purposes.
The problem here is you're resetting length after every update. You need a variable to store the maximum of every length.
#include <iostream>
using namespace std;
const int maxn = 1e6;
int arr[maxn];
int main ()
{
int n; cin>>n;
for (int i=0;i<n;i++) { cin >> arr[i]; }
int length = 2;
int maxLength = 2; //max variable
int cd = arr[1] - arr[0];
for(int i=2; i<n; i++){
if(arr[i] - arr[i-1] == cd) {length++;}
else {
cd = arr[i] - arr[i-1];
length=2;
}
//cout<<length<<" "; //remove this
maxLength = max(maxLength, length); //update maxLength
}
cout << maxLength;
}
A few more aesthetic notes:
array is a keyword in C++ used to declare std::array. Although the program may still run, it could create unnecessary confusion.
int array[n] is a VLAs (variable length array). It's not a C++ standard. It may or may not work depends on the compiler.
Why is "using namespace std;" considered bad practice?

How to use scanf in a loop, store the value into one variable and then print it later?

I'm trying to make a program where user is able to input the number of test cases they want, input the number of alphabet, and then print it.
Since I want to do the printf of the Cases after the value of i is the same as input, which means I have to keep the value of word first but the next scanf always overwrite the value of the previous scanf.
Here's my current code:
#include<stdio.h>
int main()
{
int input=0;
int word=0;
int i=0;
int j=1;
scanf("%d", &input); //number of test cases
for(i=0;i<input;i++)
{
scanf("%d", &word); //how many alphabets
}
for(;i>0;i--)
{
printf("Case #%d: ", j);
j++;
if(word==1)
printf("a\n");
if(word==2)
printf("ab\n");
if(word==3)
printf("abc\n");
else
return 0;
return 0;
}
For example, currently the program works like this:
2
1
2
Case #1: ab
Case #2: ab
Which means the second word scanf (2) overwrote its previous value (1).
When I want it to work like this:
2
1
2
Case #1: a
Case #2: ab
I've been searching google for the answer but haven't really found one.
Please tell me how to do it in stdio.h if possible and also what does the function called (as in recursion, selection, etc).
Thank you very much.
Firs of all are you need this code in C or C++? Case you tagged this post as C++ but code is written in C. So I will answer in C.
You have two solutions in this case:
Simple way is to print the Case after user make second input like this:
#include<stdio.h>
int main()
{
int input=0;
int word=0;
int i=0;
scanf("%d", &input); //number of test cases
for(i = 0; i < input; i++)
{
scanf("%d", &word); //how many alphabets
printf("Case #%d: ", i);
if(word==1)
printf("a\n");
if(word==2)
printf("ab\n");
if(word==3)
printf("abc\n");
}
return 0;
}
Or you have to make some dynamic structure to hold all user input and then iterate over it and print your case. In C it will look like this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int input=0;
int i=0;
int j=1;
int* word = NULL;
scanf("%d", &input); //number of test cases
if (input > 0) { // check if input cases are more than 0;
word = (int*)malloc(sizeof(int) * input);
}
for(i=0;i<input;i++) {
scanf("%d", &word[i]); //how many alphabets. Write new
}
for(;i > 0;i--) {
printf("Case #%d: ", j);
j++;
if(word[i-1] == 1)
printf("a\n");
if(word[i-1] == 2)
printf("ab\n");
if(word[i-1] == 3)
printf("abc\n");
}
free(word);
return 0;
}
Of corse in case of dynamic array's you need to check if word ptr is not null. But this case shows a bigger picture.
If you decide to use C++ it will be easier because you may use std::vector as dynamic container and there is no need to use pointers.

Backtracking of 'AABC' string in C++

I'm struggling with solving this problem in C++.
I have a string: {A,A,B,C} and I want to print all possible permutations for this.
This would be 12:
AABC, AACB, ABAC, ABCA, etc...
I've written the following piece of code in which I have:
- a string which contains the letters A,A,B,C.
- a result string in which I will print each permutation when base condition of recursivity is fullfilled
- an array of integers which represent counters values for each digit: counters[3] = {2,1,1} which means there can be 2 A's, 1 B and 1C in a permutation.
- a function which should solve the problem in a recursive manner like this:
Start from initial string. From left to right of string check if counter for each character is greater than 0. If it is put the character in result[lvl] where lvl is the depth of the recursion. Then decrement the counter for that character's position. Do that for all the elements to the right of the current element and then backtrack all the way up and start with next element(second A).
The base case would be when all counters are equal to 0 print the solution then return.
Here is the code:
#include <iostream>
using namespace std;
char theString[4] = {'A','A','B','C'};
char resultString[4]={};
int counters[3] = {2,1,1};
void printPermutation()
{
for(int i=0; i<4; i++)
{
cout << resultString[i];
}
cout << endl;
}
void solvePermutations(int *counters, int lvl)
{
if(lvl == 4)
{
printPermutation();
return;
}
for(int i=0; i<4; i++)
{
if(counters[i] == 0)
{continue;}
else
{
resultString[lvl] = theString[i];
counters[i]--;
solvePermutations(counters, lvl+1);
counters[i]++;
}
}
}
int main()
{
int *ptr;
ptr = counters;
solvePermutations(ptr, 0);
return 0;
}
When I run the code I get this output instead of what I'm expecting(12 distinct permutations):
ACAB
ACBA
BAAA
BAAC
BACA
etc
More than 12 and with no logic(to me :D)
Please help me correct this and tell me what is wrong in my algorithm and help me understand it. Thank you.
You have one small logical error in your algorithm. You are using a counter[3] and a theString[4]. The idea here is that each index of counter should correspond to one letter, and hold the amount of that letter used.
With your loop you are using i<4. When i is 3 in that loop, you are trying to access counter[3] which is out of bounds. This in undefined behavior and you could be reading any int value.
To correct this, you simply need to decrease the loop to go to max 2 (i < 3) and change theString to an array of 3 elements, {'A', 'B', 'C'}.
char theString[3] = {'A','B','C'};
//...
for(int i=0; i<3; i++)

Basic obfuscation program

#include<iostream>
#include<conio.h>
#include<math.h>
#include<vector>
#include<iterator>
#include<string>
using namespace std;
int main() {
int k=0;
string s;
cout<<"string ";
getline(cin,s); //taking in a string from the user
float n=s.size(); //storing size of string
int f=floor((sqrt(n))); //floor of square root of input string
int c=ceil((sqrt(n))); //ceiling
int m=f*c; //storing product of f and c
vector< vector<string> > vec(n<=m?f:++f, vector<string>(c)); //makes a 2d vector
//depending on user's
//string length
for(int i=0;n<=m?i<f:i<++f;i++) //looping acc to user's input and assigning
{
for(int j=0;j<c;j++) //string to a matrix
{
if(k<s.size())
{
vec[i][j]=s[k];
k++;
}
}
}
for(int j=0;j<c;j++) //printing the vector
{
{
for(int i=0;n<=m?i<f:i<++f;i++)
cout<<vec[i][j];
}cout<<" ";
}
getch();
}
It's not working for n>m as for a string of length 8 characters it makes a vector of 2*3 thus failing to enclose the whole string in the matrix and which is why I am using ternary so as to make a vector of bigger size when it encounters cases like these.
.So what am I doing wrong?
I'll just write the whole question.
One classic method for composing secret messages is called a square code. The spaces are removed from the english text and the characters are written into a square (or rectangle). The width and height of the rectangle have the constraint,
floor(sqrt(word)) <= width, height <= ceil(sqrt(word))
The coded message is obtained by reading down the columns going left to right. For example, the message above is coded as:
imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau
Sample Input:
chillout
Sample Output:
clu hlt io
This won't fix your entire problem, but I still feel it is important. You seem to misunderstand how the ternary works. Let's observe one of its uses here:
for (int i = 0; n <= m ? i < f : i < ++f; i++) {}
// ^^^^^^^^^^^^^^^^^^^^^^^^ <--- not the intended outcome
This will not work because the returned side of the ternary does not "stick" itself in-place. In other words, neither i < f nor i < ++f will be put directly into the for-loop. Instead, it'll give you a value.
To see what it's really doing, you'll first need to understand that the ternary is just another way to do an if-else. The ternary above, put into if-else form, looks like this:
if (n <= m)
i < f; // left side of the ":"
else
i < ++f; // right side of the ":"
Let's break it down further:
i < f
This is doing a less-than comparison of i and f. So, depending on the individual values, you'll receive either a 0 (false) or a 1 (true).
So, in your for-loop, this will occur:
for (int i = 0; 1; i++) {}
// ^ <--- if comparison returns true
for (int i = 0; 0; i++) {}
// ^ <--- if comparison returns false
So, for your example, you'll need to find the value of f before the loop. You can use a ternary for that part, but only if you understand it. Otherwise, use another method to find f (the intended numerical value). Once you find it, then you can put i < f into the for-loop.