当前位置: 首页 > news >正文

leetcode 堆栈(栈+优先队列)——java实现

java创建堆栈和操作函数

Queue<String> queue = new LinkedList<String> ();//队列定义
Deque<String> stack= new LinkedList<String>();//堆栈
队列方法:
queue.offer(e) null
queue.poll() 返回移除的值
queue.peek()
堆栈方法:
stack.push(e) null
stack.pop()返回移除的值
stack.peek()返回栈顶的元素但不移除它
stack.size()返回栈中元素2 (假设栈里有1,5两个元素)
stack.search(2));返回从栈顶往前数第2个元素1

堆的逻辑结构是一颗完全二叉树
堆的物理结构是一个数组
大根堆就是整个完全二叉树,任意一个根节点的值都比左右子树的值大
小根堆表示整个完全二叉树,任意一个根节点的值都比左右子树的值小。

leetcode

20. 有效的括号

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
也就是说:括号可以互相包含,但不能参差摆放,如下例: “{[]}()” true ({)} false

遇到左括号入栈
遇到右括号检验栈顶元素是否和它匹配,匹配则出栈,否则False
最后栈空则true

class Solution {public boolean isValid(String s) {//括号可以互相包含,但不能参差摆放,如下例: "{[]}()" true ({)} false Deque<Character> sta = new LinkedList<Character>();HashMap<Character,Character> map = new HashMap<Character,Character>();map.put('(',')');map.put('[',']');map.put('{','}');for(int i=0;i<s.length();i++){if(s.charAt(i)=='('||s.charAt(i)=='['||s.charAt(i)=='{'){sta.push(s.charAt(i));}else if(s.charAt(i)==')'||s.charAt(i)==']'||s.charAt(i)=='}'){if(!sta.isEmpty() &&map.get(sta.peek())==s.charAt(i)){//匹配上了sta.pop();}else return false;}}return sta.isEmpty();}
}

155. 最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:
MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。

关键在于:建两个栈,一个存正常放入的数,另一个存小值使得栈顶是当前时刻最小的值。

class MinStack {Deque<Integer> mstack;Deque<Integer> stackmin;int min;public MinStack() {mstack = new LinkedList<Integer>();stackmin = new LinkedList<Integer>();//存min的栈,栈顶是当前时刻最小的值}public void push(int val) {mstack.push(val);if(!stackmin.isEmpty()){if(val<=stackmin.peek()){//比栈顶值小就入栈stackmin.push(val);}}else{stackmin.push(val);}}public void pop() {int top = mstack.pop();if(top==stackmin.peek()){stackmin.pop();}}public int top() {return mstack.peek();}public int getMin() {return stackmin.peek();}
}

394. 字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
(重点样例)
输入:s = “3[a2[c]]”
输出:“accaccacc”
输入:s=b2[c]
输出:abcc

重点注意:在什么时候数组字母入栈和出栈
以及动态更新字母串用StringBuilder或StringBuffer

class Solution {public String decodeString(String s) {//有嵌套的情况//数字存放在数字栈,字符串存放在字符串栈,遇到右括号时候弹出一个数字栈,字母栈弹到左括号为止。//关键点:(1)处理多位数(2)遇到 '[',将当前的字符串和数字推入各自的栈(3)遇到 ']'开始解码Deque<Integer> numStack = new LinkedList<Integer>();Deque<String> strStack = new LinkedList<String>();int number=0;String str="";for(int i=0;i<s.length();i++){if(Character.isDigit(s.charAt(i))){//是数字number = number*10+s.charAt(i)-'0';//处理多位数}else if(s.charAt(i)=='['){//数字结束,字母开始numStack.push(number);number=0;strStack.push(str);str="";}else if(s.charAt(i)==']'){//字母结束,处理一次数字加字母StringBuilder strb = new StringBuilder(strStack.pop());//用str栈顶的初始化一个stringbuilderint n=numStack.pop();for(int j=0;j<n;j++){strb.append(str);}str=strb.toString();//更新当前字符串}else{//是字母str+=s.charAt(i);}}return str;}
}

739. 每日温度

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
示例 1:
输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]
示例 2:
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]
示例 3:
输入: temperatures = [30,60,90]
输出: [1,1,0]

单调栈:在单调栈基础题中,经常需要类似这种的解题思路:在 O(n) 的时间复杂度内求出数组中各个元素右侧第一个更大的元素及其下标,然后一并得到其他信息。
下图摘自leetcode:
栈中存入下标,并维持栈中下标对应的元素从左到右非递增。
arr[0],arr[1],arr[2]非递增依次入栈
在这里插入图片描述
arr[2]出栈,arr[3]入栈,以此同时记录result[2]=3-2;(这个result是题目要求的下一个更大元素)
在这里插入图片描述
arr[3],arr[1],arr[0]都出栈,并记录result[3]=4-3,result[1]=4-1,result[0]=4-0;
至于右侧没有更大元素的在result数组里没填过值,就默认为0了。【而按照下一题,HashMap里没有默认值,所以是map.containsKey为空判断一下然后取值-1】

class Solution {public int[] dailyTemperatures(int[] temperatures) {//单调栈Deque<Integer> decStack = new LinkedList<Integer>();int[] result = new int[temperatures.length];for(int i=0;i<temperatures.length;i++){while(!decStack.isEmpty()&&temperatures[i]>temperatures[decStack.peek()]){int m = decStack.pop();result[m]=i-m;//记录差距填数}decStack.push(i);//记录下标}return result;}
}

496. 下一个更大元素 I

nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。
给你两个 没有重复元素 的数组 nums1 和 nums2 ,下标从 0 开始计数,其中nums1 是 nums2 的子集。
对于每个 0 <= i < nums1.length ,找出满足 nums1[i] == nums2[j] 的下标 j ,并且在 nums2 确定 nums2[j] 的 下一个更大元素 。如果不存在下一个更大元素,那么本次查询的答案是 -1 。
返回一个长度为 nums1.length 的数组 ans 作为答案,满足 ans[i] 是如上所述的 下一个更大元素 。

示例 1:
输入:nums1 = [4,1,2], nums2 = [1,3,4,2].
输出:[-1,3,-1]
解释:nums1 中每个值的下一个更大元素如下所述:

