标签:
本文是【常用算法思路分析系列】的第三篇,分析栈和队列相关的高频题目。本文分析:1、可查询最值的栈;2、用两个栈实现队列的功能;3、反转栈中元素;4、排序栈中元素;5、滑动窗口问题。
本系列前两篇导航:
【常用算法思路分析系列】排序高频题集
【常用算法思路分析系列】字符串高频题集
public class GetMinStack {
Stack<Integer> stackData = new Stack<Integer>();
Stack<Integer> stackMin = new Stack<Integer>();
public void push(int node) {
if(stackMin.empty()){
stackData.push(node);
stackMin.push(node);
}else{
//第一种方案
if(node > stackMin.peek()){
stackData.push(node);
}else{
stackData.push(node);
stackMin.push(node);
}
/* 第二种方案
int minTop = stackMin.peek();
if(node > minTop){
stackData.push(node);
stackMin.push(minTop);
}else{
stackData.push(node);
stackMin.push(node);
}
*/
}
}
public void pop() {
if(!stackData.empty() && ! stackMin.empty()){
int dataTop = stackData.peek();
int minTop = stackMin.peek();
//第一种方案
if(dataTop == minTop){//此时两个栈都需要出栈操作
stackData.pop();
stackMin.pop();
}else if(dataTop > minTop){
stackData.pop();
}
/*
* 第二种方案
stackData.pop();
stackMin.pop();
*/
}
}
public int top() {
return stackData.peek();
}
public int min() {
return stackMin.peek();
}
}编写一个类,只能用两个栈结构实现队列,支持队列的基本操作(push,pop)。
给定一个操作序列ope及它的长度n,其中元素为正数代表push操作,为0代表pop操作,保证操作序列合法且一定含pop操作,请返回pop的结果序列。
[1,2,3,0,4,0],6
返回:[1,2]代码如下:
public class TwoStack {
public int[] twoStack(int[] ope, int n) {
if(ope == null || n == 0)
return null;
Stack<Integer> stackPush = new Stack<Integer>();
Stack<Integer> stackPoll = new Stack<Integer>();
int popCount = 0;//出栈次数
for(int i = 0; i < n; i++){
if(ope[i] != 0){
stackPush.push(ope[i]);
}else{
popCount++;
}
}
int[] result = new int[popCount];
//将stackPush栈中的所有数据导入到stackPoll栈中
while(!stackPush.empty()){
stackPoll.push(stackPush.pop());
}
for(int i = 0; i < popCount; i++){
result[i] = stackPoll.pop();
}
return result;
}
}public class StackReverse {
//反转栈
public static int[] reverseStack(int[] A, int n) {
if(A == null || n == 0)
return null;
Stack<Integer> stack = new Stack<Integer>();
for(int i = 0; i < n; i++){
stack.push(A[i]);
}
reverse(stack);//开始反转操作
for(int i = n-1; i >= 0; i--){
A[i] = stack.pop();
}
return A;
}
/**
* 反转栈中的元素
* @param stack
*/
public static void reverse(Stack<Integer> stack){
if(stack.isEmpty()){
return ;
}
//下面就是先递归拿到栈底元素,然后再把栈底元素入栈,此时栈中元素顺序反转
int bottom = popBottom(stack);
reverse(stack);
stack.push(bottom);
}
/**
* 移除栈底元素,并返回
* @return
*/
public static int popBottom(Stack<Integer> stack){
int result = stack.pop();
if(stack.isEmpty()){//弹出一个栈顶元素后,栈为空了,表示该元素就是栈底元素
return result;
}else{
int last = popBottom(stack);
stack.push(result);//注意!!!这里是把前面拿到的元素压入,这样栈底元素才不会再次压入到栈中
return last;
}
}
public static void main(String[] args) {
int[] a = {9,8,7,6,5,4,3,2,1};
reverseStack(a,a.length);
}
}public static ArrayList<Integer> twoStacksSort(int[] numbers) {
if(numbers == null)
return null;
Stack<Integer> stack = new Stack<Integer>();
for(int i = numbers.length - 1; i >= 0; i--){
stack.push(numbers[i]);
}
Stack<Integer> help = new Stack<Integer>();
int pop,temp;
while(!stack.isEmpty()){
pop = stack.pop();
if(help.isEmpty()){
help.push(pop);
}else{
if(pop <= help.peek()){
help.push(pop);
}else{
while(!help.isEmpty() && pop > help.peek()){//将help中元素放入到stack中
temp = help.pop();
stack.push(temp);
}
//help栈为空了或者找到了pop<=help栈顶的元素
help.push(pop);
}
}
}
while(!help.isEmpty()){
stack.push(help.pop());
}
ArrayList<Integer> res = new ArrayList<Integer>();
while(!stack.isEmpty()){
res.add(stack.pop());
}
return res;
}/**
* 数组作为栈,0的位置为栈顶
* @param numbers
* @return
*/
public static ArrayList<Integer> twoStacksSort2(int[] numbers) {
if(numbers == null)
return null;
int[] help = new int[numbers.length];
int i = 0;//指向numbers栈顶元素
int j = -1;//指向help栈顶元素
int pop;
while(i >= 0 && i != numbers.length){
pop = numbers[i];
if(j < 0){
help[++j] = pop;
}else{
if(pop <= help[j]){
help[++j] = pop;
}else{
while(j >= 0 && pop > help[j]){
numbers[i--] = help[j--];
}
help[++j] = pop;
}
}
i++;
}
ArrayList<Integer> res = new ArrayList<Integer>();
for (int k = 0; k < help.length; k++) {
res.add(help[k]);
System.out.println(help[k]);
}
return res;
}有一个整型数组 arr 和一个大小为 w 的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。 返回一个长度为n-w+1的数组res,res[i]表示每一种窗口状态下的最大值。 以数组为[4,3,5,4,3,3,6,7],w=3为例。因为第一个窗口[4,3,5]的最大值为5,第二个窗口[3,5,4]的最大值为5,第三个窗口[5,4,3]的最大值为5。第四个窗口[4,3,3]的最大值为4。第五个窗口[3,3,6]的最大值为6。第六个窗口[3,6,7]的最大值为7。所以最终返回[5,5,5,4,6,7]。
给定整形数组arr及它的大小n,同时给定w,请返回res数组。保证w小于等于n,同时保证数组大小小于等于500。
[4,3,5,4,3,3,6,7],8,3
返回:[5,5,5,4,6,7]思路:
public static int[] slide(int[] arr, int n, int w) {
if(arr == null || w < 1 || n < w){
return null;
}
int[] res = new int[n - w + 1];
//一个维护w个窗口的双端队列,保持下标为对头元素的值最大
LinkedList<Integer> qmax = new LinkedList<Integer>();
int index = 0;
for(int i = 0; i < n; i++){
//执行队尾进入规则
while(!qmax.isEmpty() && arr[qmax.peekLast()] <= arr[i]){
qmax.pollLast();
}
qmax.addLast(i);//将下标加入到队尾
//执行对头弹出规则
if(qmax.peekFirst() == i - w){
qmax.pollFirst();
}
if(i >= w - 1){//如果双端队列里面至少维持了w个数据,则每次可以从对头中拿到最大值
res[index++] = arr[qmax.peekFirst()];
}
}
return res;
}
本系列下一篇将是与链表相关算法题。
标签:
原文地址:http://blog.csdn.net/shakespeare001/article/details/51469268