春招冲刺百题计划|栈

Java基础复习

  1. Java数组的声明与初始化
  2. Java ArrayList
  3. Java HashMap
  4. Java String 类
  5. Java LinkedList
  6. Java Deque继承LinkedList
  7. Java Set

第一题:有效的括号

很简单的题,从大一做到现在,就是复习一下语法。
在这里插入图片描述

class Solution {
    public boolean isValid(String s) {
        //先明确一下Java的stack用什么:Deque<Character> stack = new LinkedList<Character>();先进后出为栈
        //自己可以规定一下用法:addLast, removeLast和getLast
        int n = s.length();
        if(n%2!=0){
            return false;
        }
        Deque<Character> stack = new LinkedList<Character>();
        for(int i=0; i<n; i++){
            char cur = s.charAt(i);
            if(cur=='('||cur=='{'||cur=='['){
                stack.addLast(cur);
                continue;
            }
            if(stack.size()!=0){
                char top = stack.getLast();
                if(top=='(' && cur==')'){
                    stack.removeLast();
                    continue;
                    
                }
                if(top=='{'&&cur=='}'){
                    stack.removeLast();
                    continue;
                }
                if(top=='['&&cur==']'){
                    stack.removeLast();
                    continue;
                }
                
            }
            return false;   
        }
        if(stack.size()==0){
            return true;
        }else{
            return false;
        }
    }
}

第二题:二叉树的中序遍历

中序遍历顺序:左根右。
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    //怎么改进成用栈呢?这里学习一位大佬的颜色标记法。作者:henry
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        Deque<Object> stack = new LinkedList<>();
        if(root == null){
            return res;
        }
        stack.push("WHITE");
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode node = (TreeNode)stack.pop();
            String color = (String)stack.pop();
            if (node == null) continue;
            if(color.equals("WHITE")){
                stack.push("WHITE");
                stack.push(node.right);
                stack.push("GRAY");
                stack.push(node);
                stack.push("WHITE");
                stack.push(node.left);
            }else{
                res.add(node.val);
            }
        }
        return res;
        
    }
    //非常简单的回溯法
    // List<Integer> res = new ArrayList<>();
    // private void traceBack(TreeNode cur){
    //     if(cur.left != null){
    //        traceBack(cur.left);
    //     }
    //     res.add(cur.val);
    //     if(cur.right != null){
    //         traceBack(cur.right);
    //     }
    // }
    // public List<Integer> inorderTraversal(TreeNode root) {
    //     if(root != null){
    //         traceBack(root);
    //     }
    //     return res;
    // }
}

第三题:移掉k个数字,要求返回最小

在这里插入图片描述
维持一个单调栈,单调栈最麻烦的是维持个数。在大佬的题解里面就直接舍弃这个。最后再处理。很有趣。
强推这个大佬的题解!一招吃遍力扣四道题,妈妈再也不用担心我被套路啦~

class Solution {
    public String removeKdigits(String num, int k) {
        //特殊情况:k>=num.length()
        int n = num.length();
        int remain = n-k;
        if(remain<=0){
            return "0";
        }
        //定义单调栈
        Deque<Character> stack = new LinkedList<Character>();
        //遍历整个num,在其中维护一个长度为无限制的单调栈
        for(int i=0; i<n; i++){
            char ch = num.charAt(i);
            while(!stack.isEmpty()&&k>0&&stack.peekLast()>ch){
                stack.pollLast();
                k--;
            }
            stack.offerLast(ch);
        }
        //只保留栈底的remain个元素
        for (int i = 0; i < k; ++i) {
            stack.pollLast();
        }
        //处理前导0
        StringBuilder ret = new StringBuilder();
        boolean leadingZero = true;
        while (!stack.isEmpty()) {
            char digit = stack.pollFirst();
            if (leadingZero && digit == '0') {
                continue;
            }
            leadingZero = false;
            ret.append(digit);
        }
        return ret.length() == 0 ? "0" : ret.toString();

    }
    // int mul[];
    // int n;
    // int res=Integer.MAX_VALUE;
    // int len;
    // List<Integer> path = new ArrayList<>();
    // private void traceBack(String num, int idx){
    //     if(idx>n){
    //         return;
    //     }
    //    // System.out.println("path= "+path);
    //     if(path.size()==len){
    //         int tmp=0;   
    //         for(int i=0; i<len; i++){
    //             tmp += mul[i] * path.get(i);
    //         }
    //         res = Math.min(tmp, res);
    //         // System.out.println(res + " "+ tmp);
    //         return;
    //     }
    //     for(int i=idx; i<n; i++){
    //         path.add(num.charAt(i)-'0');
    //         traceBack(num, i+1);
    //         path.remove(path.size()-1);
    //     }
        
    // }
    // public String removeKdigits(String num, int k) {
    //     //特殊情况:k>=num.length()
    //     n = num.length();
    //     if(k >= n){
    //         return "0";
    //     }
    //     len = n-k;
    //     mul = new int[n-k];
    //     for(int i=0; i<n-k; i++){
    //         mul[i] = (int) Math.pow((int)10, n-k-i-1);
    //         //System.out.println(mul[i]);
    //     }
    //     //肯定是把k全部用完最好。那就不删除,选择组合?变成组合问题。又想递归回溯了。
    //     //如果是回溯的话,我要画递归树,解空间(i之后的所有)深度(n-k)(不出所料,超时了。)
    //     traceBack(num, 0);
    //     return res+"";
    //     //其实我心里有一个想法,固定栈,里面保证是当前遍历的最小的四个。好像在哪里做过。我需要清醒的脑子过一遍,明天早上来。
    //     //起床了,还是想不到;看了题解:贪心+单调栈


