语言
Java
150. 逆波兰表达式求值
题目
给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
思路
我们采用栈这个数据结构来解决这个问题,我们先遍历数组,将他的元素放到栈中,如果碰到‘+’就相加’-‘就相减’*‘就相乘’/‘就相除,最后一个栈中的数就是我们要返回的值。
具体细节看代码
代码
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList();
for (String s : tokens) {
if ("+".equals(s)) {
stack.push(stack.pop() + stack.pop());
} else if ("-".equals(s)) {
stack.push(-stack.pop() + stack.pop());
} else if ("*".equals(s)) {
stack.push(stack.pop() * stack.pop());
} else if ("/".equals(s)) {
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
} else {
stack.push(Integer.valueOf(s));
}
}
return stack.pop();
}
}
易错点
注意栈是先进后出的,比较’-‘号的时候要第一个是被减的
还有’/‘号的时候也是。
时间复杂度
时间复杂度: O(n)
空间复杂度: O(n)
239. 滑动窗口最大值
题目
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
思路
先创建一个双端队列,定义一个结果数组,先循环遍历源数组,判断如果是空或者不符合范围要弹出,判断如果没有末尾的数大也要弹出,再加入新的元素到队列中,每K个将最大的数添加到结果数组中。具体细节看代码
代码
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
ArrayDeque<Integer> deque = new ArrayDeque<>();//定义双端队列
int n = nums.length;//数组长度
int[] res = new int[n - k + 1];//定义结果数组大小
int idx = 0;//用来存放结果的索引
for (int i = 0; i < n; i++) {//遍历数组
while (!deque.isEmpty() && deque.peek() < i - k + 1) {//不符合范围的都弹出
deque.poll();
}
while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {//比末尾小的也弹出
deque.pollLast();
}
deque.offer(i);//加入遍历的元素
if (i >= k - 1) {//获得最大值
res[idx++] = nums[deque.peek()];
}
}
return res;
}
}
易错点
1.忘记判断不在数组范围的情况了
2.容易忘记不大于队尾的元素也要弹出。
思路是最重要的
时间复杂度
时间复杂度: O(n)
空间复杂度: O(k)
347.前 K 个高频元素
题目
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
思路
先用Map存元素和元素出现的次数,然后用队列和小顶堆的数据结构进行解决。具体过程是
循环遍历数组存在Map中,创建优先队列,再遍历map。判断队列中的元素是否小于k,小于的话直接把map中的元素添加到队列中,如果没有小于,进行对比,如果新元素大,弹出队头,加入新元素。
最后把一整个小顶堆上的元素全弹出,先弹出的是最少的,后弹出的是大的,从大到小加入到结果数组中,返回结果数组。具体细节看代码。
代码
class Solution {
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();//map用来存出现的元素和出现次数.
for (int num : nums) {
map.put(num, map.getOrDefault(num, 0) + 1);//key元素value次数。
}
//创建一个优先级队列,并且保证是升序排列的
PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2) -> pair1[1] - pair2[1]);
for (Map.Entry<Integer,Integer> entry : map.entrySet()) {//遍历map,采用小顶堆的数据结构
if (pq.size() < k ) {//队列元素小于k直接添加
pq.add(new int[]{entry.getKey(), entry.getValue()});
} else {
if (entry.getValue() > pq.peek()[1]) {//如果VALUE值大于队列中的
pq.poll();//弹出队头,即小顶堆的根节点,就是最少的弹出了,留下的是出现次数多的了
pq.add(new int[]{entry.getKey(), entry.getValue()});//加入出现次数多的
}
}
}
int[] res = new int[k];//定义一个结果数组
for (int i = k - 1; i >= 0; i--) {//依次弹出小顶堆
res[i] = pq.poll()[0];//先弹出的是根也就是出现次数少的,后面是弹出的多的
}
return res;//例题中也展示的是出现元素最多的放前面
}
}
易错点
弹出队首和队尾的时候要小心一些。
基本队列方法不要写错。
时间复杂度
- 时间复杂度: O(nlogk)
- 空间复杂度: O(n)
总结
栈和队列今天就算完结了,今天我体会到了写注释的重要性,以后的代码我会多多写注释,来保证思路的完整性。
继续加油!我亦无他唯手熟而。