【LeetCode算法学习笔记】数组去重题(难)

labuladong算法公众号学习笔记
LeetCode316 去除重复字母

题目思考

有三点要求:

  • 要去重
  • 不能打乱s中字符出现的相对顺序
  • 字典序最小(比如“abc”的字典序就比“bac”的字典序小)

思路

先用栈实现前两个要求

String removeDuplicateLetters(String s){
    //存放去重结果
    Stack<Character> stk =  new Stack<>();
    //布尔数组初始值为false,记录栈中是否存在某个字符
    //输入字符均为ASCII字符
    boolean[] inStack = new boolean[256]; 
    for(char c : s.toCharArray()){
        //如果字符c存在栈中,直接跳过
        if(inStack[c]) continue;
        //如果不存在,则插入栈顶并标记为存在
        stk.push(c);
        inStack[c] = true;
    }   
    StringBuilder sb = new StringBuilder();
    while(!stk.empty()){
        sb.append(stk.pop);
    }
    //插入的元素顺序相反需要reverse一下
    return sb.reverse().toString();
}

要求三:

如果当前字符‘a’比之前的字符字典序小,就有可能需要把前面的字符pop出栈,让‘a’拍在前面。而且分一下情况

  • 如果 stk.peek( ) > c 这个字符以后还会出现,就可以pop出去。
  • 如果 stk.peek( ) > c 这个字符之后不再出现,就不能简单pop出去。
  • 关键在于让算法知道字符’a’之后有几个’b’和’c’
String removeDuplicateLetters(String s){
    //存放去重结果
    Stack<Character> stk =  new Stack<>();
    //维护一个计数器记录字符串中字符的数量
    //因为输入为ASCII字符,大小256够用
    int[] count = new int[256];
    for(int i = 0;i < s.length; i++){
        count[s.charAt(i)++];
    }
    //布尔数组初始值为false,记录栈中是否存在某个字符
    //输入字符均为ASCII字符
    boolean[] inStack = new boolean[256]; 
    
    for(char c : s.toCharArray()){
        //每遍历过一个字符,都将对应的计数减一
        count[c]--;
        //如果字符c存在栈中,直接跳过
        if(inStack[c]) continue;
        while(!stk.isEmpty() && stk.peek() > c){
            //若之后不存在栈顶元素了,则停止pop
            if(count[stk.peek()] == 0) break;
            //若之后还有,则可以pop
            inStack[stk.pop] = false;
        }
        //如果不存在,则插入栈顶并标记为存在
        stk.push(c);
        inStack[c] = true;
    }   
    StringBuilder sb = new StringBuilder();
    while(!stk.empty()){
        sb.append(stk.pop);
    }
    //插入的元素顺序相反需要reverse一下
    return sb.reverse().toString();
}

利用count计数,来查找时候后面还有和栈顶相同的元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值