    // }
}

第四题:去除重复字母,要求返回字典序最小

与上一题基本一致!
在这里插入图片描述

class Solution {
    public String removeDuplicateLetters(String s) {
        //看过题解过后写的,与402的核心思路是相同的。
        //前期工作,得到一个map (字母:出现的次数)
        Map<Character, Integer> container = new HashMap<>();
        for(int i=0; i<s.length(); i++){
            if(!container.containsKey(s.charAt(i))){
                container.put(s.charAt(i), 1);
            }else{
                container.put(s.charAt(i), container.get(s.charAt(i))+1);
            }
        }
        //现在出现一个问题,就是前面保留了某个字母之后,后面怎么知道呢?题解里面由加了一个set:当已经保留了,之后的就不在讨论,且数目-1
        Set<Character> seen = new HashSet<>();
        int k = container.size();
        Deque<Character> stack = new LinkedList<>();
        for(int i=0; i<s.length(); i++){
            if(!seen.contains(s.charAt(i))){
                while(!stack.isEmpty()&&container.get(stack.getLast())>1&&stack.getLast()>=s.charAt(i)){
                    container.put(stack.getLast(), container.get(stack.getLast())-1);
                    seen.remove(stack.getLast());
                    stack.removeLast();
                } 
                stack.addLast(s.charAt(i));
                seen.add(s.charAt(i));
                System.out.print(container + "  ");
                System.out.println(stack);
            }else{
                container.put(s.charAt(i), container.get(s.charAt(i))-1);
            }
        }
        //只取满足条件的前k个。
        String res="";
        while(!stack.isEmpty()&&k>0){
            res += stack.getFirst()+"";
            stack.removeFirst();
            k--;
        }
        return res;

    }
}

第五题:拼接最大数,与前面两题相比,多了一个合并排序。

在这里插入图片描述

class Solution {

    private int[] maxNumberInOne(int[] nums, int k){
        int res[] = new int[k];
        int remain = nums.length - k;
        Deque<Integer> stack = new LinkedList<>();
        for(int i=0; i<nums.length; i++){
            while(!stack.isEmpty()&&stack.getLast()<nums[i]&&remain>0){
                stack.removeLast();
                remain--;
            }
            stack.addLast(nums[i]);
            
        }
        
        for(int i=0; i<k&&!stack.isEmpty(); i++){
            res[i] = stack.getFirst();
            stack.removeFirst();
        }
        return res;
    }
    //不是简单的归并:查看官方题解,写了一个compare函数比如:
    public int compare(int[] subsequence1, int index1, int[] subsequence2, int index2) {
        int x = subsequence1.length, y = subsequence2.length;
        //按每一位比较
        while (index1 < x && index2 < y) {
            int difference = subsequence1[index1] - subsequence2[index2];
            if (difference != 0) {
                return difference;
            }
            index1++;
            index2++;
        }
        //比较剩余长度 谁的剩余长度大,谁就大
        return (x - index1) - (y - index2);
    }
    private int[] merge(int[] nums1, int[] nums2){
        int n1 = nums1.length;
        int n2 = nums2.length;
        int res[] = new int[n1+n2];
        Deque<Integer> stack = new LinkedList<>();
        Arrays.fill(res, 0);
        int i=0, j=0, k=0;
        for(; k<n1+n2; k++){
            if(compare(nums1, i, nums2, j)>0){
                stack.addLast(nums1[i]);
                i++;
            }else{
                stack.addLast(nums2[j]);
                j++;
            }
            res[k] = stack.getFirst();
            stack.removeFirst();
        }
        return res;
    }
    public int[] maxNumber(int[] nums1, int[] nums2, int k) {
        int res[] = new int[k];
        Arrays.fill(res, 0);
        //遍历k1和k2的多种可能(考虑挺多的):1.对于一个数组,最少选多少,最多选多少
        int n1 = nums1.length;
        int n2 = nums2.length;
        int maxk=Math.min(k, n1);
        int mink;
        if(n2-k>=0){
            mink = 0;
        }else{
            mink = k-n2; 
        }
        for(int k1=mink; k1<=maxk; k1++){
            // System.out.println("min:" + k1 + ", max:" + (k-k1));
            int res1[] = maxNumberInOne(nums1, k1);
            int res2[] = maxNumberInOne(nums2, k-k1); 
            // System.out.println("1: "+ Arrays.toString(res1) + "; 2: "+ Arrays.toString(res2));
            int tmp[] = merge(res1, res2);
            // System.out.println( Arrays.toString(res));
            if(compare(res, 0, tmp, 0)<0){
                res = tmp;
            }

        }
        return res;
    }
}

根据前两题的大佬的总结,核心就是得到一个单调栈。得到k种可能,每种可能做一个归并,比较。

这个合并排序要重新定义compare函数,因为单纯的选择当前的值做比较,当出现相同数字时,需要根据后续的数字来判断选择哪个数组里的。compare部分参考以下截图理解。
在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值