单调栈解题

这篇文章详细介绍了单调栈的概念及其在算法中的应用,包括寻找下一个更大元素、索引间距处理和环形数组场景的解决方案。通过实例演示,展示了如何利用单调栈简化问题并提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单调栈解题模板

单调栈实际上就是栈,只是利用了一些巧妙的逻辑,使得每次新元素入栈后,栈内的元素都保持有序(单调递增或单调递减)

本文就通过几道算法题来看看单调栈模板的使用。

一.单调栈模板

给一个数组,返回一个等长的数组,对应索引存储着下一个更大元素,如果没有更大的元素,就存 -1。

函数签名如下:

vector<int> nextGreaterElement(vector<int>& nums);

比如说,输入一个数组nums = [2,1,2,4,3],你返回数组[4,2,4,-1,-1]。

解释:第一个 2 后面比 2 大的数是 4; 1 后面比 1 大的数是 2;第二个 2 后面比 2 大的数是 4; 4 后面没有比 4 大的数,填 -1;3 后面没有比 3 大的数,填 -1。

暴力解很容易想到:

public int[] nextGreaterElement(int[]nums){
	int n = nums.length;
	int[] nums1 = new int[n];
	int index=0;
	for(int i=0;i<n;i++){
		for(int j=i+1;j<n;j++){
			if(nums[j]>nums[i])
				nums1[index++] =nums[j];
				break;
			nums1[index++]=-1; 
		}
	}
}

这个问题可以这样抽象思考:把数组的元素想象成并列站立的人,元素大小想象成人的身高。这些人面对你站成一列,如何求元素「2」的 Next Greater Number 呢?很简单,如果能够看到元素「2」,那么他后面可见的第一个人就是「2」的 Next Greater Number,因为比「2」小的元素身高不够,都被「2」挡住了,第一个露出来的就是答案。

在这里插入图片描述

public int[] nextGreaterElement(int[]nums){
	int nums3 = new int[nums.length];
	Stack<Integer>st =new Stack<Integer>();
	for(int i=nums.length-1;i>=0;i--){
		//判断个子高矮
		while(!st.isEmpty()&&st.peek()<=nums[i])
			//矮的就去掉
			st.pop();
		//这时候还能看见的第一个,说明就是最近的比本数大的。
		nums3[i] =st.isEmpty()?-1:st.peek();
		st.push(nums[i]);
	}
	return nums3;
}

二.问题变形

这次相当于是数组里存放的不是数本身,而是对应的索引间距。

在这里插入图片描述

public int[] dailyTemp(int []T){
	int n = T.length;
	int []nums = new int[n];
	//单调栈用来存放高的元素
	Stack<Integer> st = new Stack<>();
	//从后往前放入
	for(int i =n-1;i>=0;i--){
		while(!st.isEmpty()&&T[st.peek()]<=T[i])
			//温度低的都抛掉
			st.pop();
		nums[i] = st.isEmpty()?0:(st.peek()-i);
		st.push(i);
	}
	return nums;
}

三. 如何处理环形数组

这里主要得熟悉如何构造环形数组,一般通过取模操作:

int[] arr = {1,2,3,4,5};
int n = arr.length, index = 0;
while (true) {
    print(arr[index % n]);
    index++;
}

常用套路是将数组长度翻倍,但这里可以不用额外构造,使用循环数组实现:

 public int[] nextGreaterElements(int[] nums) {
        int n= nums.length;
        int [] nums1 = new int [n];
        Stack<Integer>st = new Stack<>();
        for(int i=2*n-1;i>=0;i--){
            while(!st.isEmpty()&& st.peek()<=nums[i%n])
                st.pop();
            nums1[i%n] = st.isEmpty()?-1:st.peek();
            st.push(nums[i%n]);
        }
        return nums1;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值