一、逆波兰表达式求值
这道题在数据结构中有学过原理,所以在解题的时候还是比较顺利的。有几处写代码时踩的坑需要注意一下:
- 字符串的比较。字符串在比较的使用要用到**.equal()方法**,而不是直接进行“==”比较。
//字符串不能这样比较。
//if(tokens[i] == "+"){
if(tokens[i].equals("+")){
- 加减法的处理。在进行加减法的时候,一定要注意两个操作数的顺序,是先入栈的元素去对后入栈的元素进行操作(其实加法、乘法也是一样的,只不过他们顺序调换结果也不会出错)
x = deque.pop();
y = deque.pop();
//减法注意顺序改变
tmp = y - x;
deque.push(tmp);
- 类型转换。对操作数入栈的时候需要将字符串类型转换为整型。
//压栈,将字符串转化为int类型
deque.push(Integer.parseInt(tokens[i]));
以下是完整代码:
public int evalRPN(String[] tokens) {
//创建一个栈
Deque<Integer> deque = new LinkedList<>();
int tmp;
int x,y;
for (int i = 0; i < tokens.length; i++) {
//字符串不能这样比较。
//if(tokens[i] == "+"){
if(tokens[i].equals("+")){
//取出栈顶的两个元素
x = deque.pop();
y = deque.pop();
//进行对应的操作
tmp = x + y;
//将操作好的元素压入栈
deque.push(tmp);
}else if(tokens[i].equals("-")){
x = deque.pop();
y = deque.pop();
//减法注意顺序改变
tmp = y - x;
deque.push(tmp);
}else if(tokens[i].equals("*")){
x = deque.pop();
y = deque.pop();
tmp = x * y;
deque.push(tmp);
}else if(tokens[i].equals("/")){
x = deque.pop();
y = deque.pop();
//除法注意顺序改变
tmp = y / x;
deque.push(tmp);
}else
//压栈,将字符串转化为int类型
deque.push(Integer.parseInt(tokens[i]));
}
return deque.pop();
}
二、239. 滑动窗口最大值
这道题在看到提示需要用到单调队列时,思考了下就是在一个队列中存储有用的最大值和较大的值,但是不清楚如何在滑动窗口的时候也较高的效率将队列中不包含的值删去。
在看了视频讲解后,了解了原理,主要有3个重点:
- 在push时,从队列后端依次比较插入值与队列最后一个值的大小。将比它小的值全部从队列后端弹出(这里使用的时双端队列),然后插入该值。
- 在pop时,如果队头元素与出队的值相同,才会做出队操作。否则不做操作。(因为如果不同的话,说明这个值相当于无效值,早在其他元素push的时候被从队列后端弹出了)
- 前k个值既不能全部插入队列,也不能只选择最大值插入队列。应该在每次循环中只调用push()方法,最后调用一次getValue()方法。
以下是完整代码:
public class 滑动窗口最大值239 {
Deque<Integer> deque = new LinkedList<>();
//标准答案
public int[] maxSlidingWindow(int[] nums, int k) {
int[] res = new int[nums.length -k + 1];
//错误的想法:取前k个最大值放入队列,但这样做会忽略前k个除最大值外其他值的存在
// //先计算出前k个的最大值
// int tmp = nums[0];
// for (int i = 1; i < k; i++) {
// //这里是tmp和nums[i]比较
// if(tmp<nums[i])
// tmp = nums[i];
// }
// //把前k个元素中最大的入队
// deque.push(tmp);
// //把前k个元素最大的放入数组。
// res[0] = tmp;
//前k个值只需要push,不需要pop
for (int i = 0; i < k; i++) {
push(nums[i]);
}
res[0] = getValue();
for (int i = k,j = 1; i < nums.length; i++,j++) {
//出队,这里注意出队是 i-k
pop(nums[i-k]);
//入队
push(nums[i]);
res[j] = getValue();
}
return res;
}
void pop(int val){
//如果当前单调队列的对头是需要弹出的元素,则弹出。否则,不需要进行任何操作(因为小的元素已经在push的时候从队尾弹出了)
if(!deque.isEmpty() && deque.peek()==val)
deque.remove();
}
void push(int val){
//如果队列后端的元素比新插入的元素小,则从队尾弹出小的元素
while(!deque.isEmpty() && deque.peekLast()<val)
deque.removeLast();
deque.offer(val);
}
int getValue(){
return deque.peek();
}
}
三、347.前 K 个高频元素
这道题我自己的思路:需要用到map,遍历一遍数组,将每个值及其出现的次数以<key,value>存储在哈希表中。然后再遍历一遍哈希表,维护一个k大小的数组,并记录数组中的value最小值,每次遍历新的entry都与这个value比较,若大于这个value,则替换。
标准答案中是通过一个小顶堆(或者大顶堆)来实现对value值最大的前k个entry进行存储。我没有接触过Java的语法中关于优先队列的知识,所以代码也是照着题解代码写的。
以下是完整代码:
ublic int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if(map.containsKey(nums[i]))
//改变map中的value值——给map的value重新赋值
map.put(nums[i] , map.get(nums[i])+1);
else
map.put(nums[i] , 1);
}
PriorityQueue<int[]> pq = new PriorityQueue<>((pair1,pair2) -> pair2[1]-pair1[1]);
for(Map.Entry<Integer,Integer> entry:map.entrySet()){
pq.add(new int[]{entry.getKey(),entry.getValue()});
}
int[] ans = new int[k];
for (int i = 0; i < k; i++) {
ans[i] = pq.poll()[0];
}
return ans;
}