代码随想录:单调栈

单调栈

单调栈是一种特殊的栈结构,通常用于解决一类特定的问题,如找到数组中元素的下一个更大(或更小)元素。它的核心特性是维护栈内元素的单调性,即栈内元素按照从栈底到栈顶的顺序,要么严格递增,要么严格递减

739. Daily Temperatures

在这里插入图片描述

思路:
遍历所有元素,依次压入栈! 但要保持栈是单调递减!

如何做到单调性?(保持栈底->栈顶,严格递减)
每次压入一个元素tem[i]的时候和栈顶元素比较,

  1. 如果小于等于栈顶元素直接压入;
  2. 如果大于栈顶元素,进行标记,说明找到了大于栈顶的元素,且它为第一个!
    栈顶元素出栈,继续比较tem[i]和新的栈顶元素,直到满足1.条件,压入栈。

如何标记?给谁标记?
在栈顶元素的索引位置,记录该元素的与栈顶索引距离。
给栈顶元素标记当前元素,表示栈顶元素右侧第一个大于自己的就是当前元素。

在这里插入图片描述

举例:nums= [5, 4, 3, 5], 依次压入栈中 stack=[5,4,3],

i=3 nums[4] stack.top()
5 3

假如当前i=3,当前元素 > 栈顶元素。 然后计算两者的索引距离 3 - 2 = 1.

在栈顶元素的索引位置记录下来这个值。[0, 0, 1, 0]
然后弹出栈顶的元素 stack = [5, 4] ,
继续重复判断,该元素大不大与上一个元素?如果是的话,就给上一个元素标记。
直到该元素不大于栈顶元素了,把该元素压入栈

为了理解 上面栈中写的是元素,其实代码中 栈记录的是索引

go语言实现

/**
 * @date: 2024 Jan 04
 * @time: 22:10
 * @author: Chris
 * @title: 739. Daily Temperatures
 * @link: https://leetcode.cn/problems/daily-temperatures/description/
**/
package day58

// 找右侧第一个大于该元素的值。
// [4, 1, 5, 9] 第一个大于4的值为5,第一个大于1的也为5
// 答案 [5, 5, 9, -1]
// 栈中元素是单调的,递增或递减
func dailyTemperatures(temperatures []int) []int {
    
    
	result := make([]int, len(temperatures))

	for i := range result {
    
    
		result[i] = 0
	}

	var stack []int

	for i, tem := range temperatures {
    
    
		// 非空栈,  当前元素 >  栈顶元素
		for len(stack) > 0 && tem > temperatures[stack[len(stack)-1]] {
    
    

			topIndex := stack[len(stack)-1]
			// 就找到了大于栈顶的元素!且它是第一个大于栈顶的!
			// 给栈顶元素标记一下,该元素的位置!
			result[topIndex] = i - topIndex 
			
			stack = stack[:len(stack)-1] // 已经记录完了,弹出栈
			
		}
		// 把数组中的每一个元素(的索引)都加入栈中
		stack = append(stack, i)
	}
	return result
}

496. Next Greater Element

步骤很简单,
第一步,使用单调栈找nums2的右侧第一个大的元素,并记录下来
第二步,根据nums1查找第一步的记录表,然后写入result数组!

/**
 * @date: 2024 Jan 04
 * @time: 23:35
 * @author: Chris
 * @title: 496. Next Greater Element
 * @link: https://programmercarl.com/0496.下一个更大元素I.html
**/

package day58

// nums2用单调栈找到右侧第一个最大的值,并用map记录结果
// 然后映射给nums1
func nextGreaterElement(nums1 []int, nums2 []int) []int {
    
    
	stack := []int{
    
    }

	// map = (栈顶元素 : 右侧第一个大于自己的元素)
	nextGreater := make(map[int]int)

    // 根据单调栈的步骤,记录下来,
	// 因为题目中要求是nums1中元素在nums2中元素xxxx,
	// 所以这里这里记录的是元素-元素的映射,不是索引-元素。
	for _, num := range nums2 {
    
    
		for len(stack) > 0 && num > stack[len(stack)-1] {
    
    
			top := stack[len(stack)-1]
			nextGreater[top] = num
			stack = stack[:len(stack)-1]
		}
		stack = append(stack, num)
	}

	// 栈里的元素都是不存在 右侧 大于自己的元素
	for len(stack) > 0 {
    
    
		top := stack[len(stack)-1]   // 栈顶元素
		nextGreater[top] = -1        //  置为-1
		stack = stack[:len(stack)-1] //出栈
	}

	// 记录答案
	result := make([]int, len(nums1))
	for i, num := range nums1 {
    
    
		result[i] = nextGreater[num] // 查表
	}
	return result
}

496. Next Greater Element

/**
 * @date: 2024 Jan 04
 * @time: 23:35
 * @author: Chris
 * @title: 496. Next Greater Element
 * @link: https://programmercarl.com/0496.下一个更大元素I.html
**/

package day58

// nums2用单调栈找到右侧第一个最大的值,并用map记录结果
// 然后映射给nums1
func nextGreaterElement(nums1 []int, nums2 []int) []int {
    
    
	stack := []int{
    
    }

	// map = (栈顶元素 : 右侧第一个大于自己的元素)
	nextGreater := make(map[int]int)

	// 根据单调栈的步骤,记录下来,
	// 因为题目中要求是nums1中元素在nums2中元素xxxx,
	// 所以这里这里记录的是元素-元素的映射,不是索引-元素。
	for _, num := range nums2 {
    
    
		for len(stack) > 0 && num > stack[len(stack)-1] {
    
    
			top := stack[len(stack)-1]
			nextGreater[top] = num
			stack = stack[:len(stack)-1]
		}
		stack = append(stack, num)
	}

	// 栈里的元素都是不存在 右侧 大于自己的元素
	for len(stack) > 0 {
    
    
		top := stack[len(stack)-1]   // 栈顶元素
		nextGreater[top] = -1        //  置为-1
		stack = stack[:len(stack)-1] //出栈
	}

	// 记录答案
	result := make([]int, len(nums1))
	for i, num := range nums1 {
    
    
		result[i] = nextGreater[num] // 查表
	}
	return result
}

42. Trapping Rain Water

单调栈、横向计算雨水
维护一个单调递减的栈
当遇到比栈顶元素大的,即遇到凹槽。计算雨水量。

举例:
比如数组[4, 1, 2, 3], 遍历到最后一个元素3的时候,如下图所示。
递减栈中 [4, 1]栈顶左侧的元素 相当于在数组中 左侧第一个高于栈顶的柱子
在这里插入图片描述

// 单调栈、横向计算雨水
// 维护一个单调递减的栈
// 当遇到比栈顶元素大的,即遇到凹槽。计算雨水量
// 递减栈中 [4, 2, 1]栈顶左侧的元素 相当于在数组中 左侧第一个高于栈顶的柱子
func Trap(height []int) int {
    
    
	stack := []int{
    
    }
	sum := 0

	for i := 0; i < len(height); i++ {
    
    
		for len(stack) > 0 && height[i] > height[stack[len(stack)-1]] {
    
    
			mid := stack[len(stack)-1]
			stack = stack[:len(stack)-1]
			if len(stack) > 0 {
    
    
				left_index := stack[len(stack)-1]
				h := min(height[left_index], height[i]) - height[mid]
				w := i - left_index - 1
				sum += h * w
			}
		}
		stack = append(stack, i)
	}
	return sum
}

猜你喜欢

转载自blog.csdn.net/weixin_43356770/article/details/135398242