20. 有效的括号 - 力扣(LeetCode)
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
此题是栈的经典应用,遇到左括号压栈,遇到右括号则弹出栈并与之匹配,如果不匹配直接返回false
最后判断栈是否为空,栈不为空也返回false
public boolean isValid(String s) {
Stack<Character> stack=new Stack<>();
for(int i=0;i<s.length();i++){
char c=s.charAt(i);
if(c=='(' || c=='[' || c=='{'){
stack.push(c); //左括号压栈
}else{
if(stack.isEmpty()) return false;
char temp=stack.pop(); //右括号则弹指栈
if(c==')' && temp!='(') return false;
if(c==']' && temp!='[') return false;
if(c=='}' && temp!='{') return false; //如果括号不匹配,返回false
}
}
return stack.isEmpty(); //最后看栈是否为空
}
1047. 删除字符串中的所有相邻重复项 - 力扣(LeetCode)
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
public String removeDuplicates(String s) {
Stack<Character> stack=new Stack<>();
StringBuilder stringBuilder=new StringBuilder(); //收集最后结果
for(int i=s.length()-1;i>=0;i--){
if(!stack.isEmpty() && stack.peek()==s.charAt(i)){
stack.pop(); //如果栈非空且与栈顶元素相同,则弹出
}else{
stack.push(s.charAt(i)); //反之则直接压入栈中
}
}
while(!stack.isEmpty()){
stringBuilder.append(stack.pop()); //从栈中依次弹出并加入StringBuilder
}
String res=stringBuilder.toString(); //将结果转换位字符串输出
return res;
}
之所以选择从右向左处理,是因为从栈弹出时顺序较原先是相反的
这时从右向左,处理完毕后弹出正好是原来的顺序
347. 前 K 个高频元素 - 力扣(LeetCode)
给你一个整数数组 nums
和一个整数 k
,请你返回其中出现频率前 k
高的元素。你可以按 任意顺序 返回答案。
public int[] topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<nums.length;i++){
map.put(nums[i],map.getOrDefault(nums[i],0)+1); //将元素和频次存入map中
}
Queue<Map.Entry<Integer,Integer>> q=new PriorityQueue<>(new Comparator<Map.Entry<Integer, Integer>>() {
@Override
public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
return o2.getValue()-o1.getValue();
}
}); //设置优先队列的排序规则
for(Map.Entry<Integer,Integer> e: map.entrySet()){
q.add(e); //将map中的每个entry都加入优先队列中
}
int[] res=new int[k];
for(int i=0;i<k;i++){
res[i]=q.poll().getKey(); //取出前k个元素即为前K个高频元素
}
return res;
}
注意优先队列中存放的是map的entry,既有key也有value,只存放其中一个是不对的
优先队列默认是最小优先队列,要重写Comparator接口,设置排序规则
150. 逆波兰表达式求值 - 力扣(LeetCode)
根据 逆波兰表示法,求表达式的值。
有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
注意 两个整数之间的除法只保留整数部分。
可以保证给定的逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
此题是根据后缀表达式计算算数值
遇到数直接压栈,遇到运算符则弹出栈的两个元素,并计算两个数后再压入栈中
注意弹出的顺序,后弹出的元素在前面
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList<Integer>();
for(int i=0;i<tokens.length;i++){
String token=tokens[i];
if(token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/")){
int num2=stack.pop();
int num1=stack.pop(); //后弹出的元素运算在前
switch (token) {
case "+":
stack.push(num1 + num2);
break;
case "-":
stack.push(num1 - num2);
break;
case "*":
stack.push(num1 * num2);
break;
case "/":
stack.push(num1 / num2);
break;
default:
}
}else{
int temp=Integer.valueOf(tokens[i]);
stack.push(temp); //遇到数直接压栈
}
}
return stack.pop();
}
239. 滑动窗口最大值 - 力扣(LeetCode)
public int[] maxSlidingWindow(int[] nums, int k) {
int[] res=new int[nums.length-k+1];
Queue<int[]> q=new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o2[1]-o1[1];
}
}); //优先队列存放一个数组,第0个元素是下标,第1个元素是值,按值进行优先队列排序
for(int i=0;i<k;i++){
q.offer(new int[]{i,nums[i]}); //先把前k个元素加入优先队列
}
res[0]=q.peek()[1]; //先把第一个结果加入
for(int i=1;i<nums.length-k+1;i++){
q.offer(new int[]{i+k-1,nums[i+k-1]}); //之后每一步向右滑动一步,加入优先队列
while(q.peek()[0]<i){
q.poll(); //最重要一步,在写结果前要判断,优先队列的最大值是否过期
} //当为i时,最大值的下标最少也要为i
res[i]=q.peek()[1];
}
return res;
}
此题最重要的是每步都加入一个新元素,即右侧向右滑动一格,但左侧不需要立即滑动
虽然左侧已经过期,但只要其不是最大值就不影响结果
换句话说,在右侧滑动之后,只要保证最大值下标未过期就可以
如果一个已经过期的比未过期的大,那它肯定会被优先队列弹出,相反一个很小的数可能一直留在优先队列
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
Deque<Integer> deque = new LinkedList<Integer>();
for (int i = 0; i < k; ++i) {
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
deque.pollLast();
}
deque.offerLast(i);
}
int[] ans = new int[n - k + 1];
ans[0] = nums[deque.peekFirst()];
for (int i = k; i < n; ++i) {
while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
deque.pollLast();
}
deque.offerLast(i);
while (deque.peekFirst() <= i - k) {
deque.pollFirst();
}
ans[i - k + 1] = nums[deque.peekFirst()];
}
return ans;
}