栈操作之逆序 排序 汉诺塔 右边第一大数 牛视野问题

1.用递归逆序一个栈
一个栈进入顺序为1,2,3,4,则从栈顶往下看是4,3,2,1
希望从栈顶往下看也是1,2,3,4如何用递归实现。

参考大神的思路:
用两个递归函数
第一个函数返回栈底元素并移出
第二个递归函数逆序。

public static int getAndRemoveLastElement(Stack<Integer> stack) {
	int result = stack.pop();
	if(stack.isEmpty()) {//栈空返回栈底元素
		return result;
	}else {
		int last = getAndRemoveLastElement(stack);//得到栈底元素
		stack.push(result);//将除了栈底元素以外的元素重新压入栈
		return last;//返回栈底元素
	}
}
	
public static void reverse(Stack<Integer> stack) {
	if(stack.isEmpty()) {//栈空的时候,返回
		return ;
	}
	int i = getAndRemoveLastElement(stack);//得到栈底元素
	reverse(stack);//递归从下往上得到栈中元素
	stack.push(i);//递归返回的时候,从栈底依次往上压入元素
}

2.利用栈实现另一个栈元素排序,只能用一个辅助栈,不能用别的数据结构,可以利用辅助边量。
例如:一个栈从栈顶到栈底为 2 3 6 5 1 4
最后要排序为:6 5 4 3 2 1

思路:用一个辅助栈,依次从原栈中取出一个元素,如果比辅助栈顶元素小,直接放。
如果比辅助栈顶元素大,则把辅助栈所有元素都放回原栈,再把原栈当前元素放入辅助栈。

public static void sortStack(Stack<Integer> stack){
	    Stack<Integer> help = new Stack<Integer>();
	    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());
        }
	}

3.汉诺塔问题
添加一个限制条件:不能直接从最左侧到最右侧
非递归用栈实现
思路:1.小压大原则
2.相邻不可逆原则
解释如下:
L->M M->L 与M->R R->M为相邻逆过程,重复没有意义,不会得到最小步数。

public class Main {
    
      public static void main(String[] args) {
           hanoiProblem(3,"左","中","右");
      }
      public enum Action{
    	 No,LToM,MToL,MToR,RToM 
      }
      public static int hanoiProblem(int num,String left,String mid,String right) {
    	  Stack<Integer> ls = new Stack<Integer>();
    	  Stack<Integer> ms = new Stack<Integer>();
    	  Stack<Integer> rs = new Stack<Integer>();
    	  ls.push(Integer.MAX_VALUE);
    	  ms.push(Integer.MAX_VALUE);
    	  rs.push(Integer.MAX_VALUE);
    	  for(int i = num;i>0;i--) {
    		  ls.push(i);
    	  }
    	  Action [] record = {Action.No};
    	  int step = 0;
    	  while(rs.size()!=num+1) {
    		  step+=fStackToStack(record,Action.MToL,Action.LToM,ls,ms,left,mid);
    		  step+=fStackToStack(record,Action.LToM,Action.MToL,ms,ls,mid,left);
    		  step+=fStackToStack(record,Action.RToM,Action.MToR,ms,rs,mid,right);
    		  step+=fStackToStack(record,Action.MToR,Action.RToM,rs,ms,right,mid);
    	  }
    	  return step;
      }
      public static int fStackToStack(Action[] record,Action preNoAct,Action nowAct,Stack<Integer> fStack,
    		  Stack<Integer> tStack,String from,String to) {
    	  if(record[0]!=preNoAct&&fStack.peek()<tStack.peek()) {
    		  tStack.push(fStack.pop());
    		  System.out.println("Mode"+tStack.peek()+"from"+from+"to"+to);
    		  record[0] = nowAct;
    		  return 1;
    	  }
    	  return 0;
      }
}

运行结果:

Move1from左to中
Move1from中to右
Move2from左to中
Move1from右to中
Move1from中to左
Move2from中to右
Move1from左to中
Move1from中to右
Move3from左to中
Move1from右to中
Move1from中to左
Move2from右to中
Move1from左to中
Move1from中to右
Move2from中to左
Move1from右to中
Move1from中to左
Move3from中to右
Move1from左to中
Move1from中to右
Move2from左to中
Move1from右to中
Move1from中to左
Move2from中to右
Move1from左to中
Move1from中to右

4.找出数组中每个数的右边第一个比它大的数
思路:利用一个单调栈解决,一次遍历,当前数<=栈底元素,则入栈,否则,当前的这个数就是第一个比栈顶元素大的,存入数组中,栈底元素出栈。继续处理
栈中存放的是数组的索引。

public static int [] findMax(int [] array) {
	  Stack<Integer> st = new Stack();
	  int len = array.length;
	  int [] result = new int[len];
	  int i = 0;
	  while(i<len) {
	    if(st.isEmpty()|| array[st.peek()]>=array[i]) {
	    	st.push(i);
	    	i++;
	    }else {
	    	result[st.pop()] = array[i];
	    }
	  }
	  while(!st.isEmpty()) {
		  result[st.pop()] = -1;
	  }
	  return result;
   }

5.找出数组中每个数的左边第一个比它小的数

 public static void search(int [] array) {
    	Stack<Integer> st = new Stack<>();
    	
    	int i = array.length-1;
    	int [] result = new int[array.length];
    	while(i>=0) {
    		if(st.isEmpty() || array[i]>=array[st.peek()]) {
    			st.push(i--);
    		}else {
    			result[st.pop()] = i;
    		}
    	}
    	while(!st.isEmpty()) {
    		result[st.pop()] = -1;
    	}
    	for(int index:result) {
    		System.out.println(index);
    	}
    }

6.牛的视野问题
一群高度不完全相同的牛从左到右站成一排,每头牛只能看见它右边的比它矮的牛的发型,若遇到一头高度大于或等于它的牛,则无法继续看到这头牛和后面的其他牛的发型。给出这些牛的高度,要求每头牛可以看到的牛的数量的和。

思路:也是使用单调栈在这里我们把问题等效于每头牛可以被看到的次数之和来求解
构建一个单调栈,栈底元素最大,从左到右依次读取牛的高度,当当前高度小于栈顶元素时,代表目前栈里的牛都可以看到这头牛,记录目前栈里的元素,然后把当前高度入栈,继续下一个操作

import java.util.Scanner;
import java.util.Stack;
 
public class Main {
 
	public static void main(String[] arg) {
		Scanner sc = new Scanner(System.in);
		int n=sc.nextInt();
		Stack<Integer> st=new Stack<Integer>();
		int sum=0;
		//首先压入初始值
		st.push(sc.nextInt());
		int now=0;
		//依次读入高度
		for(int i=1;i<n;i++) {
			now=sc.nextInt();
			//当栈不为空并且栈顶元素小于等于当前高度,栈顶出栈,
			
			while(!st.isEmpty()&&now>=st.peek()) {
				st.pop();
			}
			//栈里的牛应该都是能看到当前牛的,栈的大小即能看到当前牛的数量
			sum+=st.size();
			st.push(now);
		}
		System.out.println(sum);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值