栈与队列part02 + 集合知识总结

Java集合相关基础知识总结

在这里插入图片描述

1.逆波兰表达式求值

题目链接
逆波兰表达式=二叉树的后序遍历
逆波兰表达式主要有以下两个优点:
(1) 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
(2) 适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中
易错点:
(1)Java中判断字符串相等需要用equals方法,所以可以直接用token.equals(“+”)来判断。也可以像我一样利用char ch=token.charAt(0)将字符串转换成char再判断,问题在于我一开始忽略了当token为负数时,token.charAt(0)也是’-‘,所以后来又加上了token.length()==1的条件。
(2)题目中明确要求“ 两个整数之间的除法总是 向零截断 ",Java和c++的整数除法都是向0截断,即int result2 = -7 / 3; 结果是-2而非向下截断的-3。但一些语言如python是向下截断的,所以需要做特殊处理。
(3)当ch等于’-‘或者’/'时,要想清楚谁是被除数和除数(num1和num2谁在前面)。

class Solution {
    public int evalRPN(String[] tokens) {
        LinkedList<Integer> stack=new LinkedList<>();
        for(String token:tokens){
            char ch=token.charAt(0);
            //符号
            if(token.length()==1 && (ch=='+' || ch=='-' || ch=='*' || ch=='/')){
                int num1=stack.pop();
                int num2=stack.pop();
                switch(ch){
                    case '+':
                        stack.push(num1+num2);
                        break;
                    case '-':
                        stack.push(num2-num1);
                        break;
                    case '*':
                        stack.push(num1*num2);
                        break;
                    case '/':
                        stack.push(num2/num1);
                        break;
                }
            }
            //数字
            else{
                stack.push(Integer.valueOf(token));
            }
        }
        return stack.pop();
    }
}

2.滑动窗口最大值

题目链接
使用单调队列的经典题目,自认为有点像最小栈,想到用一个单独的数据结构用于存储。此队列不能只存储最大值,还需要存储有可能成为最大值的元素,因为随着窗口的移动,元素会弹出。而又不能像普通单调队列一样,将窗口内元素从大到小排列,这样弹出时每次需要寻找该元素,使得问题更加复杂。那么如何存储维护有可能成为窗口里最大值的元素,同时保证队列里的元素数值是由大到小的呢?
✅最关键的一个原则就是:队列中无需保留位于当前元素左侧并且小于当前元素的数值(这些左侧的元素比当前元素弹出早,在当前元素弹出之前,最大值都会是当前元素,这些左侧元素不可能成为最大值)
在这里插入图片描述

由此推理出几个步骤:
1.处理右指针
向右扩展窗口,添加新元素时,从末端遍历,将队列中所有小于right元素都清除,然后加入right。
(如果新元素大于队列的头部元素,我们可以选择清空整个队列并只保留这个新元素。这个逻辑可以单独处理,其实从末端遍历效果也一样。)
2. 处理左指针
当窗口向右滑动,需要弹出左元素时。只需将left和队列最大值(head)进行对比,如果left小于最大值,说明最大值在left右侧,left不可能在队列中,无需进行任何操作。

class Solution {
    LinkedList<Integer> list=new LinkedList<>();

    public int[] maxSlidingWindow(int[] nums, int k) {
        int[] result=new int[nums.length-k+1];
        int i=0;
        int left=0,right=0;
        //先添加前k个元素
        while(right<k){
            push(nums[right]);
            right++;
        }
        result[i++]=list.getFirst();
        while(right<nums.length){
            //处理左指针
            if(nums[left]==list.getFirst()){
                list.removeFirst();
            }
            left++;
            push(nums[right]);
            result[i++]=list.getFirst();
            right++;
        }
        return result;
        
    }

    //处理右指针
    public void push(int num){
        if(list.isEmpty()){
            list.addFirst(num);
        }
        else{
            while(!list.isEmpty() && num>list.getLast()){
                list.removeLast();
            }
            list.addLast(num);
        }
    }
}

易错点:
(1)当存在循环和自增时,一定要想清楚退出时变量的值(本题中就是由于先添加前k个元素后,退出循环时变量right实际上已经等于k,而不是我们可能直觉上认为的k-1)。先变量自增再进行逻辑处理和先进行逻辑处理再自增,对于循环条件会不同。
(2)Java函数传参时使用的是值传递的方式
基本数据类型:值传递(pass by value)是指在调用方法时将实参复制一份传递到方法中,这样当方法对形参进行修改时不会影响到实参。
引用类型:引用传递(pass by reference)是指在调用方法时将实参的地址直接传递到方法中,那么在方法中对形参所进行的修改,将影响到实参。
引用类型作为参数被传递时也是值传递,只不过“值”为对应的引用。
在这里插入图片描述参考:CSDN:五分钟学Java:Java到底是值传递还是引用传递?
对于示例1:

class Solution {
    LinkedList<Integer> list = new LinkedList<>();

    public static void main(String[] args) {
        Solution solution = new Solution();
        solution.push(1);
    }

    public void push(int num) {
        this.list.push(num);
    }
}

示例2:

class Solution {
    public static void main(String[] args) {
        Solution solution = new Solution();
        LinkedList<Integer> list = new LinkedList<>();
        solution.push(list, 1);
    }

    public LinkedList<Integer> push(LinkedList<Integer> list, int num) {
        list.push(num);
        return list;
    }
}

在LeetCode上,通常推荐使用示例2的方法,因为它提供了更好的灵活性和可测试性。但确实示例2的空间消耗更高,如果push方法被频繁调用,每次调用都会创建一个新的LinkedList实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值