LeetCode热题100记录-【栈】【堆】

20.有效的括号
思考:用栈存左括号,如果遇到右括号就弹出栈,出栈的左括号和右括号匹配就true否则false
记录:需要二刷

class Solution {
    public boolean isValid(String s) {
        Stack<Character> left = new Stack<>();
        for(char c : s.toCharArray()){
            if(c == '(' || c == '[' || c =='{'){
                left.push(c);
            }else{
                if(left.isEmpty()){
                    return false;
                }else{
                    if(left.pop() != findLeft(c)){
                        return false;
                    }
                }
            }
        }
        return left.isEmpty()? true:false;
    }
    char findLeft(Character right){
        if(right == ')'){
            return '(';
        }else if(right == '}'){
            return '{';
        }else{
            return '[';
        }
    }
}

155.最小栈
思考:用两个栈存储,最大栈就是基础的push、pop、peek操作。最小栈需要判断,每次push只存最小元素,如果当前元素小于最小元素,就存入,如果大于就把最小元素再存一次
记录:需要二刷

class MinStack {
    Stack<Integer> min;
    Stack<Integer> max;
    
    public MinStack() {
        min = new Stack<>();
        max = new Stack<>();
    }
    
    public void push(int val) {
        if(min.isEmpty() || min.peek()>=val){
            min.push(val);
        }else{
            min.push(min.peek());
        }
        max.push(val);
    }
    
    public void pop() {
        max.pop();
        min.pop();
    }
    
    public int top() {
        return max.peek();
    }
    
    public int getMin() {
        return min.peek();
    }
}

394.字符串编码
思考:用两个栈:数字、括号中路径

  • 如果当前字符是数字,就记录数字(先不存进栈,防止是十位、百位这种)
  • 遇到左括号,证明前面数字记录完毕,把数字存入数字栈。把前面的字符res全部存入字符栈。然后初始化数字和字符res,这样保证括号后面的重新入栈
  • 然后括号里面的依次记录,如果是字符直接加入res(已经初始化过了)
  • 遇到右括号,把数字弹出,把字符弹出,在弹出的字符res上依次添加刚刚括号里的记录

记录:需要二刷

class Solution {
    public String decodeString(String s) {
        StringBuilder res = new StringBuilder();
        Stack<Integer> num = new Stack<>();
        Stack<StringBuilder> track = new Stack<>();
        int numTrack = 0;
        for(int i = 0;i < s.length();i++){
            char c = s.charAt(i);
            if(Character.isDigit(c)){
                numTrack = numTrack * 10 + c - '0';
            }else if(c == '['){
                num.push(numTrack);
                track.push(res);
                res = new StringBuilder();
                numTrack = 0;
            }else if(c == ']'){
                int curNum = num.pop();
                StringBuilder curString = track.pop();
                for(int j = 0;j < curNum;j++){
                    curString.append(res);
                }
                res = curString;
            }else{
                res.append(c);
            }
        }
        return res.toString();
    }
}

739.每日温度
思考:用栈存储气温较大值。遍历整个气温数组,注意从后往前,这样可获取当日往后的气温作为先验数据。每次都将栈中气温和当日气温比较,如果栈中气温小于当日,证明气温下降,就pop出去,注意这里用while可以确保栈中每个气温都与当日比较。然后将栈中存留的(代表气温上升的)存入结果集,最后当日的气温push进栈。
注意这里栈中存的是索引,方便对结果集存储
记录:需要二刷

class Solution {
    public int[] dailyTemperatures(int[] temperatures) {
        int[] res = new int[temperatures.length];
        Stack<Integer> s = new Stack<>();
        for(int i = temperatures.length-1;i >= 0;i--){
            while(!s.isEmpty() && temperatures[s.peek()] <= temperatures[i]){
                s.pop();
            }
            res[i] = s.isEmpty() ? 0 : (s.peek()-i);
            s.push(i);
        }
        return res;
    }
}

84.柱状图中最大的矩阵
思考:找到一个柱子 heights[p] 大于或等于当前柱子 heights[i] 时,知道它不可能是我们要找的"左侧第一个小于当前高度的柱子"。可以直接跳到 left[p](即柱子p左侧的第一个小于p的柱子),而不需要一个一个向左检查。这是因为:

  • 如果 heights[p] >= heights[i],那么 p 左边的所有高度大于等于 heights[p] 的柱子也一定大于等于 heights[i]
  • 所以我们可以直接跳到 left[p],这是一个已经计算好的、p 左侧第一个小于 heights[p] 的位置

记录:需要二刷

class Solution {
    public int largestRectangleArea(int[] heights) {
        int[] left = new int[heights.length];
        int[] right = new int[heights.length];
        for(int i = 0;i < heights.length;i++){
            int p = i-1;
            while(p >= 0 && heights[p] >= heights[i]){
                p = left[p];
            }
            left[i] = p;            
        }
        for(int i = heights.length-1;i >= 0;i--){
            int p = i+1;
            while(p < heights.length && heights[p] >= heights[i]){
                p = right[p];
            }
            right[i] = p;
        }
        int res = 0;
        for(int i = 0;i < heights.length;i++){
            int width = right[i] - left[i] - 1;
            int area = heights[i] * width;
            res = Math.max(area,res);
        }
        return res;
    }
}

215.数组中的第K个最大元素
思考:排序好的数组,第k个最大的就是数组个数-k,秒
记录:不需要二刷

class Solution {
    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums);
        return nums[nums.length-k];
    }
}

347.前K个高频元素
思考:用优先级队列存哈希值,按照大小比较,当队列中元素大于k就拉出来,否则就存进去,最后把队列里元素的key拿出来放到结果里
记录:需要二刷

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        HashMap<Integer,Integer> numToCount = new HashMap<>();
        for(int i = 0;i < nums.length;i++){
            numToCount.put(nums[i],numToCount.getOrDefault(nums[i],0)+1);
        }
        PriorityQueue<Map.Entry<Integer,Integer>> pq = new PriorityQueue<>(
            (hm1,hm2)->{
                return hm1.getValue().compareTo(hm2.getValue());
            }
        );
        for(Map.Entry<Integer,Integer> hm : numToCount.entrySet()){
            pq.offer(hm);
            if(pq.size() > k){
                pq.poll();
            }
        }
        int[] res = new int[k];
        for(int i = 0;i < k;i++){
            res[i] = pq.poll().getKey();
        }
        return res;
    }
}

295.数据流的中位数
思考:拿两个优先级队列分别表示小和大,每次添加元素时保持两个队列差不多长,如果给小队列添加元素,就把小的里面最大值弹出给大队列,大队列同理。返回中位数即返回小/大中多的元素或平均值
记录:需要二刷

class MedianFinder {
    PriorityQueue<Integer> min;
    PriorityQueue<Integer> max;
    public MedianFinder() {
        min = new PriorityQueue<>();
        max = new PriorityQueue<>((a,b)->{return b-a;});
    }
    
    public void addNum(int num) {
        if(min.size() >= max.size()){
            min.offer(num);
            max.offer(min.poll());
        }else{
            max.offer(num);
            min.offer(max.poll());
        }
    }
    
    public double findMedian() {
        if(min.size() > max.size()){
            return min.peek();
        }else if(min.size() < max.size()){
            return max.peek();
        }else{
            return (min.peek() + max.peek())/2.0;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值