Remove all adjacent duplicates in a string using a Stack

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
Input: careermonk
Output: camonk
Input: mississippi
Output: m
I want to improve this code.
#include <iostream>
#include <string>
#define max 1000
class Stack
int top;
public:
char stk[max];
Stack()
top = -1;
bool isStackEmpty();
void push(char);
char pop();
std::string modifyString(std::string);
private:
void removeAdjacentDuplicate(std::string);
;
bool Stack::isStackEmpty()
if (top == -1)
return true;
else
return false;
void Stack::push(char val)
int s = max - 1;
if (top < s)
top = top + 1;
stk[top] = val;
else
std::cerr << "Stack Overflow n";
char Stack::pop()
if (isStackEmpty() == true)
std::cerr << "Stack Underflow n";
else
--top;
return stk[top + 1];
void Stack::removeAdjacentDuplicate(std::string str)
int len = str.length();
for (int i = 0; i < len; i++)
if (isStackEmpty() == true)
push(str[i]);
else if (str[i] == stk[top])
int discard = pop();
else
push(str[i]);
std::string Stack::modifyString(std::string str)
removeAdjacentDuplicate(str);
str.resize(top + 1);
for (int i = 0; i <= top; i++)
str[i] = stk[i];
str[top + 1] = '';
return str;
int main()
Stack stack1;
std::string str = "careermonk";
std::cout << "Orignal string : " << str << "n";
str = stack1.modifyString(str);
std::cout << "New string : " << str << "n";
Stack stack2;
std::string str2 = "mississippi";
std::cout << "Original string : " << str2 << "n";
str2 = stack2.modifyString(str2);
std::cout << "New string : " << str2 << "n";
c++ strings stack
add a comment |Â
up vote
1
down vote
favorite
Input: careermonk
Output: camonk
Input: mississippi
Output: m
I want to improve this code.
#include <iostream>
#include <string>
#define max 1000
class Stack
int top;
public:
char stk[max];
Stack()
top = -1;
bool isStackEmpty();
void push(char);
char pop();
std::string modifyString(std::string);
private:
void removeAdjacentDuplicate(std::string);
;
bool Stack::isStackEmpty()
if (top == -1)
return true;
else
return false;
void Stack::push(char val)
int s = max - 1;
if (top < s)
top = top + 1;
stk[top] = val;
else
std::cerr << "Stack Overflow n";
char Stack::pop()
if (isStackEmpty() == true)
std::cerr << "Stack Underflow n";
else
--top;
return stk[top + 1];
void Stack::removeAdjacentDuplicate(std::string str)
int len = str.length();
for (int i = 0; i < len; i++)
if (isStackEmpty() == true)
push(str[i]);
else if (str[i] == stk[top])
int discard = pop();
else
push(str[i]);
std::string Stack::modifyString(std::string str)
removeAdjacentDuplicate(str);
str.resize(top + 1);
for (int i = 0; i <= top; i++)
str[i] = stk[i];
str[top + 1] = '';
return str;
int main()
Stack stack1;
std::string str = "careermonk";
std::cout << "Orignal string : " << str << "n";
str = stack1.modifyString(str);
std::cout << "New string : " << str << "n";
Stack stack2;
std::string str2 = "mississippi";
std::cout << "Original string : " << str2 << "n";
str2 = stack2.modifyString(str2);
std::cout << "New string : " << str2 << "n";
c++ strings stack
a Stack is FILO, so maybe try and reverse the order of: void Stack::removeAdjacentDuplicate(std::string str) and see if this helps.
â xyz
Feb 11 at 14:17
How do you want to improve it?
â Juho
Feb 11 at 16:28
@Juho using STL or better logic.
â coder
Feb 11 at 17:40
What do you want to happen with odd numbers of similar characters, such assteeel? Your code appears to only remove adjacent pairs, but the example inputs don't give a clear requirement.
â Toby Speight
Feb 14 at 17:38
Better real-life examples:gazetteer,addressees,keenness
â Toby Speight
Feb 14 at 18:27
add a comment |Â
up vote
1
down vote
favorite
up vote
1
down vote
favorite
Input: careermonk
Output: camonk
Input: mississippi
Output: m
I want to improve this code.
#include <iostream>
#include <string>
#define max 1000
class Stack
int top;
public:
char stk[max];
Stack()
top = -1;
bool isStackEmpty();
void push(char);
char pop();
std::string modifyString(std::string);
private:
void removeAdjacentDuplicate(std::string);
;
bool Stack::isStackEmpty()
if (top == -1)
return true;
else
return false;
void Stack::push(char val)
int s = max - 1;
if (top < s)
top = top + 1;
stk[top] = val;
else
std::cerr << "Stack Overflow n";
char Stack::pop()
if (isStackEmpty() == true)
std::cerr << "Stack Underflow n";
else
--top;
return stk[top + 1];
void Stack::removeAdjacentDuplicate(std::string str)
int len = str.length();
for (int i = 0; i < len; i++)
if (isStackEmpty() == true)
push(str[i]);
else if (str[i] == stk[top])
int discard = pop();
else
push(str[i]);
std::string Stack::modifyString(std::string str)
removeAdjacentDuplicate(str);
str.resize(top + 1);
for (int i = 0; i <= top; i++)
str[i] = stk[i];
str[top + 1] = '';
return str;
int main()
Stack stack1;
std::string str = "careermonk";
std::cout << "Orignal string : " << str << "n";
str = stack1.modifyString(str);
std::cout << "New string : " << str << "n";
Stack stack2;
std::string str2 = "mississippi";
std::cout << "Original string : " << str2 << "n";
str2 = stack2.modifyString(str2);
std::cout << "New string : " << str2 << "n";
c++ strings stack
Input: careermonk
Output: camonk
Input: mississippi
Output: m
I want to improve this code.
#include <iostream>
#include <string>
#define max 1000
class Stack
int top;
public:
char stk[max];
Stack()
top = -1;
bool isStackEmpty();
void push(char);
char pop();
std::string modifyString(std::string);
private:
void removeAdjacentDuplicate(std::string);
;
bool Stack::isStackEmpty()
if (top == -1)
return true;
else
return false;
void Stack::push(char val)
int s = max - 1;
if (top < s)
top = top + 1;
stk[top] = val;
else
std::cerr << "Stack Overflow n";
char Stack::pop()
if (isStackEmpty() == true)
std::cerr << "Stack Underflow n";
else
--top;
return stk[top + 1];
void Stack::removeAdjacentDuplicate(std::string str)
int len = str.length();
for (int i = 0; i < len; i++)
if (isStackEmpty() == true)
push(str[i]);
else if (str[i] == stk[top])
int discard = pop();
else
push(str[i]);
std::string Stack::modifyString(std::string str)
removeAdjacentDuplicate(str);
str.resize(top + 1);
for (int i = 0; i <= top; i++)
str[i] = stk[i];
str[top + 1] = '';
return str;
int main()
Stack stack1;
std::string str = "careermonk";
std::cout << "Orignal string : " << str << "n";
str = stack1.modifyString(str);
std::cout << "New string : " << str << "n";
Stack stack2;
std::string str2 = "mississippi";
std::cout << "Original string : " << str2 << "n";
str2 = stack2.modifyString(str2);
std::cout << "New string : " << str2 << "n";
c++ strings stack
asked Feb 9 at 19:27
coder
911425
911425
a Stack is FILO, so maybe try and reverse the order of: void Stack::removeAdjacentDuplicate(std::string str) and see if this helps.
â xyz
Feb 11 at 14:17
How do you want to improve it?
â Juho
Feb 11 at 16:28
@Juho using STL or better logic.
â coder
Feb 11 at 17:40
What do you want to happen with odd numbers of similar characters, such assteeel? Your code appears to only remove adjacent pairs, but the example inputs don't give a clear requirement.
â Toby Speight
Feb 14 at 17:38
Better real-life examples:gazetteer,addressees,keenness
â Toby Speight
Feb 14 at 18:27
add a comment |Â
a Stack is FILO, so maybe try and reverse the order of: void Stack::removeAdjacentDuplicate(std::string str) and see if this helps.
â xyz
Feb 11 at 14:17
How do you want to improve it?
â Juho
Feb 11 at 16:28
@Juho using STL or better logic.
â coder
Feb 11 at 17:40
What do you want to happen with odd numbers of similar characters, such assteeel? Your code appears to only remove adjacent pairs, but the example inputs don't give a clear requirement.
â Toby Speight
Feb 14 at 17:38
Better real-life examples:gazetteer,addressees,keenness
â Toby Speight
Feb 14 at 18:27
a Stack is FILO, so maybe try and reverse the order of: void Stack::removeAdjacentDuplicate(std::string str) and see if this helps.
â xyz
Feb 11 at 14:17
a Stack is FILO, so maybe try and reverse the order of: void Stack::removeAdjacentDuplicate(std::string str) and see if this helps.
â xyz
Feb 11 at 14:17
How do you want to improve it?
â Juho
Feb 11 at 16:28
How do you want to improve it?
â Juho
Feb 11 at 16:28
@Juho using STL or better logic.
â coder
Feb 11 at 17:40
@Juho using STL or better logic.
â coder
Feb 11 at 17:40
What do you want to happen with odd numbers of similar characters, such as
steeel? Your code appears to only remove adjacent pairs, but the example inputs don't give a clear requirement.â Toby Speight
Feb 14 at 17:38
What do you want to happen with odd numbers of similar characters, such as
steeel? Your code appears to only remove adjacent pairs, but the example inputs don't give a clear requirement.â Toby Speight
Feb 14 at 17:38
Better real-life examples:
gazetteer, addressees, keennessâ Toby Speight
Feb 14 at 18:27
Better real-life examples:
gazetteer, addressees, keennessâ Toby Speight
Feb 14 at 18:27
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
2
down vote
std::array
You could use std::array and get rid of max define. In general, I'd like to suggest avoiding defines which can conflict with any stl names by any cost.
One of Windows header has its own #define max and this is horrible when your code wants std::numeric_limits<int>::max(), std::max(a, b, c), etc.
Things are even worse if you're writing header only library:
#if defined max
# undef max
# define HAD_MAX
#endif
// ... C++ code ...
#if defined HAD_MAX
# define max(a, b) ... // copy-paste from Windows.h
#endif
Stack::removeAdjacentDuplicate signature
Signature of Stack::removeAdjacentDuplicate(std::string) can be improved:
At least, it doesn't actually removes anything. It perform some kind of initialization from given string, so consider choosing more intuitive name.
Additionally, avoid copying parameter - you can use const std::string&
Stack::modifyString
Stack::modifyString also says nothing about its purpose and it also constructs another string instead of modifying something. Consider better naming.
Use standard library
When copying N characters, consider using standard library functions instead of for loop: strncpy, memcpy, std::copy_n and others works fine, looks clear and may perform some performance optimizations.
Use standard library (alternative)
As alternative, you can construct new string directly from Stack::stk. There is corresponding constructor: std::string(const char* s, size_t n);. In this case you can pass all std::string parameters by const reference.
BTW, I'm assure you're already bored with my variable naming suggestions, so I don't need to add another one here :)
Non-const public members are dangerous
Consider using some naming conventions
It's hard to determine whether some variable is a class member or not. In order to simplify your work, make member variables somehow. You can use m_member, member_, etc.
add a comment |Â
up vote
1
down vote
Avoid arbitrary limits
The definition of max (and especially as a #define rather than as a C++ constant) is worrying. Especially as the checking simply prints a diagnostic and then ignores the action that was requested.
Simple refactorings
if (test) return true; else return false; is the same as return test;. So we can write
bool Stack::isStackEmpty()
return top == -1;
Similarly, testing ==true is redundant:
if (isStackEmpty())
A more involved refactoring
void Stack::removeAdjacentDuplicate(std::string str)
int len = str.length();
for (int i = 0; i < len; i++)
if (isStackEmpty() == true)
push(str[i]);
else if (str[i] == stk[top])
int discard = pop();
else
push(str[i]);
Here, we're iterating over the elements of str, so we can use for (char c: str), which is clearer and less error-prone than using indexes.
The first and last branch are the same, so we can change the condition to bring them together:
void Stack::removeAdjacentDuplicate(const std::string& str)
for (auto c: str)
if (isStackEmpty()
Think like standard algorithms
We have standard algorithms - one similar to our needs is std::unique(). This makes a single pass over its input, and returns an iterator to the new end position.
If we make a function with a similar interface, we can use the 'erase/remove' idiom to replace characters in a string:
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
How do we implement repeatedly_remove_duplicates()? I would assume a single pass called remove_duplicates(), and call it until the returned end doesn't change:
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
(I've made this a template, so it can work with any container. The also allows us to make repeatedly_remove_duplicates() a template to work with any string type, including std::wstring, for instance).
Now, we need an implementation of remove_duplicates. We can do this in-place:
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
auto dest = begin;
if (begin == end) return dest;
auto prev = begin;
bool is_duplicate = false;
while (++begin != end)
if (*begin == *prev)
is_duplicate = true;
else
if (!is_duplicate)
*dest++ = *prev;
is_duplicate = false;
prev = begin;
if (!is_duplicate)
*dest++ = *prev;
return dest;
There are other ways to do this; we might use std::adjacent_find(), for example:
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
while (begin != end);
return dest;
Putting it all together
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
#ifdef REMOVE_PAIR_ONLY
begin = pair;
if (pair != end)
begin += 2;
#else
begin = std::adjacent_find(pair, end, not_equal_to());
if (begin != end)
++begin;
#endif
while (begin != end);
return dest;
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
#include <iostream>
int main(int argc, char **argv)
for (auto i = 1; i < argc; ++i)
std::cout << argv[i] << " â "
<< repeatedly_remove_duplicates(argv[i])
<< std::endl;
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
std::array
You could use std::array and get rid of max define. In general, I'd like to suggest avoiding defines which can conflict with any stl names by any cost.
One of Windows header has its own #define max and this is horrible when your code wants std::numeric_limits<int>::max(), std::max(a, b, c), etc.
Things are even worse if you're writing header only library:
#if defined max
# undef max
# define HAD_MAX
#endif
// ... C++ code ...
#if defined HAD_MAX
# define max(a, b) ... // copy-paste from Windows.h
#endif
Stack::removeAdjacentDuplicate signature
Signature of Stack::removeAdjacentDuplicate(std::string) can be improved:
At least, it doesn't actually removes anything. It perform some kind of initialization from given string, so consider choosing more intuitive name.
Additionally, avoid copying parameter - you can use const std::string&
Stack::modifyString
Stack::modifyString also says nothing about its purpose and it also constructs another string instead of modifying something. Consider better naming.
Use standard library
When copying N characters, consider using standard library functions instead of for loop: strncpy, memcpy, std::copy_n and others works fine, looks clear and may perform some performance optimizations.
Use standard library (alternative)
As alternative, you can construct new string directly from Stack::stk. There is corresponding constructor: std::string(const char* s, size_t n);. In this case you can pass all std::string parameters by const reference.
BTW, I'm assure you're already bored with my variable naming suggestions, so I don't need to add another one here :)
Non-const public members are dangerous
Consider using some naming conventions
It's hard to determine whether some variable is a class member or not. In order to simplify your work, make member variables somehow. You can use m_member, member_, etc.
add a comment |Â
up vote
2
down vote
std::array
You could use std::array and get rid of max define. In general, I'd like to suggest avoiding defines which can conflict with any stl names by any cost.
One of Windows header has its own #define max and this is horrible when your code wants std::numeric_limits<int>::max(), std::max(a, b, c), etc.
Things are even worse if you're writing header only library:
#if defined max
# undef max
# define HAD_MAX
#endif
// ... C++ code ...
#if defined HAD_MAX
# define max(a, b) ... // copy-paste from Windows.h
#endif
Stack::removeAdjacentDuplicate signature
Signature of Stack::removeAdjacentDuplicate(std::string) can be improved:
At least, it doesn't actually removes anything. It perform some kind of initialization from given string, so consider choosing more intuitive name.
Additionally, avoid copying parameter - you can use const std::string&
Stack::modifyString
Stack::modifyString also says nothing about its purpose and it also constructs another string instead of modifying something. Consider better naming.
Use standard library
When copying N characters, consider using standard library functions instead of for loop: strncpy, memcpy, std::copy_n and others works fine, looks clear and may perform some performance optimizations.
Use standard library (alternative)
As alternative, you can construct new string directly from Stack::stk. There is corresponding constructor: std::string(const char* s, size_t n);. In this case you can pass all std::string parameters by const reference.
BTW, I'm assure you're already bored with my variable naming suggestions, so I don't need to add another one here :)
Non-const public members are dangerous
Consider using some naming conventions
It's hard to determine whether some variable is a class member or not. In order to simplify your work, make member variables somehow. You can use m_member, member_, etc.
add a comment |Â
up vote
2
down vote
up vote
2
down vote
std::array
You could use std::array and get rid of max define. In general, I'd like to suggest avoiding defines which can conflict with any stl names by any cost.
One of Windows header has its own #define max and this is horrible when your code wants std::numeric_limits<int>::max(), std::max(a, b, c), etc.
Things are even worse if you're writing header only library:
#if defined max
# undef max
# define HAD_MAX
#endif
// ... C++ code ...
#if defined HAD_MAX
# define max(a, b) ... // copy-paste from Windows.h
#endif
Stack::removeAdjacentDuplicate signature
Signature of Stack::removeAdjacentDuplicate(std::string) can be improved:
At least, it doesn't actually removes anything. It perform some kind of initialization from given string, so consider choosing more intuitive name.
Additionally, avoid copying parameter - you can use const std::string&
Stack::modifyString
Stack::modifyString also says nothing about its purpose and it also constructs another string instead of modifying something. Consider better naming.
Use standard library
When copying N characters, consider using standard library functions instead of for loop: strncpy, memcpy, std::copy_n and others works fine, looks clear and may perform some performance optimizations.
Use standard library (alternative)
As alternative, you can construct new string directly from Stack::stk. There is corresponding constructor: std::string(const char* s, size_t n);. In this case you can pass all std::string parameters by const reference.
BTW, I'm assure you're already bored with my variable naming suggestions, so I don't need to add another one here :)
Non-const public members are dangerous
Consider using some naming conventions
It's hard to determine whether some variable is a class member or not. In order to simplify your work, make member variables somehow. You can use m_member, member_, etc.
std::array
You could use std::array and get rid of max define. In general, I'd like to suggest avoiding defines which can conflict with any stl names by any cost.
One of Windows header has its own #define max and this is horrible when your code wants std::numeric_limits<int>::max(), std::max(a, b, c), etc.
Things are even worse if you're writing header only library:
#if defined max
# undef max
# define HAD_MAX
#endif
// ... C++ code ...
#if defined HAD_MAX
# define max(a, b) ... // copy-paste from Windows.h
#endif
Stack::removeAdjacentDuplicate signature
Signature of Stack::removeAdjacentDuplicate(std::string) can be improved:
At least, it doesn't actually removes anything. It perform some kind of initialization from given string, so consider choosing more intuitive name.
Additionally, avoid copying parameter - you can use const std::string&
Stack::modifyString
Stack::modifyString also says nothing about its purpose and it also constructs another string instead of modifying something. Consider better naming.
Use standard library
When copying N characters, consider using standard library functions instead of for loop: strncpy, memcpy, std::copy_n and others works fine, looks clear and may perform some performance optimizations.
Use standard library (alternative)
As alternative, you can construct new string directly from Stack::stk. There is corresponding constructor: std::string(const char* s, size_t n);. In this case you can pass all std::string parameters by const reference.
BTW, I'm assure you're already bored with my variable naming suggestions, so I don't need to add another one here :)
Non-const public members are dangerous
Consider using some naming conventions
It's hard to determine whether some variable is a class member or not. In order to simplify your work, make member variables somehow. You can use m_member, member_, etc.
edited Feb 14 at 14:44
answered Feb 14 at 14:38
Victor Istomin
1313
1313
add a comment |Â
add a comment |Â
up vote
1
down vote
Avoid arbitrary limits
The definition of max (and especially as a #define rather than as a C++ constant) is worrying. Especially as the checking simply prints a diagnostic and then ignores the action that was requested.
Simple refactorings
if (test) return true; else return false; is the same as return test;. So we can write
bool Stack::isStackEmpty()
return top == -1;
Similarly, testing ==true is redundant:
if (isStackEmpty())
A more involved refactoring
void Stack::removeAdjacentDuplicate(std::string str)
int len = str.length();
for (int i = 0; i < len; i++)
if (isStackEmpty() == true)
push(str[i]);
else if (str[i] == stk[top])
int discard = pop();
else
push(str[i]);
Here, we're iterating over the elements of str, so we can use for (char c: str), which is clearer and less error-prone than using indexes.
The first and last branch are the same, so we can change the condition to bring them together:
void Stack::removeAdjacentDuplicate(const std::string& str)
for (auto c: str)
if (isStackEmpty()
Think like standard algorithms
We have standard algorithms - one similar to our needs is std::unique(). This makes a single pass over its input, and returns an iterator to the new end position.
If we make a function with a similar interface, we can use the 'erase/remove' idiom to replace characters in a string:
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
How do we implement repeatedly_remove_duplicates()? I would assume a single pass called remove_duplicates(), and call it until the returned end doesn't change:
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
(I've made this a template, so it can work with any container. The also allows us to make repeatedly_remove_duplicates() a template to work with any string type, including std::wstring, for instance).
Now, we need an implementation of remove_duplicates. We can do this in-place:
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
auto dest = begin;
if (begin == end) return dest;
auto prev = begin;
bool is_duplicate = false;
while (++begin != end)
if (*begin == *prev)
is_duplicate = true;
else
if (!is_duplicate)
*dest++ = *prev;
is_duplicate = false;
prev = begin;
if (!is_duplicate)
*dest++ = *prev;
return dest;
There are other ways to do this; we might use std::adjacent_find(), for example:
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
while (begin != end);
return dest;
Putting it all together
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
#ifdef REMOVE_PAIR_ONLY
begin = pair;
if (pair != end)
begin += 2;
#else
begin = std::adjacent_find(pair, end, not_equal_to());
if (begin != end)
++begin;
#endif
while (begin != end);
return dest;
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
#include <iostream>
int main(int argc, char **argv)
for (auto i = 1; i < argc; ++i)
std::cout << argv[i] << " â "
<< repeatedly_remove_duplicates(argv[i])
<< std::endl;
add a comment |Â
up vote
1
down vote
Avoid arbitrary limits
The definition of max (and especially as a #define rather than as a C++ constant) is worrying. Especially as the checking simply prints a diagnostic and then ignores the action that was requested.
Simple refactorings
if (test) return true; else return false; is the same as return test;. So we can write
bool Stack::isStackEmpty()
return top == -1;
Similarly, testing ==true is redundant:
if (isStackEmpty())
A more involved refactoring
void Stack::removeAdjacentDuplicate(std::string str)
int len = str.length();
for (int i = 0; i < len; i++)
if (isStackEmpty() == true)
push(str[i]);
else if (str[i] == stk[top])
int discard = pop();
else
push(str[i]);
Here, we're iterating over the elements of str, so we can use for (char c: str), which is clearer and less error-prone than using indexes.
The first and last branch are the same, so we can change the condition to bring them together:
void Stack::removeAdjacentDuplicate(const std::string& str)
for (auto c: str)
if (isStackEmpty()
Think like standard algorithms
We have standard algorithms - one similar to our needs is std::unique(). This makes a single pass over its input, and returns an iterator to the new end position.
If we make a function with a similar interface, we can use the 'erase/remove' idiom to replace characters in a string:
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
How do we implement repeatedly_remove_duplicates()? I would assume a single pass called remove_duplicates(), and call it until the returned end doesn't change:
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
(I've made this a template, so it can work with any container. The also allows us to make repeatedly_remove_duplicates() a template to work with any string type, including std::wstring, for instance).
Now, we need an implementation of remove_duplicates. We can do this in-place:
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
auto dest = begin;
if (begin == end) return dest;
auto prev = begin;
bool is_duplicate = false;
while (++begin != end)
if (*begin == *prev)
is_duplicate = true;
else
if (!is_duplicate)
*dest++ = *prev;
is_duplicate = false;
prev = begin;
if (!is_duplicate)
*dest++ = *prev;
return dest;
There are other ways to do this; we might use std::adjacent_find(), for example:
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
while (begin != end);
return dest;
Putting it all together
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
#ifdef REMOVE_PAIR_ONLY
begin = pair;
if (pair != end)
begin += 2;
#else
begin = std::adjacent_find(pair, end, not_equal_to());
if (begin != end)
++begin;
#endif
while (begin != end);
return dest;
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
#include <iostream>
int main(int argc, char **argv)
for (auto i = 1; i < argc; ++i)
std::cout << argv[i] << " â "
<< repeatedly_remove_duplicates(argv[i])
<< std::endl;
add a comment |Â
up vote
1
down vote
up vote
1
down vote
Avoid arbitrary limits
The definition of max (and especially as a #define rather than as a C++ constant) is worrying. Especially as the checking simply prints a diagnostic and then ignores the action that was requested.
Simple refactorings
if (test) return true; else return false; is the same as return test;. So we can write
bool Stack::isStackEmpty()
return top == -1;
Similarly, testing ==true is redundant:
if (isStackEmpty())
A more involved refactoring
void Stack::removeAdjacentDuplicate(std::string str)
int len = str.length();
for (int i = 0; i < len; i++)
if (isStackEmpty() == true)
push(str[i]);
else if (str[i] == stk[top])
int discard = pop();
else
push(str[i]);
Here, we're iterating over the elements of str, so we can use for (char c: str), which is clearer and less error-prone than using indexes.
The first and last branch are the same, so we can change the condition to bring them together:
void Stack::removeAdjacentDuplicate(const std::string& str)
for (auto c: str)
if (isStackEmpty()
Think like standard algorithms
We have standard algorithms - one similar to our needs is std::unique(). This makes a single pass over its input, and returns an iterator to the new end position.
If we make a function with a similar interface, we can use the 'erase/remove' idiom to replace characters in a string:
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
How do we implement repeatedly_remove_duplicates()? I would assume a single pass called remove_duplicates(), and call it until the returned end doesn't change:
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
(I've made this a template, so it can work with any container. The also allows us to make repeatedly_remove_duplicates() a template to work with any string type, including std::wstring, for instance).
Now, we need an implementation of remove_duplicates. We can do this in-place:
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
auto dest = begin;
if (begin == end) return dest;
auto prev = begin;
bool is_duplicate = false;
while (++begin != end)
if (*begin == *prev)
is_duplicate = true;
else
if (!is_duplicate)
*dest++ = *prev;
is_duplicate = false;
prev = begin;
if (!is_duplicate)
*dest++ = *prev;
return dest;
There are other ways to do this; we might use std::adjacent_find(), for example:
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
while (begin != end);
return dest;
Putting it all together
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
#ifdef REMOVE_PAIR_ONLY
begin = pair;
if (pair != end)
begin += 2;
#else
begin = std::adjacent_find(pair, end, not_equal_to());
if (begin != end)
++begin;
#endif
while (begin != end);
return dest;
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
#include <iostream>
int main(int argc, char **argv)
for (auto i = 1; i < argc; ++i)
std::cout << argv[i] << " â "
<< repeatedly_remove_duplicates(argv[i])
<< std::endl;
Avoid arbitrary limits
The definition of max (and especially as a #define rather than as a C++ constant) is worrying. Especially as the checking simply prints a diagnostic and then ignores the action that was requested.
Simple refactorings
if (test) return true; else return false; is the same as return test;. So we can write
bool Stack::isStackEmpty()
return top == -1;
Similarly, testing ==true is redundant:
if (isStackEmpty())
A more involved refactoring
void Stack::removeAdjacentDuplicate(std::string str)
int len = str.length();
for (int i = 0; i < len; i++)
if (isStackEmpty() == true)
push(str[i]);
else if (str[i] == stk[top])
int discard = pop();
else
push(str[i]);
Here, we're iterating over the elements of str, so we can use for (char c: str), which is clearer and less error-prone than using indexes.
The first and last branch are the same, so we can change the condition to bring them together:
void Stack::removeAdjacentDuplicate(const std::string& str)
for (auto c: str)
if (isStackEmpty()
Think like standard algorithms
We have standard algorithms - one similar to our needs is std::unique(). This makes a single pass over its input, and returns an iterator to the new end position.
If we make a function with a similar interface, we can use the 'erase/remove' idiom to replace characters in a string:
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
How do we implement repeatedly_remove_duplicates()? I would assume a single pass called remove_duplicates(), and call it until the returned end doesn't change:
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
(I've made this a template, so it can work with any container. The also allows us to make repeatedly_remove_duplicates() a template to work with any string type, including std::wstring, for instance).
Now, we need an implementation of remove_duplicates. We can do this in-place:
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
auto dest = begin;
if (begin == end) return dest;
auto prev = begin;
bool is_duplicate = false;
while (++begin != end)
if (*begin == *prev)
is_duplicate = true;
else
if (!is_duplicate)
*dest++ = *prev;
is_duplicate = false;
prev = begin;
if (!is_duplicate)
*dest++ = *prev;
return dest;
There are other ways to do this; we might use std::adjacent_find(), for example:
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
while (begin != end);
return dest;
Putting it all together
#include <algorithm>
#include <functional>
template <typename Iter>
Iter remove_duplicates(Iter begin, Iter end)
using namespace std::placeholders;
using not_equal_to = std::not_equal_to<typename Iter::value_type>;
auto dest = begin;
do
Iter pair = std::adjacent_find(begin, end);
if (dest != begin)
std::copy(begin, pair, dest);
dest += std::distance(begin, pair);
else
dest = pair;
#ifdef REMOVE_PAIR_ONLY
begin = pair;
if (pair != end)
begin += 2;
#else
begin = std::adjacent_find(pair, end, not_equal_to());
if (begin != end)
++begin;
#endif
while (begin != end);
return dest;
template <typename Iter>
Iter repeatedly_remove_duplicates(Iter begin, Iter end)
Iter new_end;
while ((new_end = remove_duplicates(begin, end)) != end)
end = new_end;
return end;
#include <string>
std::string repeatedly_remove_duplicates(std::string s)
s.erase(repeatedly_remove_duplicates(s.begin(), s.end()), s.end());
return s;
#include <iostream>
int main(int argc, char **argv)
for (auto i = 1; i < argc; ++i)
std::cout << argv[i] << " â "
<< repeatedly_remove_duplicates(argv[i])
<< std::endl;
edited Feb 14 at 17:49
answered Feb 14 at 17:25
Toby Speight
17.7k13490
17.7k13490
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f187212%2fremove-all-adjacent-duplicates-in-a-string-using-a-stack%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
a Stack is FILO, so maybe try and reverse the order of: void Stack::removeAdjacentDuplicate(std::string str) and see if this helps.
â xyz
Feb 11 at 14:17
How do you want to improve it?
â Juho
Feb 11 at 16:28
@Juho using STL or better logic.
â coder
Feb 11 at 17:40
What do you want to happen with odd numbers of similar characters, such as
steeel? Your code appears to only remove adjacent pairs, but the example inputs don't give a clear requirement.â Toby Speight
Feb 14 at 17:38
Better real-life examples:
gazetteer,addressees,keennessâ Toby Speight
Feb 14 at 18:27