【代码随想录】第五章-栈与队列
- [第五章 栈与队列](#第五章 栈与队列)
-
- [1 有效括号](#1 有效括号)
- [2 删除字符串中所有相邻重复项](#2 删除字符串中所有相邻重复项)
- [3 逆波兰表达式求值](#3 逆波兰表达式求值)
- [4 滑动窗口最大值](#4 滑动窗口最大值)
- [5 第K个高频元素](#5 第K个高频元素)
第五章 栈与队列
1 有效括号
20.有效括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:左括号必须用相同类型的右括号闭合;左括号必须以正确的顺序闭合;每个右括号都有一个对应的相同类型的左括号。
输入:s = "([])" 输出:true
思路:
如果是左括号,就放进去,如果是右括号,就弹出来一个看匹不匹配,匹配就继续下一个
java
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<>();
for (char c : s.toCharArray()) {
if (c == '(' || c == '{' || c == '[') {
stack.push(c);
} else {
if (stack.isEmpty()) {
return false;
}
char top = stack.pop();
if ((c == ')' && top != '(') ||
(c == '}' && top != '{') ||
(c == ']' && top != '[')) {
return false;
}
}
}
return stack.isEmpty();
}
}
2 删除字符串中所有相邻重复项
1047.删除字符串中所有相邻重复项
给出由小写字母组成的字符串 s,重复项删除操作会选择两个相邻且相同的字母,并删除它们。在 s 上反复执行重复项删除操作,直到无法继续删除。在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
输入:"abbaca" 输出:"ca"
思路:
用栈匹配
java
class Solution {
public String removeDuplicates(String s) {
Deque<Character> S = new ArrayDeque<Character>();
char[] cs = s.toCharArray();
int i = 0;
int len = s.length();
S.push(cs[i++]);
while (i < len) {
if (S.isEmpty()) {
S.push(cs[i++]);
continue;
}
char top = S.peek();
if (top != cs[i]) {
S.push(cs[i++]);
} else {
S.pop();
i++;
}
}
StringBuffer sb=new StringBuffer();
while(!S.isEmpty()){
sb.append(S.pop());
}
return sb.reverse().toString();
}
}
3 逆波兰表达式求值
150.逆波兰表达式求值
根据逆波兰表示法,求表达式的值。有效的运算符包括+,-,*,/。每个运算对象可以是整数,也可以是另一个逆波兰表达式。说明:整数除法只保留整数部分。给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为0的情况。
输入:s = "abbaca" 输出:"ca"
思路:
java
class Solution {
public int evalRPN(String[] tokens) {
Deque<String> S = new ArrayDeque<String>();
int len=tokens.length;
int i=0;
S.push(tokens[i++]);
while(i<len){
if(tokens[i].matches("-?\\d+")){
S.push(tokens[i++]);
}
else{
int b=Integer.parseInt(S.pop());
int a=Integer.parseInt(S.pop());
if(tokens[i].equals("+")){
S.push(String.valueOf(a+b));
}
else if(tokens[i].equals("-")){
S.push(String.valueOf(a-b));
}
else if(tokens[i].equals("/")){
S.push(String.valueOf(a/b));
}
else if(tokens[i].equals("*")){
S.push(String.valueOf(a*b));
}
i++;
}
}
return Integer.parseInt(S.peek());
}
}
4 滑动窗口最大值
239.滑动窗口最大值
给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7]
思路:
用一个单调队列来存储对应的下标,每当窗口滑动的时候,直接取队列的头部指针对应的值放入结果集即可。
队列头结点需要在[i - k + 1, i]范围内,不符合则要弹出。
既然是单调,就要保证每次放进去的数字要比末尾的都大,否则队尾也弹出
因为单调,当i增长到符合第一个k范围的时候,每滑动一步都将队列头节点放入结果就行了
java
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int len=nums.length;
int []res=new int[len-k+1];
Deque<Integer> Q=new ArrayDeque<>();
int ri=0;
int ni=0;
for(int i=0;i<len;i++){
while(!Q.isEmpty()&&Q.peek()<i-k+1){
Q.poll();
}
while(!Q.isEmpty()&&nums[Q.peekLast()]<nums[i]){
Q.pollLast();
}
Q.add(i);
if(i>=k-1){
res[ni++]=nums[Q.peek()];
}
}
return res;
}
}
5 第K个高频元素
347.前K个高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。。
输入:nums = [1,1,1,2,2,3], k = 2 输出:[1,2]
思路:
Hashmap排序
java
class Solution {
public int[] topKFrequent(int[] nums, int k) {
int []res=new int[k];
Deque<Integer> Q=new ArrayDeque<>();
Map<Integer,Integer>map=new HashMap<>();
int len=nums.length;
for(int i=0;i<len;i++){
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
List<Map.Entry<Integer, Integer>> entryList =
new ArrayList<>(map.entrySet());
entryList.sort((entry1, entry2) ->
entry2.getValue().compareTo(entry1.getValue()));
for (int i = 0; i < k; i++) {
res[i]=entryList.get(i).getKey();
}
return res;
}
}
Tip:Integer数组排序
java
int[] arr = {5, 3, 8, 1, 2};
Integer[] arr2 = {5, 3, 8, 1, 2};
for(int i=0;i<arr.length;i++){
arr2[i] = arr[i];
}
- 如果不用比较器的话,只有对象数组arr2可以用自定义排序,arr只能先升序后手动翻转
- 对于对象数组可以用lamada表达式
java
Arrays.sort(arr, (a, b) -> b - a)
Arrays.sort(arr2, (a,b)->b.compareTo(a));
Tip:Hashmap排序/Arraylist排序
先转为List:List<Map.Entry<...,...>>list= new ArrayList<>(map.entrySet());
用谁排序用谁,用value排value,用key排key。List.sort((e1,e2)->e1.getValue().compareTo(e2.getValue()));