Given a string s, repeatedly remove any group of exactly three consecutive identical characters. After each removal, concatenate the remaining parts of the string and continue removing such groups until no more removals are possible. Return the final string after all possible removals. If the resulting string is empty, return "-1".
Examples:
Input: s = "aabbbaccddddc"
Output: ccdc
Explanation: First remove "aaa" to obtain "bbbaccdddddc". Next remove "bbb" to obtain "accdddddc". Finally, remove "ddd" to obtain "ccddc". No more groups of three consecutive identical characters remain, so the reduced string is "ccddc".
Input: s = "aaabbbccc"
Output: -1
Explanation: Remove "aaa" to obtain "bbbccc". Next remove "bbb" to obtain "ccc". Finally, remove "ccc" to obtain an empty string. Since no characters remain, return "-1".
Table of Content
[Naive Approach] Repeated Scanning and Deletion - O(n ^ 2) Time and O(1) Space
The idea is to repeatedly scan the string and remove any group of three consecutive identical characters. After each removal, concatenate the remaining parts of the string and start scanning again from the beginning, since new groups may be formed. Continue this process until no more groups can be removed.
#include <iostream>
#include <string>
using namespace std;
string reducedString(string &s)
{
while (true)
{
bool removed = false;
for (int i = 0; i + 2 < s.size(); i++)
{
// Remove three consecutive identical characters.
if (s[i] == s[i + 1] && s[i] == s[i + 2])
{
s.erase(i, 3);
removed = true;
break;
}
}
if (!removed)
break;
}
return s.empty() ? "-1" : s;
}
int main()
{
string s = "aabbbaccddddc";
cout << reducedString(s);
return 0;
}
class GFG {
static String reducedString(String s)
{
StringBuilder str = new StringBuilder(s);
while (true) {
boolean removed = false;
for (int i = 0; i + 2 < str.length(); i++) {
// Remove three consecutive identical
// characters.
if (str.charAt(i) == str.charAt(i + 1)
&& str.charAt(i) == str.charAt(i + 2)) {
str.delete(i, i + 3);
removed = true;
break;
}
}
if (!removed)
break;
}
return str.length() == 0 ? "-1" : str.toString();
}
public static void main(String[] args)
{
String s = "aabbbaccddddc";
System.out.println(reducedString(s));
}
}
def reducedString(s):
while True:
removed = False
for i in range(len(s) - 2):
# Remove three consecutive identical characters.
if s[i] == s[i + 1] and s[i] == s[i + 2]:
s = s[:i] + s[i + 3:]
removed = True
break
if not removed:
break
return "-1" if not s else s
if __name__ == "__main__":
s = "aabbbaccddddc"
print(reducedString(s))
using System;
class GFG {
static string reducedString(string s)
{
while (true) {
bool removed = false;
char[] charArray = s.ToCharArray();
for (int i = 0; i + 2 < charArray.Length; i++) {
// Remove three consecutive identical
// characters.
if (charArray[i] == charArray[i + 1]
&& charArray[i] == charArray[i + 2]) {
s = s.Remove(i, 3);
removed = true;
break;
}
}
if (!removed)
break;
}
return string.IsNullOrEmpty(s) ? "-1" : s;
}
static void Main()
{
string s = "aabbbaccddddc";
Console.WriteLine(reducedString(s));
}
}
function reducedString(s)
{
while (true) {
let removed = false;
for (let i = 0; i + 2 < s.length; i++) {
// Remove three consecutive identical
// characters.
if (s[i] === s[i + 1] && s[i] === s[i + 2]) {
s = s.slice(0, i) + s.slice(i + 3);
removed = true;
break;
}
}
if (!removed) {
break;
}
}
return s.length === 0 ? "-1" : s;
}
// Driver Code
let s = "aabbbaccddddc";
console.log(reducedString(s));
Output
ccdc
[Expected Approach] Using Stack with Character Frequency - O(n) Time and O(n) Space
The idea is to process the string from left to right while maintaining a stack of character-frequency pairs. If the current character is the same as the top of the stack, increase its frequency; otherwise, push it as a new group. Whenever a group's frequency becomes three, remove it immediately. Finally, reconstruct the remaining string from the stack.
Let us understand with an example:
Input: s = "aabbbaccddddc"
- Traverse the string from left to right and maintain a stack of (character, frequency) pairs.
- For each character, increment the frequency if it matches the top of the stack; otherwise, push it as a new group.
- Whenever the frequency of the top group becomes 3, immediately remove that group by popping it from the stack.
- After processing all characters, reconstruct the remaining string by popping all stack elements and reversing the result.
- For s = "aabbbaccddddc", the remaining string is "aaccdc".
#include <algorithm>
#include <iostream>
#include <stack>
#include <string>
using namespace std;
string reducedString(string &s)
{
// Store each character along with its consecutive frequency.
stack<pair<char, int>> st;
for (char ch : s)
{
if (!st.empty() && st.top().first == ch)
{
st.top().second++;
}
else
{
st.push({ch, 1});
}
// Remove the group once its frequency becomes three.
if (!st.empty() && st.top().second == 3)
{
st.pop();
}
}
// Reconstruct the reduced string from the stack.
string ans;
ans.reserve(s.size());
while (!st.empty())
{
ans.append(st.top().second, st.top().first);
st.pop();
}
reverse(ans.begin(), ans.end());
// Return "-1" if all characters are removed.
return ans.empty() ? "-1" : ans;
}
int main()
{
string s = "aabbbaccddddc";
cout << reducedString(s);
return 0;
}
import java.util.Stack;
class GFG {
static String reducedString(String s)
{
// Store each character along with its consecutive
// frequency.
Stack<Pair> st = new Stack<>();
for (char ch : s.toCharArray()) {
if (!st.isEmpty() && st.peek().ch == ch) {
st.peek().freq++;
}
else {
st.push(new Pair(ch, 1));
}
// Remove the group once its frequency becomes
// three.
if (!st.isEmpty() && st.peek().freq == 3) {
st.pop();
}
}
// Reconstruct the reduced string from the stack.
StringBuilder ans = new StringBuilder();
while (!st.isEmpty()) {
Pair p = st.pop();
for (int i = 0; i < p.freq; i++) {
ans.append(p.ch);
}
}
ans.reverse();
// Return "-1" if all characters are removed.
return ans.length() == 0 ? "-1" : ans.toString();
}
static class Pair {
char ch;
int freq;
Pair(char ch, int freq)
{
this.ch = ch;
this.freq = freq;
}
}
public static void main(String[] args)
{
String s = "aabbbaccddddc";
System.out.println(reducedString(s));
}
}
def reducedString(s):
# Store each character along with its consecutive frequency.
st = []
for ch in s:
if st and st[-1][0] == ch:
st[-1][1] += 1
else:
st.append([ch, 1])
# Remove the group once its frequency becomes three.
if st and st[-1][1] == 3:
st.pop()
# Reconstruct the reduced string from the stack.
ans = []
while st:
ch, freq = st.pop()
ans.append(ch * freq)
ans.reverse()
ans = "".join(ans)
# Return "-1" if all characters are removed.
return "-1" if not ans else ans
if __name__ == "__main__":
s = "aabbbaccddddc"
print(reducedString(s))
using System;
using System.Collections.Generic;
using System.Text;
class GFG {
static string reducedString(string s)
{
// Store each character along with its consecutive
// frequency.
Stack<(char ch, int freq)> st
= new Stack<(char ch, int freq)>();
foreach(char ch in s)
{
if (st.Count > 0 && st.Peek().ch == ch) {
var top = st.Pop();
top.freq++;
st.Push(top);
}
else {
st.Push((ch, 1));
}
// Remove the group once its frequency becomes
// three.
if (st.Count > 0 && st.Peek().freq == 3) {
st.Pop();
}
}
// Reconstruct the reduced string from the stack.
StringBuilder ans = new StringBuilder();
while (st.Count > 0) {
var top = st.Pop();
ans.Append(new string(top.ch, top.freq));
}
char[] arr = ans.ToString().ToCharArray();
Array.Reverse(arr);
ans = new StringBuilder(new string(arr));
// Return "-1" if all characters are removed.
return ans.Length == 0 ? "-1" : ans.ToString();
}
static void Main()
{
string s = "aabbbaccddddc";
Console.WriteLine(reducedString(s));
}
}
function reducedString(s)
{
// Store each character along with its consecutive
// frequency.
let st = [];
for (let ch of s) {
if (st.length > 0 && st[st.length - 1][0] === ch) {
st[st.length - 1][1]++;
}
else {
st.push([ ch, 1 ]);
}
// Remove the group once its frequency becomes
// three.
if (st.length > 0 && st[st.length - 1][1] === 3) {
st.pop();
}
}
// Reconstruct the reduced string from the stack.
let ans = "";
while (st.length > 0) {
let [ch, freq] = st.pop();
ans += ch.repeat(freq);
}
ans = ans.split("").reverse().join("");
// Return "-1" if all characters are removed.
return ans.length === 0 ? "-1" : ans;
}
// driver code
let s = "aabbbaccddddc";
console.log(reducedString(s));
Output
ccdc