公司新来了一位38岁的领导,刚一上任就把这个网友的工资从1w调到了1.5w。。
最让人震惊的是,领导还这么说:“你是唯一的35岁老员工,咱们老人可要互相帮忙。”我当时看到这一段,直接懵了!🤯
算法题:去除重复字母
今天我们来聊聊一个常见的算法问题:去除重复字母。
假设给定一个字符串,你需要去除其中所有重复的字母,并且确保每个字母在最终结果中只出现一次。关键是,结果字符串的顺序要和原字符串中的字母顺序一致。
看似简单,但要高效解决它,就得考虑一下时间和空间的复杂度问题。尤其是在实际生产环境中,我们常常需要处理大数据量的情况,代码的效率直接影响程序的性能。
首先,我们可以考虑直接的解决方案:用一个 Set 存储已经遍历过的字母。每次遇到重复的字母,就跳过它。这个方法的思路是直观的,但是效率不是最优的。每次要查找是否已经存在过,时间复杂度为 O(n),而且还需要额外的空间来存储 Set。
不过,稍微改进一下,我们就可以用栈来做。栈在这个问题上就像是一个有序的容器,能保证我们按照出现顺序来处理每个字母,并且避免重复。
思路:
使用一个栈来存储结果字符串的字符。 每遇到一个新的字符时,如果栈顶的字符比当前字符大,而且栈顶字符后面还会出现该字符(我们可以通过一个频率数组来判断),那么就将栈顶字符弹出,继续尝试放入当前字符。 通过这种方式,我们保证了结果中没有重复字母,并且保持了字母的顺序。
代码实现:
import java.util.*;public class RemoveDuplicateLetters {
public String removeDuplicateLetters(String s) {
// 记录每个字符的出现次数
int[] count = new int[26];
// 记录字符是否已经在结果中出现过
boolean[] inResult = new boolean[26];
Stack<Character> stack = new Stack<>();
// 统计字符串中每个字符的出现次数
for (char c : s.toCharArray()) {
count[c - 'a']++;
}
for (char c : s.toCharArray()) {
count[c - 'a']--; // 当前字符已经处理,出现次数减一
// 如果该字符已经出现在结果中,跳过
if (inResult[c - 'a']) {
continue;
}
// 保证栈内的字符按字典序排列,栈顶字符大于当前字符,并且栈顶字符后面还有出现,才能弹出栈顶字符
while (!stack.isEmpty() && stack.peek() > c && count[stack.peek() - 'a'] > 0) {
inResult[stack.pop() - 'a'] = false;
}
stack.push(c);
inResult[c - 'a'] = true;
}
// 组合最终结果
StringBuilder result = new StringBuilder();
for (char c : stack) {
result.append(c);
}
return result.toString();
}
public static void main(String[] args) {
RemoveDuplicateLetters solution = new RemoveDuplicateLetters();
String input = "bcabc";
System.out.println("Result: " + solution.removeDuplicateLetters(input)); // 输出 "abc"
}
}
讲解:
首先,我们用一个数组 count 来统计每个字母在原字符串中出现的次数。然后,我们遍历字符串的每一个字符。如果栈顶字符比当前字符大,并且栈顶字符后面还会出现(通过 count 数组来判断),我们就把栈顶的字符弹出栈。
这样做的好处是,我们确保了栈中的字符是有序的,并且没有重复的字母。而且每个字母只会被放入栈一次,时间复杂度是 O(n),空间复杂度是 O(n),也就是非常高效。
代码中的小细节:
栈的使用:栈在这里扮演着一个非常重要的角色,保证了我们能够按顺序逐一考虑字符的加入,同时也能够弹出那些不满足条件的字符。 inResult数组:这个数组的作用是保证每个字符在最终结果中只出现一次。如果栈中已经有了某个字符,我们就跳过当前字符,避免重复。count数组:这个数组记录每个字符剩余的次数,确保我们在决定是否弹出栈顶字符时不会错过后面可能出现的相同字符。
总的来说,去除重复字母的这个问题其实没有我们想象中那么复杂,只要把栈运用得当,考虑清楚每个字符的出现顺序和频率,问题就迎刃而解了。希望这篇代码分析能帮大家更好地理解这个算法问题,下一次面试碰到类似的问题,记得可以利用栈来高效解决!
-END-
以上,就是今天的分享了,看完文章记得右下角给何老师点赞,也欢迎在评论区写下你的留言。