java中的栈和队列的实现用双端队列Deque
Deque deque = new LinkedList()//此种方式创建取出的元素是object类型要强制转换为int等
Deque deque =new LinkedList<>()//此种方式创建不需要强制类型转化。
#用作队列
deque.addLast(e);
deque.removeFirst(e);
deque.getFirst(e);
#用作栈
deque.addFirst(e);
deque.removeFirst(e);
deque.getFirst(e);]
#deque的栈方法
deque.push(e); //addFirst
deque.pop(); //removeFirst
deque.peek();//getFirst
q.size();
q.isEmpty();
232. 用栈实现队列
你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
进阶:
你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。
不管是用栈实现队列还是用队列是实现栈,都可以用双栈/双队列的方式。每个元素最多进站出站两次,所以均摊时间复杂度为O(1);
每次 pop 或peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序
class MyQueue {
private Deque in;
private Deque out;
/** Initialize your data structure here. */
public MyQueue() {
in=new LinkedList();
out=new LinkedList();
}
/** Push element x to the back of queue. */
public void push(int x) {
in.push(x);
}
/** Removes the element from in front of queue and returns that element. */
public int pop() {
if(out.isEmpty())
{
while(!in.isEmpty())
{
out.push(in.pop());
}
}
return (int)out.pop();
}
/** Get the front element. */
public int peek() {
if(out.isEmpty())
{
while(!in.isEmpty())
{
out.push(in.pop());
}
}
return (int)out.peek();
}
/** Returns whether the queue is empty. */
public boolean empty() {
return in.isEmpty()&&out.isEmpty();
}
}
225. 用队列实现栈
队列是先进先出的规则,把一个队列中的数据导入另一个队列中,数据的顺序并没有变,并有变成先进后出的顺序,,所以用栈实现队列, 和用队列实现栈的思路还是不一样的.思路有两种,一种是每次push时放到队头,一种是每次pop时先把队伍前面部分转移到备份队列,把队尾弹出,再从备份队列转移回来。
class MyStack {
private Deque que1;
private Deque que2; //备份队列
/** Initialize your data structure here. */
public MyStack() {
que1=new LinkedList();
que2=new LinkedList();
}
/** Push element x onto stack. */
public void push(int x) { //将放到队尾改为放到队首
que2.addLast(x); //刚push进来的元素放备份队列到队首
while(!que1.isEmpty()) //原本的元素放到备份队列的队首后面
{
que2.addLast(que1.removeFirst());
}
Deque tmp=que1; //交换que1和备份队列,备份队列为空,que1队首是刚刚进来的元素,出队出的是刚刚进来的元素。
que1=que1;
que2=tmp;
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return (int)que1.removeFirst();
}
/** Get the top element. */
public int top() {
return (int)que1.getFirst();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return que1.isEmpty();
}
}
20. 有效的括号
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
1.遇到右括号但栈为空或栈顶括号不匹配
2.已经没有右括号但栈内剩余左括号
class Solution {
public boolean isValid(String s) {
Deque stack= new LinkedList();
for(int i=0;i
1047. 删除字符串中的所有相邻重复项
输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。"对对碰“
class Solution {
public String removeDuplicates(String S) {
Deque stack=new LinkedList();
for(int i=0;i
150. 逆波兰表达式求值
输入: ["2", "1", "+", "3", "*"]
输出: 9
解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
思路:遇到数字入栈,遇到操作符弹出栈顶的两个操作数计算结果后再将结果入栈,最终栈中剩下的一个数字是结果。
class Solution {
public int evalRPN(String[] tokens) {
Deque numbers=new LinkedList();
for(String token:tokens)
{
if(token.equals("+")||token.equals("-")||token.equals("*")||token.equals("/"))
{
int b=(int)numbers.pop(),a=(int)numbers.pop();
int result=cal(a,b,token);
numbers.push(result);
}
else
{
numbers.push(Integer.valueOf(token));
}
}
return (int)numbers.pop();
}
public int cal(int a,int b,String opt)
{
switch(opt)
{
case "+":
return a+b;
case "-":
return a-b;
case "*":
return a*b;
case "/":
return a/b;
default:
return 0;
}
}
}
单调栈主要用来解决找到比当前元素更大/小的前一个/后一个元素的问题
单调栈优化了for循环暴力求解的时间效率,因为每个元素只会进栈出栈一次,所以时间复杂度是O(n)。
84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
对每一个柱子找到其左边和右边第一个比它低的,此柱子高度*左右下标范围=此高度下矩形的最大面积。
class Solution {
public int largestRectangleArea(int[] heights) {
//对每一个柱子找到其左边和右边第一个比它低的,此柱子高度*左右下标范围=此高度下矩形的最大面积。
//添加哨兵,在heights最后补0,强迫最后栈内元素全部出栈,在最前补0,不用额外判断栈pop了一次之后为空的情况(说明栈顶柱子的高度是所有柱子里最低的)。
int[] new_heights = new int[heights.length + 2];
for (int i = 1; i < heights.length + 1; i++) {
new_heights[i] = heights[i - 1];
}
int maxArea= 0;
Deque stack=new LinkedList<>();
for(int i=0;inew_heights[i])
{
int cur=stack.pop();
int left=stack.peek()+1;//矩形左边界,当前栈顶就是左边第一个比出栈元素低的柱子
int right=i-1;//矩形右边界,i是右边第一个比出栈元素低的柱子的下标
int width=right-left+1;
maxArea=Math.max(maxArea,new_heights[cur]*width);
}
stack.push(i);
}
return maxArea;
}
}
42. 接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
找到每个元素左右第一个比它高的柱子,水坑的高度就是左右两边更低的一边减去底部,宽度是在左右中间
class Solution {
public int trap(int[] height) {
int result=0;
if(height.length<=2)return result;
Deque stack= new LinkedList<>();
for(int i=0;i
739. 每日温度
请根据每日 气温
列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0
来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73]
,你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]
。
找到每日右边第一个大于该日气温的日子,注意栈内存的是下标,要用T[stack.peek()]
class Solution {
public int[] dailyTemperatures(int[] T) {
int[] result =new int[T.length];
Deque stack=new LinkedList<>();
for(int i=0;i
一个序列只有头尾的数据有变动,需要求该序列的最大值或最小值,可以尝试使用单调队列,常见题型是滑动窗口类
239. 滑动窗口最大值
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
本题需要借助单调队列,单调队列是单调递增或单调递减的队列,它不是一种固有的数据结构,需要我们自己维护。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
Deque deque=new LinkedList();
int n=nums.length;
int ans[]=new int[n-k+1];
int j=0; //ans 的下标
for(int i=0;i
347. 前 K 个高频元素
给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
你可以按任意顺序返回答案。
class Solution {
public int[] topKFrequent(int[] nums, int k) {
//统计每个元素的频率
Map hashMap=new HashMap<>();
for(int i=0;i0则交换ab否则不交换,因此升序是a-b,降序是b-a
PriorityQueue queue=new PriorityQueue<>(new Comparator(){
@Override
public int compare(Integer a,Integer b)
{
return hashMap.get(a)-hashMap.get(b);
}
});
//把优先队列大小维持在k,大于k了就移除一个队首频率最小的元素
//复杂度Onlogk ,插入大小为k的堆复杂度Ologk
for(Integer key:hashMap.keySet())
{
if(queue.size() res=new ArrayList<>();
int result[]=new int[k];
int j=0;
while(!queue.isEmpty())
{
result[j++]=queue.remove();
}
return result;
}
}
方法二 利用快速排序中的分治之的分,找到第n-k大,其后面所有元素就是前k大。
不明白partition时为什么一定要while l<=r ,swap(left,r)??????a
class Solution {
Random random=new Random();
Map hashMap= new HashMap<>();
public int[] topKFrequent(int[] nums, int k) {
for(int num:nums)
{
if(hashMap.containsKey(num))
hashMap.put(num, hashMap.get(num)+1);
else
hashMap.put(num,1);
}
int [] elements=new int[hashMap.keySet().size()];
int i=0;
for(Integer a:hashMap.keySet())
{
elements[i++]=a;
}
int l=0,r=elements.length-1,target=elements.length-k;
while(true)
{
int index=partition(elements, l, r);
if(index==target)
{
return Arrays.copyOfRange(elements, index, elements.length);
}
else if(index =pivot){
r--;
continue;
}
swap(nums,l,r);
l++;
r--;
}
swap(nums,left,r);
return r;
}
public void swap(int [] nums,int a,int b)
{
int temp=nums[a];
nums[a]=nums[b];
nums[b]=temp;
}
}
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue minHeap=new PriorityQueue<>(new Comparator(){
@Override
public int compare(Integer a,Integer b)
{
return a-b;
}
});
for(int i=0;i