返回

字符串去重,用 Java 巧夺先机

见解分享

引言

在编程的世界里,字符串操作是永恒的旋律。从文本处理到数据分析,字符串无处不在。然而,当字符串中出现重复字符时,如何巧妙地将其剔除,却成了程序员们津津乐道的话题。

LC 316:去重难题

LC 316 是 LeetCode 上一道经典的字符串去重题目。题目要求给定一个字符串,将其中的重复字符去除,并返回所有可能的结果中按字符串排序最小的那个。

例如,对于字符串 "abcabcbb",正确的输出应该是 "abc",因为这是所有可能去除重复字符的结果中最小的。

乍一看,这道题似乎很简单,但要找到最优解却并不容易。我们需要在效率和准确性之间取得平衡,同时还要考虑各种可能的输入情况。

贪心算法:循序渐进

解决 LC 316 的一种直观方法是贪心算法。贪心算法是一种分步决策的方法,每一步都基于当前的信息,做出看似局部最优的选择。

具体来说,我们可以从字符串的第一个字符开始,将其放入一个集合中。然后,依次遍历字符串中的其余字符,如果字符不在集合中,则将其放入集合并添加到结果字符串中。如果字符已经在集合中,则将其跳过。

这个算法的优点是简单易懂,而且在大多数情况下效率很高。但是,它有一个缺点,就是无法保证找到最优解。例如,对于字符串 "abcabcbb",贪心算法会得到 "abcbb" 的结果,而不是最优的 "abc"。

栈:后进先出

为了找到最优解,我们可以使用栈这种数据结构。栈遵循后进先出的原则,这意味着最后放入栈中的元素将第一个被取出。

对于 LC 316,我们可以使用一个栈来存储字符串中的字符。当我们遍历字符串时,如果当前字符不在栈中,则将其放入栈中。如果当前字符已经在栈中,则将其从栈中弹出,并继续遍历字符串。

当我们遍历完整个字符串后,栈中剩下的字符就是最优解。这是因为栈中字符的顺序是倒序的,而我们要求输出的字符串按字符串排序最小,因此栈中字符的倒序就是最优解。

Java 实现

下面是使用 Java 实现栈方法的代码:

import java.util.Stack;

public class RemoveDuplicateLetters {

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

        // 创建一个栈来存储字符
        Stack<Character> stack = new Stack<>();

        // 创建一个数组来记录每个字符最后出现的位置
        int[] lastIndex = new int[26];
        for (int i = 0; i < 26; i++) {
            lastIndex[i] = -1;
        }

        // 遍历字符串
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);

            // 如果字符不在栈中
            if (!stack.contains(c)) {
                // 如果栈不为空,并且当前字符比栈顶字符小
                while (!stack.isEmpty() && stack.peek() > c && lastIndex[stack.peek() - 'a'] > i) {
                    stack.pop();
                }

                // 将当前字符放入栈中
                stack.push(c);
                lastIndex[c - 'a'] = i;
            }
        }

        // 从栈中弹出字符,组成结果字符串
        StringBuilder result = new StringBuilder();
        while (!stack.isEmpty()) {
            result.append(stack.pop());
        }

        return result.reverse().toString();
    }
}

复杂度分析

上述算法的时间复杂度为 O(n),其中 n 是字符串的长度。空间复杂度为 O(n),因为我们需要创建一个栈和一个数组来存储字符信息。

总结

通过贪心算法和栈这两种方法,我们可以高效地解决 LC 316 的字符串去重难题。贪心算法虽然简单易懂,但无法保证找到最优解;而栈方法则可以保证找到最优解,但实现起来稍显复杂。

掌握这些算法,不仅可以解决实际问题,更能提升我们的编程思维,在浩瀚的代码世界中乘风破浪。