Minimum Deletions to Make String Balanced - LeetCode
1653. Minimum Deletions to Make String Balanced
Medium
You are given a string s consisting only of characters 'a' and 'b'.
You can delete any number of characters in s to make s balanced. s is balanced if there is no pair of indices (i,j) such that i < j and s[i] = 'b' and s[j]= 'a'.
Return the minimum number of deletions needed to make s balanced.
Example 1:
Input: s = "aababbab"
Output: 2
Explanation: You can either:
Delete the characters at 0-indexed positions 2 and 6 ("aababbab" -> "aaabbb"), or
Delete the characters at 0-indexed positions 3 and 6 ("aababbab" -> "aabbbb").
Example 2:
Input: s = "bbaaaaabb"
Output: 2
Explanation: The only solution is to delete the first two characters.
Constraints:
1 <= s.length <= 105
s[i] is 'a' or 'b'.
class Solution {
public:
int minimumDeletions(string s) {
int cnt=0;
stack<int> st;
st.push(s[0]);
for(int i=1;i<s.length();i++){
if(s[i]=='b'){
st.push(s[i]);
}
else{
if(st.empty()==true){
st.push('a');
}
else if(st.top()=='a'){
st.push('a');
}
else{
while(st.empty()==false and st.top()=='b'){
cnt++;
st.pop();
}
st.push('a');
}
}
}
return cnt;
}
};
for both the exapmles the answer should be 2,2
but my code it giving 3,2
I recommend to learn some test framework. IMO two best are:
gtest - industry standard - old but quite powerful
catch2 - nice and more user friendly, quickly gains popularity.
Write test code which will validate your solution then use it with a debugger to find issue in your code.
Here is an example with catch2:
https://godbolt.org/z/xevvPrEeK
TEST_CASE("Sum") {
auto [result, s] = GENERATE(table<int, std::string>({
{ 0, ""},
{ 0, "a"},
{ 0, "b"},
{ 0, "ab"},
{ 1, "ba"},
{ 1, "bba"},
{ 1, "baa"},
{ 1, "aba"},
{ 2, "aababbab" },
{ 2, "bbaaaaabb" },
}));
INFO("s = " << s);
REQUIRE(result == Solution{}.minimumDeletions(s));
}
Note this test finds simplest case where your code fails.
On problem: use of the stack is obsolete. Just try find place where you have to delete all bs before it and all as after it.
Related
I am a beginner currently in first semester. I have been practising on Code Chef and am stuck at this problem. They are asking to reduce the execution time of my code. The problem goes as follows:
Meliodas and Ban are fighting over chocolates. Meliodas has X chocolates, while Ban has Y. Whoever has lesser number of chocolates eats as many chocolates as he has from the other's collection. This eatfest war continues till either they have the same number of chocolates, or at least one of them is left with no chocolates.
Can you help Elizabeth predict the total no of chocolates they'll be left with at the end of their war?
Input:
First line will contain T, number of testcases. Then the testcases follow.
Each testcase contains of a single line of input, which contains two integers X,Y, the no of chocolates Meliodas and Ban have, respectively.
Output:
For each testcase, output in a single line the no of chocolates that remain after Ban and Meliodas stop fighting.
Sample Input:
3
5 3
10 10
4 8
Sample Output:
2
20
8
My code is as follows:
#include <iostream>
using namespace std;
int main()
{
unsigned int t,B,M;
cin>>t;
while(t--)
{
cin>>M>>B;
if(B==M)
{
cout<<B+M<<endl;
}
else
{
for(int i=1;B!=M;i++)
{
if(B>M)
B=B-M;
else
M=M-B;
}
cout<<M+B<<endl;
}
}
return 0;
}
Assuming that Band Mare different from 0, this algorithm corresponds to one version of the Euclidean algorithm. Therefore, you can simply:
std::cout << 2 * std::gcd(B, M) << "\n";
If at least one of the quantity is equal to 0, then just print B + M.
After realizing that your code was correct, I wondered where could be any algorithmic improvement. And I realized that eating as many chocolate from the peer as one has was in fact close to a modulo operation. If both number are close, a minus operation could be slightly faster than a modulo one, but if one number is high, while the other is 1, you immediately get it instead of looping a great number of times...
The key to prevent stupid errors is to realize that if a modulo is 0, that means that the high number is a multiple of the small one and we must stop immediately writing twice the lower value.
And care should be taken that if one of the initial counts are 0, the total number will never change.
So the outer loop should become:
if(B==M || B == 0 || M == 0)
{
cout<<B+M<<"\0";
}
else {
for (;;) {
if (M < B) {
B = B % M;
if (B == 0) {
cout << M * 2 << '\n';
break;
}
}
else {
M = M % B;
if (M == 0) {
cout << B * 2 << '\n';
break;
}
}
}
}
...
Note: no infinite loop is possible here because a modulo ensures that for example is M > B > 0' after M = M % Byou will haveB > M >= 0and as the case== 0` is explicitely handled the number of loops cannot be higher than the lower number.
So I need to make a program that lists all permutations.
There are 4 characters:
"1",
"2",
"R",
"T"
The conditions is that the "R" needs to have "1" before and after him so it sits like this 1-R-1
The "T" condition is that either "1" or "2" are after him so it sits like this T-1 or T-2
The max length should be 10
The output should be like this:
111
112
121
122
1R1
1T1
1T2
211
212
221
222
2T1
2T2
T11
T12
T21
T22
I have managed to figure out the permutations part but I just cannot make them work with the conditions
void displayPermutation(string permutation[], int length){
int i;
for (i=0;i<length;i++){
cout<<permutation[i];
}
cout << endl;
}
void getPermutations(string operatorBank[], int operatorCount,
string permutation[],int permutationLength, int curIndex){
int i;
//stop recursion condition
if(curIndex == permutationLength){
displayPermutation(permutation,permutationLength);
}
else{
for(i = 0; i < operatorCount; i++){
permutation[curIndex] = operatorBank[i];
getPermutations(operatorBank,operatorCount,permutation,
permutationLength,curIndex+1);
}
}
}
int main ()
{
int operatorCount = 4;
int permutationLength = 3;
string operatorBank[] = {"1","2","R","T"};
string permutation[] = {"","","",""}; //empty string
int curIndex = 0;
getPermutations(operatorBank,operatorCount,permutation,
permutationLength,curIndex);
return 0;
}
You got your terms a little mixed up. You're not talking about permutations[1] but about combinations[2].
As far as I can tell you already have the algorithm (recursive backtracking) you're just not checking if your solution is valid, by filtering the solution space. So you're generating all solutions without taking into account any constraint and you print a solution when you reached the permutationLength. At this step you can also check if the solution is valid by checking if it abides by the conditions. If it is you print it, if not you discard it.
Strategy for this would be:
Look for R and check if permutation[idx-1] is 1 and permutation[idx+1] is 1
Look for T and check if permutation[idx+1] is either 1 or 2.
You only print the solution if these conditions are met!
...
if(curIndex == permutationLength){
if (solutionValid()) {
displayPermutation(permutation,permutationLength);
}
}
...
https://mathworld.wolfram.com/Permutation.html
https://mathworld.wolfram.com/Combination.html
Do you mean a recursion like this?
function f(n, str=""){
if (!n)
return [str];
let result = [];
if (n >= 3)
result = result.concat(f(n - 3, str + "1R1"));
if (n >= 2)
result = result
.concat(f(n - 2, str + "T1"))
.concat(f(n - 2, str + "T2"));
return result
.concat(f(n - 1, str + "1"))
.concat(f(n - 1, str + "2"));
}
console.log(f(3));
My input is a range of positive integer values between 0 to 200, and I have to classify each value between ranges:0-24, 25-49, 50-74, 75-99, 100-124, 125-149, 150-174 and 175-200 and then output how many values lie is what range. The values are stored in a text file(TextScores.txt) separated with commas. Here is the code.
ifstream file;
string x;
int y,j;
int count[8]={0};
j=0;
file.open("C:\\Users\\USER\\Desktop\\TestScores.txt");
while(getline(file,x,','))
{
y = stoi(x);
if(y<=24)
{
count[0]++;
}
else
if (y>=25 && y<=49)
{
count[1]++;
}
else
if (y>=50 && y<=74)
{
count[2]++;
}
else
if (y>=75 && y<=99)
{
count[3]++;
}
else
if (y>=100 && y<=124)
{
count[4]++;
}
else
if (y>=124 && y<=149)
{
count[5]++;
}
else
if (y>=150 && y<=174)
{
count[6]++;
}
else
if (y>=175 && y<=200)
{
count[7]++;
}
}
for (int i=0; i<=7; i++)
{
cout<<"Test scores between range "<<setw(3)<<j<<" to "
<<setw(3)<<j+25<<" are "<<count[i]<<endl;
j+=25;
}
Alternatives for the hefty amount of if..else statements can be:
y<=24 ? count[0]++ : y>=25 && y<=49 ? count[1]++ : y>=50 && y<=74
count[2]++ : y>=75 && y<=99 ? count[3]++ : y>=100 && y<=124 ? count[4]++ :
y>=125 && y<=149 ? count[5]++ : y>=150 && y<=174 ? count[6]++ : count[7]++;
Or switch statements. Anyone got any other suggestions?
Note: I studied a little bit of range based for loops but I don't know precisely how to go about them in this situation. If anybody knows how to apply them on the problem specified it will be appreciated. I don't want to go into O.O.P. Thanks.
Notice that your ranges are exactly 25 apart. If you perform integer division on y, you can use that to index into your count array. There is a special case for y=200 because that would return 8, which is outside of your array size.
if (y >=0 && y < 200)
++count[y/25];
else if (y == 200)
++count[7];
As Richard Hodges states in his comment, a shorter, more idiomatic way of writing this would be just:
++count[ std::min(7, y/25) ];
You will need to include the algorithm header to access this function.
Define a struct
struct limit {
int min;
int max;
};
Then an array of that
struct limit limits[] = { {0, 24} {25, 49}, {50, 74} /* and so on */ };
Then loop over the array
while(getline(file,x,','))
{
y = stoi(x);
for (int i = 0; i < sizeof(limits)/sizeof(limits[0]); i++) {
if (y >= limits[i].min && y <= limits[i].max) {
count[i]++;
}
}
}
Of course if the pairs are equidistant the array approach doesn't make sense. Go with my proposal if you need arbitrary integer ranges.
Also note that my proposal is plain C, opposed to the STL based answer from πάντα ῥεῖ.
Besides that you can use a simple mathematical solution for your task, because there are apparently fixed steps of 25 (as was mentioned in this answer), in order to create a generic solution, you could use a std::map<std::pair<int,int>,int> that holds all the possible ranges as key values and run a loop for counting:
std::map<std::pair<int,int>,int> rangeCounts =
{ { 0, 25 }, 0 ,
{ 24, 50 }, 0 ,
{ 49, 75 }, 0 ,
// ...
{ 174, 200 }, 0 ,
};
for(std::unordered_map<std::pair<int,int>,int>::iterator it = rangeCounts.begin();
it != rangeCounts.end();
++it) {
if(y > (it->first).first && y < (it->first).second)
++(it->second);
}
As a side note: Your current range delimiters look strange because of these overlapping lower and higher limits (if else cascade or not).
and I have to classify each value between ranges:0-24, 25-49, 50-74, 75-99, 100-124, 125-149, 150-174 and 175-200 and then output how many values lie is what range.
The ranges (with my example) should look like:
std::map<std::pair<int,int>,int> rangeCounts =
{ { 0, 24 }, 0 ,
{ 25, 49 }, 0 ,
{ 50, 74 }, 0 ,
// ...
{ 175, 200 }, 0 ,
};
and the range condition
if(y >= (it->first).first && y <= (it->first).second)
Note: I studied a little bit of range based for loops but I don't know precisely how to go about them in this situation.
These have nothing to do with your range check problem. A range based for() loop just allow to iterate over a containers contents based on the std::begin() and std::end() standard functions implicitely.
So a range based for loop implementation for my sample would look like
for(auto& entry : rangeCounts) {
if(y >= entry.first.first && y =< entry.first.second)
++entry.second;
}
You have a pattern in the if..else statements. You are making constant range size of 25. So, you should use the division by 25 to find the correct case to make the increment:
while(getline(file,x,','))
{
y = stoi(x);
count[y / 25]++;
}
I am trying to validate mobile using regular expression
so for i have tried
https://regex101.com/#javascript
My Expresion is ((\d[^0-5]|[6-9])\d{9})|^(\d)\1*$
i need validate moblie number like below
1.it should not start with 0-5
e.g 0600432102
2.not all the same or in sequence
e.g 1111111111 or 0123456789 or 9876543210
3.lenght is 10 digit
where i made error.
help me....
thanks ....
This covers all criteria and tests a few numbers. It does however not specify the reason for a number being invalid - I leave that to you.
var numArr = ["1111111111", "0123456789", "9876543210", "8682375827", "83255"];
for (var i = 0; i < numArr.length; i++) {
console.log(numArr[i] + " is " + validate(numArr[i]));
}
function validate(num) {
if ((num.match(/^[6-9]\d{9}$/) && (!num.match(/^([0-9])\1{9}$/))) && (!isIncr(num) && (!isDecr(num)))) {
return ( "Valid") ;
} else {
return ( "Not valid") ;
}
}
function isIncr(num) {
for (var i = 1; i < num.length; i++) {
if (num[i] == parseInt(num[i - 1]) + 1) {
continue;
} else {
return false;
}
}
return true;
}
function isDecr(num) {
for (var i = 1; i < num.length; i++) {
if (num[i] == parseInt(num[i - 1]) - 1) {
continue;
} else {
return false;
}
}
return true;
}
(([6-9])(?!\2{9})\d{9})
will:
Check if the number starts with 6-9. It stores this in match group 2.
Check that the first digit is not followed by exactly 9 (you can set the limits here) repetitions of the same digit.
Continues to find if there are 9 more digits after the first digit.
will not:
Check whether the numbers are ascending/descending order.
Check for patterns such as 6566666666
you can use the following regex:
/^(?!9876543210)(?!([\d])\1{9})[6-9][\d]{9}$/mg
Explanation
(?!9876543210) Check that the string is different (it's the only sequence possible)
(?!([\d])\1{9}) Check that this is not the same number repeated
[6-9][\d]{9} Check that the number start with 6 to 9, followed by 9 numbers
This regex works for repititions and numbers not starting with 0-5.
(?!([0-9])\1{9})(\b[6-9]\d{9})
See demo here: https://regex101.com/r/uJ0vD4/9
It doesn't detect ascending and descending numbers. You can achieve that using a loop in your program
This question already has answers here:
Given a word and a text, we need to return the occurrences of anagrams
(6 answers)
Closed 9 years ago.
For eg. word is for and the text is forxxorfxdofr, anagrams of for will be ofr, orf, fro, etc. So the answer would be 3 for this particular example.
Here is what I came up with.
#include<iostream>
#include<cstring>
using namespace std;
int countAnagram (char *pattern, char *text)
{
int patternLength = strlen(pattern);
int textLength = strlen(text);
int dp1[256] = {0}, dp2[256] = {0}, i, j;
for (i = 0; i < patternLength; i++)
{
dp1[pattern[i]]++;
dp2[text[i]]++;
}
int found = 0, temp = 0;
for (i = 0; i < 256; i++)
{
if (dp1[i]!=dp2[i])
{
temp = 1;
break;
}
}
if (temp == 0)
found++;
for (i = 0; i < textLength - patternLength; i++)
{
temp = 0;
dp2[text[i]]--;
dp2[text[i+patternLength]]++;
for (j = 0; j < 256; j++)
{
if (dp1[j]!=dp2[j])
{
temp = 1;
break;
}
}
if (temp == 0)
found++;
}
return found;
}
int main()
{
char pattern[] = "for";
char text[] = "ofrghofrof";
cout << countAnagram(pattern, text);
}
Does there exist a faster algorithm for the said problem?
Most of the time will be spent searching, so to make the algorithm more time efficient, the objective is to reduce the quantities of searches or optimize the search.
Method 1: A table of search starting positions.
Create a vector of lists, one vector slot for each letter of the alphabet. This can be space-optimized later.
Each slot will contain a list of indices into the text.
Example text: forxxorfxdofr
Slot List
'f' 0 --> 7 --> 11
'o' 1 --> 5 --> 10
'r' 2 --> 6 --> 12
For each word, look up the letter in the vector to get a list of indexes into the text. For each index in the list, compare the text string position from the list item to the word.
So with the above table and the word "ofr", the first compare occurs at index 1, second compare at index 5 and last compare at index 10.
You could eliminate near-end of text indices where (index + word length > text length).
You can use the commutativity of multiplication, along with uniqueness of primal decomposition. This relies on my previous answer here
Create a mapping from each character into a list of prime numbers (as small as possible). For e.g. a-->2, b-->3, c-->5, etc.. This can be kept in a simple array.
Now, convert the given word into the multiplication of the primes matching each of its characters. This results will be equal to a similar multiplication of any anagram of that word.
Now sweep over the array, and at any given step, maintain the multiplication of the primes matching the last L characters (where L is the length of your word). So every time you advance you do
mul = mul * char2prime(text[i]) / char2prime(text[i-L])
Whenever this multiplication equals that of your word - increment the overall counter, and you're done
Note that this method would work well on short words, but the primes multiplication can overflow a 64b var pretty fast (by ~9-10 letters), so you'll have to use a large number math library to support longer words.
This algorithm is reasonably efficient if the pattern to be anagrammed is so short that the best way to search it is to simply scan it. To allow longer patterns, the scans represented here by the 'for jj' and 'for mm' loops could be replaced by more sophisticated search techniques.
// sLine -- string to be searched
// sWord -- pattern to be anagrammed
// (in this pseudo-language, the index of the first character in a string is 0)
// iAnagrams -- count of anagrams found
iLineLim = length(sLine)-1
iWordLim = length(sWord)-1
// we need a 'deleted' marker char that will never appear in the input strings
chNil = chr(0)
iAnagrams = 0 // well we haven't found any yet have we
// examine every posn in sLine where an anagram could possibly start
for ii from 0 to iLineLim-iWordLim do {
chK = sLine[ii]
// does the char at this position in sLine also appear in sWord
for jj from 0 to iWordLim do {
if sWord[jj]=chK then {
// yes -- we have a candidate starting posn in sLine
// is there an anagram of sWord at this position in sLine
sCopy = sWord // make a temp copy that we will delete one char at a time
sCopy[jj] = chNil // delete the char we already found in sLine
// the rest of the anagram would have to be in the next iWordLim positions
for kk from ii+1 to ii+iWordLim do {
chK = sLine[kk]
cc = false
for mm from 0 to iWordLim do { // look for anagram char
if sCopy[mm]=chK then { // found one
cc = true
sCopy[mm] = chNil // delete it from copy
break // out of 'for mm'
}
}
if not cc then break // out of 'for kk' -- no anagram char here
}
if cc then { iAnagrams = iAnagrams+1 }
break // out of 'for jj'
}
}
}
-Al.