  • 4 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
  • 1 ,用加粗斜体标识,nums2 = [1,3,4,2]。下一个更大元素是 3 。
  • 2 ,用加粗斜体标识,nums2 = [1,3,4,2]。不存在下一个更大元素,所以答案是 -1 。
    示例 2:
    输入:nums1 = [2,4], nums2 = [1,2,3,4].
    输出:[3,-1]
    解释:nums1 中每个值的下一个更大元素如下所述:
  • 2 ,用加粗斜体标识,nums2 = [1,2,3,4]。下一个更大元素是 3 。
  • 4 ,用加粗斜体标识,nums2 = [1,2,3,4]。不存在下一个更大元素,所以答案是 -1 。
class Solution {public int[] nextGreaterElement(int[] nums1, int[] nums2) {//下一个更大的元素,就是用单调栈解Deque<Integer> decStack = new LinkedList<Integer>();int[] result = new int[nums1.length];HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();//因为num1是num2的子集且打乱顺序,就用HashMap记录for(int i=0;i<nums2.length;i++){while(!decStack.isEmpty()&&nums2[i]>decStack.peek()){int m=decStack.pop();map.put(m,nums2[i]);}                decStack.push(nums2[i]);//这回是直接记录值}for(int i=0;i<nums1.length;i++){result[i]= map.containsKey(nums1[i])? map.get(nums1[i]):-1;}return result;}
}

215. 数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入: [3,2,1,5,6,4], k = 2
输出: 5
示例 2:

输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4

Arrays.sort(nums) 默认使用快排

