public class Stack1{
private StackdataStack;
private Stack minStack;
public void push(int num){
if(this.minStack.isEmpty()){
this.minStack.push(num);
}else if(num<=this.getMin()){
this.minStack.push(num);
}
this.dataStack.push(num);
}
public int pop(){
int value=this.dataStack.pop();
if(value==this.minStack.peek()){
this.minStack.pop();
}
return value;
}
public int getMin(){
return this.minStack.peek();
}
}
编写一个类,用两个栈实现队列,支持队列的基本操作(add,poll,peek)
由于栈的特点是先入后出,队列的特点是先进先出,使用两个栈正好能把顺序反过来;设计上使用两个栈,一个栈负责压入数据,记为pushStack,另外一个栈负责弹出数据popStack;
1. 压入数据的规则
pushStack正常压入数据,但是如果popStack不为空,不可将pushStack的数据压入到popStack;同时pushStack的数据要往popStack压入数据时,必须要一次性的将pushStack数据全部压入,add方法
2. 弹出数据规则
popStack()正常弹出数据即可。即poll,与peek方法,
3. 向popStack压入数据在poll,peek方法处执行
public class TwoStackQueue{
private Stack pushStack;
private Stack popStack;
public void add(int num){
pushStack.push(num);
}
public int poll(){
if(pushStack.empty()&&stackPush.empty()){
throw new RuntimeException("Queue is Empty");
}
else if(popStack.empty()){
while(!pushStack.empty()){
popStack.push(pushStack.pop());
}
}
return popStack.pop();
}
public int peek(){
if(pushStack.empty()&&stackPush.empty()){
throw new RuntimeException("Queue is Empty");
}
else if(popStack.empty()){
while(!pushStack.empty()){
popStack.push(pushStack.pop());
}
}
return popStack.peek();
}
}
编写一个类,用两个队列实现栈的功能,实现栈的push,pop方法
定义两个队列queue1,queue2
1. push方法实现
判断queue1,queue2是否为空,将需要进栈的元素num,添加到不为空的一个队列的队尾,
2. pop方法实现
判断queue1,queue2是否为空,为说明方便,假设queue1队列不为空,要获得栈顶元素(队尾的元素,记为value),将队列中的元素,从队首到队尾的前一个元素依次弹出,添加到queue2(初始状态为空队列)队尾位置,最后弹出queue1队尾元素value,此时queue2队列为空,
public class TwoQueueStack{
private LinkedList queue1;
private LinkedList queue2;
public void push(int num){
if(queue1.isEmpty()){
queue2.add(num);
}
if(queue2.isEmpty()){
queue2.add(num);
}
}
public int pop(){
if(queue2.isEmpty()&&queue2.isEmpty()){
throw new RuntimeException("Stack is Empty");
}
if(queue1.isEmpty()){
while(queue2.size()>1){
queue1.add(queue2.poll());
}
int value= queue2.poll();
}
else if{//queue2.isEmpty()
while(queue1.size()>1){
queue1.add(queue1.poll());
}
int value= queue1.poll();
}
return value;
}
}
只能用递归函数来实现栈的逆序的操作
两个递归函数:
- 递归函数1:将栈的栈底元素删除并且返回
- 递归函数2:逆序一个栈,将栈底元素删除之后的栈进行逆序,然后将栈底元素重新压入栈中
public class ReverseStack{
private Stack stack;
public int getAndRemoveLastElement(){
int result=stack.pop();
if(stack.isEmpty()){
return result;
}else{
int res=getAndRemoveLastElement();
stack.push(result);
return res;
}
}
public void reverseStack(){
if(stack.isEmpty()){
return;
}
int res=getAndRemoveLastElement();
reverseStack();
stack.push(res);
}
}
一个栈中的元素类型为整型,将该栈从栈顶到栈底从大到小进行排序,只允许申请一个栈,除此之外,可以申请新的变量,不能申请额外的数据结构
将要排序的栈记为stack,辅助栈为help,比较操作在help栈中实现,具体操作如下:
1. 在stack进行pop操作,弹出的元素记为cur
2. 比较cur,help的栈顶元素
- 如果cur小于help的栈顶元素,直接将cur压入help栈中
- 如果cur大于help的栈顶元素,则将help栈中的元素逐一弹出,逐一压入stack中,直到cur小于或者等于help的栈顶元素;
3. 最后将help的元素压入stack中
public void sortStackByStack(Stack stack){
Stack help=new Stack<>();
while(!stack.isEmpty()){
int cur=stack.pop();
while(!help.isEmpty()&&cur>help.peek()){
stack.push(help.pop());
}
help.push(cur);
}
while(!help.isEmpty()){
stack.push(help.pop());
}
}
有一个整型数组arr,和一个大小为w的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。
例如arr=[4,3,5,4,3,3,6,7],窗口大小为3
[4 3 5] 4 3 3 6 7 窗口的最大值为5
4 [3 5 4] 3 3 6 7 窗口的最大值为5
4 3 [5 4 3] 3 6 7 窗口的最大值为5
4 3 5 [4 3 3] 6 7 窗口的最大值为4
4 3 5 4 [3 3 6] 7 窗口的最大值为6
4 3 5 4 3 [3 6 7] 窗口的最大值为7
数组长度为n,窗口为w,将产生n-w+1
输出为:[5 5 5 4 6 7]
使用双端队列实现窗口最大值的更新,双端队列qmax保存的是数组的索引。队首即为窗口的最大值的索引。
1. 假设遍历到arr[i],qmax的放入规,则:
- qmax为空,直接放入i,
- qmax不为空,取出当前qmax的队尾存放的下标j(其实是队列的最小值)
- 如果arr[i]>=arr[j],直接将j从qmax队列弹出,继续qmax的放入规则,说明arr[j]不可能是之后向右滑动窗口的最大值
- 如果arr[j]>arr[i],将小标i,加入到qmax队尾中,由于arr[i]可能是之后向右滑动窗口的最大值,
2. 要清除队列中最大值的失效值。当遍历的数组元素下标i,qmax队首元素为j,窗口的长度w,之间满足j=i-w;也就是元素arr[j]最大值已经失效了
3. 只要遍历数组元素下标i满足i>w-1;将qmax队首元素为某个窗口的最大值,保存即可。
public int[] getMaxWindow(int[]arr,int w){
if(arr==null||arr.length0)
return null;
int index=0;
int res=new int[arr.length-w+1];
LinkedList qmax=new LinkedList<>();
for(int i=0;iwhile(!qmax.isEmpty()&&arr[i]>=arr[qmax.peekLast()])
{
qmax.pollLast();
}
qmax.addLast(i);
if(i-w==qmax.peekFirst())//清除失效最大值
qmax.pollFirst();
if(i>w-1)
res[index++]=arr[qmax.peekFirst()];
}
return res;
}
给定一个整型矩阵map,其中的值只有0,1;求其中全是1的所有矩形区域中,最大的矩形区域为1的数量。
例如 1 1 1 0 ,最大的矩形区域有3个1,返回1
map=[1 0 1 1
1 1 0 1
1 1 1 1]
其中最大的矩形区域有4个1,返回4
如果矩阵的大小为O(NM),本题的时间复杂度为O(NM);
1. 矩阵的行数为N,以每一行做切割,统计以当前作为底的情况,每个位置上为1的数量,使用高度数组height表示,
- 以题目描述的map为例,从第一行做切割,height=[1 0 1 1]
- 以第二行做切割,更新height;height=[2 1 0 2];height的更新操作为height[i]=map[i][j]==0?0:height[j]+1;
- 以第三行做切割,更新height;height=[3 2 1 3]
2. 对于每次切割,利用更新的height数组求出以每一行为底的情况下,最大的矩形是什么
- 求解当前height数组组成的最大矩形,比如{3,2 ,3, 1},看出一个数组组成的直方图
1. 第1根高度为3的柱子无法向左扩展,右边为2, 也无法向右左扩展,则以第1根柱子为高度的矩形面积为3*1=3;
2. 第2根高度为2的柱子向左可以扩展一个距离,向右扩展1个距离,则以第2根柱子为高度的矩形面积为2*3=6;
3. 同理,以第3根柱子为高度的矩形面积为3*1=3
4. 同理,以第4根柱子为高度的矩形面积为1*4=4
- 使用栈来实现上述操作
1. 生成一个栈,记为stack,每遍历一个位置都会把位置压入到stack中
2. 当遍历到arr[i],栈为空时,直接压入,若栈不为空,比较栈顶位置所代表的值与arr[i]大小,若arr[i]较大,直接压入stack中;否则则把栈中存的位置不断弹出,直到某一个栈顶所代表的值小于arr[i],再把位置i压入
3. 在遍历到数组arr[i],弹出的栈顶位置为j,弹出栈顶之后,新的栈顶元素为k,那么可以知道以arr[j]为高度的柱子向右最多可以扩展到(i-1),因为j之所以被弹出,是由于遇到了**第一个**比位置j值小的位置;向左最多扩展到k+1;这是因为栈中k,j位置是相邻的,并且从栈顶到栈底的位置所代表的的值依次递减并且无重复的,由于k位置在栈中,arr[k+1...j-1]都是既大于arr[k],否则k会被弹出;同时由于j在栈中,并且与k相邻,所以arr[k+1...j-1]没有小于arr[j],否则j不可能与k相邻。
4. j位置的柱子能扩出来的最大矩形为(i-k-1)arr[j]
public int maxSize(int[][]map){
if(map==null|||map.length==0||map[0].length==0)
return 0;
int maxArea=0;
int []height=new int[map[0].length];
for(int i=0;ifor(int j=0;j
给定数组arr和整数num,共返回多少个数组子数组的满足如下情况:
max(arr[i...j])-min(arr[i..j])<=num
要求:
如果数组的长度为N,时间复杂度为O(N)的解法
使用双端队列实现,qmax维护窗口arr[i…j]的最大值更新的结构,qmin维护窗口子数组arr[i..j]最小值更新结构,
两个基本的结论:
- 如果子数组arr[i…j]满足条件,那么arr[i..j]的子数组arrk…l都满足条件
- 反之arr[i…j]不满足条件,那么包含该数组arr[i..j]的子数组必然不满足条件。
具体实现步骤:
public int getNum(int[] arr,int num){
if(arr==null||arr.length==0){
return 0;
}
LinkedList qmin=new LinkedList<>();
LinkedList qmax=new LinkedList<>();
int i=0,j=0;
int res=0;
while(iwhile(jwhile(!qmin.isEmpty()&&arr[j]<=arr[qmin.peekLast()]){
qmin.pollLast();
}
qmin.addLast(j);
while(!qmax.isEmpty()&&arr[j]>=arr[qmax.peekLast()]){
qmax.pollLast();
}
qmax.addLast(j);
if(arr[qmax.peekFirst()]-arr[qmin.peekFirst()]>num)
break;
j++;
}
if(qmin.peekFist()==i)
qmin.pollFirst();
if(qmax.peekFirst()==i)
qmax.pollFirst();
res+=j-i;
i++;
}
return res;
}