每日一题:删除字符串中的所有相邻重复项

81 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情

题目链接

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

S上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

  示例:

输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"

提示:

  • 1 <= S.length <= 20000
  • S 仅由小写英文字母组成。

解题思路:栈

我们可以利用栈的前进后出的特点来做本题,具体思路:

  1. 定义一个变量i在字符串的初始位置,将字符串的第一个元素先放进栈中,i++
  2. 如果栈顶元素和字符串中的i号元素相等,我们就弹栈i++
  3. 如果栈顶元素和字符串中的i号元素不相等,将i号元素压栈i++
  4. 重复此过程,直到变量i遍历完了字符串
  5. 将栈中的元素弹出,因为此时字符串是倒序的,所以还需要反转下字符串再返回

代码:(JAVA实现)

public String removeDuplicates(String s) {
        if (s.length() == 0 || s == null) {
            return s;
        }

        Stack<Character> stack = new Stack<>();
        
        for (int i = 0; i < s.length(); i++) {
            if (stack.isEmpty()) {
                stack.push(s.charAt(i++));
                continue;
            }
            
            if (stack.peek() == s.charAt(i)) {
                stack.pop();
                i++;
            }else {
                stack.push(s.charAt(i++));
            }
        }
        
        String res = "";
        while (!res.isEmpty()) {
            res += res.pop();
        }
        
        Stirng reverse = new StringBuffer(res).reverse().toString();
        
        return reverse;
    }

复杂度分析:

  • 时间复杂度:O(n+m),n为字符串长度,m为栈长度
  • 空间复杂度:O(1)

提交结果:

image.png

解题思路:字符串

我们可以直接拿字符串直接作为栈,省去了栈还要转为字符串的操作,思路跟上一个一样

具体代码:(JAVA实现)

public String removeDuplicates(String s) {
        if (s.length() == 0 || s == null) {
            return s;
        }
        
        StringBuffer stringbuffer = new StringBuffer();
        int top = -1;
        for (int i = 0; i < s.length(); i++) {
            char temp = s.charAt(i);
            if (top >= 0 && stringbuffer.charAt(top) == temp) {
               stringbuffer.deleteCharAt(top);
               top--;
            }else {
               stringbuffer.append(temp);
               top++;
            }
        }
        return stringbuffer.toString();
}

复杂度分析:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

提交结果:

image.png

解题思路:双指针

其实本题也可以使用双指针,具体思路为:

  1. 定义双指针slowfast,分别指向字符串的初始位置
  2. fast一直向右移动,每次移动都将指向的值传给slow
  3. slow大于0且与前一个元素相等时,slow--。其他情况一律slow++

代码实现:(JAVA实现)

    public String removeDuplicates(String s) {
        if (s.length() == 0 || s == null) {
            return s;
        }

        char[] res = s.toCharArray();
        int slow = 0;
        int fast = 0;
        while (fast < res.length) {
            res[slow] = res[fast];
            if (slow > 0 && res[slow] == res[slow-1]) {
                slow--;
            }else {
                slow++;
            }

            fast++;
        }

        return new String(res,0,slow);
    }

复杂度分析:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

提交结果:

image.png