  1. 快排
class Solution {public int findKthLargest(int[] nums, int k) {Arrays.sort(nums);//快排return nums[nums.length-k];}
}
  1. 优先队列
    优先队列的思路是很朴素的。由于找第 K 大元素,其实就是整个数组排序以后后半部分最小的那个元素。因此,我们可以维护一个有 K 个元素的最小堆

新遍历到的数大于堆顶的时候,才将堆顶拿出,然后放入新读到的数,进而让堆自己去调整内部结构。

PriorityQueue 底层是动态数组,底层是基于堆实现。

class Solution {public int findKthLargest(int[] nums, int k) {//维护一个k大小的小顶堆,直接使PriorityQueue不用手动实现堆操作了PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();//小顶堆for(int i=0;i<k;i++){//建大小为k的堆minHeap.offer(nums[i]);}for(int i=k;i<nums.length;i++){//相当于从全部数组里提出len-k个小值就得到了第k大的值if(nums[i]>minHeap.peek()){//比堆顶大,就提出堆顶小值,把nums[i]放进去minHeap.poll();minHeap.offer(nums[i]);}}return minHeap.peek();}
}

347. 前 K 个高频元素

给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:

输入: nums = [1], k = 1
输出: [1]

依旧是k大小的小顶堆【优先队列】

重点注意:

用HashMap统计元素出现次数,以及优先队列里元素的存储形式。
还有HashMap的遍历方式

HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();
//优先队列里元素的存储形式是int[]的数组,[0]存key[1]存value
PriorityQueue<int[]> minHeap = new PriorityQueue<int[]>(n,new Comparator<int[]>(){//定义比较方式public int compare(int[] a,int[] b){return a[1]-b[1];//按value升序,即小顶堆}
} );

整体代码:

class Solution {public int[] topKFrequent(int[] nums, int k) {//先统计每个数出现次数,再建k大小的小顶堆HashMap<Integer,Integer> map = new HashMap<Integer,Integer>();for(int i=0;i<nums.length;i++){if(map.containsKey(nums[i])){int cn=map.get(nums[i])+1;map.put(nums[i],cn);}else{map.put(nums[i],1);}}int n=map.size();//优先队列里元素的存储形式是int[]的数组,[0]存key[1]存valuePriorityQueue<int[]> minHeap = new PriorityQueue<int[]>(n,new Comparator<int[]>(){//定义比较方式public int compare(int[] a,int[] b){return a[1]-b[1];//按value升序,即小顶堆}} );int cn=0,kk=0;//放前k个for(Integer key:map.keySet()){cn++;if(cn>k){break;}int value=map.get(key);minHeap.offer(new int[]{key,value});}int cnn=0;//继续后n-k个for(Integer key:map.keySet()){cnn++;if(cnn>k){int value=map.get(key);if(value>minHeap.peek()[1]){minHeap.poll();minHeap.offer(new int[]{key,value});}}}//最后数组存放k大小堆中的值,不按照顺序int[] a=new int[k];for(int i=0;i<k;i++){System.out.println(minHeap.peek()[0]+":"+minHeap.peek()[1]);a[i]=minHeap.poll()[0];}return a;}
}

http://www.mrgr.cn/news/1862.html

相关文章:

  • 牛客网SQL进阶129 :月均完成试卷数不小于3的用户
  • spring(1)
  • Hadoop 中的大数据技术:调优篇(2)
  • 0815,析构函数,拷贝构造函数,赋值运算符函数
  • 异构数据同步 datax (2)-postgres 写扩展
  • AI小白福音来啦~Flux文生图,支持手部细节,直出精美图像,让你瞬间变高手!
  • 深度学习基础—动量梯度下降法
  • 如何将 ONLYOFFICE 与 Moodle 进行集成,让师生在学习管理平台中协作编辑办公文档
  • uniapp在线下载安装包更新app
  • FastICENet:一种用于航空遥感河流冰图像的实时精确语义分割模型
  • 数值计算引擎:搭建远程容器开发环境
  • 【数据结构】关于冒泡排序,选择排序,插入排序,希尔排序,堆排序你到底了解多少???(超详解)
  • 蒟蒻的尊严被打得一败涂地17
  • QT翻金币小游戏(含音频图片文件资源)
  • 探索数字媒体产业园区的未来之路
  • 每日OJ_牛客_反转部分单向链表
  • 二叉树详解(1)
  • [星瞳科技]OpenMV有哪些合适的配件?
  • 【网络】UDP和TCP之间的差别和回显服务器
  • VSCode插件离线安装