栈(2)| 豆包MarsCode AI刷题

110 阅读7分钟

131 价格优惠计算问题

问题描述

小F在“双十一”期间购买了N件商品。每件商品有一个价格p[i],小F可以获得的优惠取决于该商品之前的一件商品。如果某一件商品的价格p[i]大于等于前面的某个商品p[j],则小F可以享受该商品]p[j]的价格作为优惠,前提是p[j]是离p[i]最近的且满足条件的商品。

例如,给定价格数组p = [9, 4, 5, 2, 4],其中p[3] = 2之前没有商品的价格小于等于p[3],因此没有优惠;而p[2] = 5可以享受最近的商品p[1] = 4的价格作为优惠。因此,任务是计算小F能获得的总优惠。

解题思路

找到某个商品p[i]之前第一个小于等于p[i]价格的商品p[j]。

  1. 初始化

    • 创建一个空栈 stack 用于存储商品价格。
    • 初始化 discount 变量为 0,用于累计总优惠。
  2. 遍历价格数组

    • 对于每个价格 price,检查栈顶元素是否大于当前价格。
    • 如果栈顶元素大于当前价格,则弹出栈顶元素,直到栈为空或栈顶元素小于等于当前价格。
    • 如果栈不为空,说明当前价格可以享受栈顶元素的价格作为优惠,因此将栈顶元素的值加到 discount 中。
    • 将当前价格 price 压入栈中。
  3. 返回结果

    • 遍历结束后,返回 discount 作为总优惠。
def solution(N: int, p: list) -> int:
    stack = []
    discount = 0

    for price in p:
        while stack and stack[-1] > price:
            stack.pop()
        if stack:
            discount += stack[-1]    
        stack.append(price)
    return discount

122 最大乘积问题

问题描述

小R最近遇到了一个数组问题。他有一个包含 N 个元素的数组,记作a1​,a2​,...,aN​。为了分析这个数组的特性,小R定义了两个函数 L(i) 和 R(i),并希望通过这两个函数来找到一些有趣的结论。

L(i) 是满足以下条件的最大的 j 值:

  • j<i
  • a[j]>a[i]
  • 如果找不到这样的 j,那么 L(i)=0;如果有多个满足条件的 j,选择离 i 最近的那个。

R(i) 是满足以下条件的最小的 k 值:

  • k>i
  • a[k]>a[i]
  • 如果找不到这样的 k,那么 R(i)=0;如果有多个满足条件的 k,选择离 i 最近的那个。

最终,小R定义MAX(i)=L(i)∗R(i),他想知道在 1≤i≤N 的范围内,MAX(i) 的最大值是多少。

解题思路

需要找到数组中每个元素的 L(i) 和 R(i),然后计算 MAX(i) = L(i) * R(i),并找出这个值的最大值。可以使用栈维护两个递减的序列,从而快速找到每个元素的 L(i) 和 R(i)

  1. 初始化 L 和 R 数组

    • L 和 R 列表用于存储每个元素的 L(i) 和 R(i) 值。
  2. 计算 L(i)

    • 从左到右遍历数组,使用栈来维护递减的序列。
    • 对于每个元素 a[i],如果栈不为空且栈顶元素小于等于 a[i],则弹出栈顶元素,直到找到一个大于 a[i] 的元素或栈为空。
    • 如果栈不为空,L(i) 为栈顶元素的索引+1,否则默认为0。
    • 当前元素入栈。
  3. 计算 R(i)

    • 从右到左遍历数组,使用栈来维护递减的序列。
    • 对于每个元素 a[i],如果栈不为空且栈顶元素小于等于 a[i],则弹出栈顶元素,直到找到一个大于 a[i] 的元素或栈为空。
    • 如果栈不为空,R(i) 为栈顶元素的索引+1,否则默认为0。
    • 当前元素入栈。
  4. 计算 MAX(i) 并找到最大值

    • 遍历列表,计算每个 i 的 MAX(i) = L(i) * R(i)
    • 记录并返回 MAX(i) 的最大值。
def solution(n, array):

    L = [0]*n
    R = [0]*n
    
    # 使用栈来计算 L(i)
    stack = []
    for i in range(n):
        # 当栈不为空且栈顶元素小于等于当前元素时,弹出栈顶元素
        while stack and array[stack[-1]] <= array[i]:
            stack.pop()
         # 如果栈不为空,L(i) 为栈顶元素的索引+1
        if stack:
            L[i] = stack[-1] + 1
        stack.append(i)
    # 清空栈,用于计算 R(i)
    stack = []
    #从右向左遍历数组
    for i in range(n-1,-1,-1):
        # 当栈不为空且栈顶元素小于等于当前元素时,弹出栈顶元素
        while stack and array[stack[-1]] <= array[i]:
            stack.pop()
        # 如果栈不为空,R(i) 为栈顶元素的索引+1
        if stack:
            R[i] = stack[-1] + 1
        stack.append(i)
    # 计算 MAX(i) 并找到最大值
    result = 0
    for i in range(n):
        result = max(result,L[i]*R[i])
    return result

139 套碗游戏的取碗顺序问题

问题描述

小F正在玩一个套碗的游戏,每个碗都有一个编号,从1到n,它们从大到小被套在一根木棍上。小F只能从木棍上取最上面的碗,每次只能取一个。现在你需要判断给定的取碗顺序是否可行。如果可行,那么返回1,否则返回0。

例如,对于2个碗,取碗的顺序可以是 2 1 或 1 2,这两种顺序都是合法的。而对于3个碗,给定顺序 3 1 2 不可能通过合法操作实现,因此该顺序不可行。

解题思路

没看懂题目,根据样例来看,是将1-n从小到大按顺序进栈,判断出栈顺序是否合法。

  1. 初始化

    • 创建一个空栈 stack,用于模拟碗的进栈和出栈操作。
    • 初始化一个指针 current,指向当前需要进栈的碗的编号,初始值为 1
  2. 遍历出栈顺序

    • 遍历给定的出栈顺序 a 中的每一个元素 num
  3. 栈操作

    • 对于每一个 num,检查栈顶元素是否等于 num

      • 如果栈顶元素等于 num,则弹出栈顶元素。
      • 如果栈顶元素不等于 num,则将当前编号的碗(即 current)进栈,并将 current 加 1
      • 如果 current 超过了总数 M,则说明无法继续进栈,出栈顺序不合法,返回 0
  4. 返回结果

    • 如果所有碗都正确进栈并出栈,且 current 等于 M + 1,则返回 1,表示出栈顺序合法。
    • 否则返回 0,表示出栈顺序不合法。
def solution(M: int, a: list) -> int:
    stack = []  # 初始化一个空栈,用于模拟碗的进栈和出栈操作
    current = 1  # 初始化一个指针,指向当前需要进栈的碗的编号
    
    for num in a:  # 遍历给定的出栈顺序
        while not stack or stack[-1] != num:  # 如果栈为空或栈顶元素不等于当前出栈顺序的元素
            if current > M:  # 如果当前需要进栈的碗的编号超过了总数 M
                return 0  # 返回 0,表示出栈顺序不合法
            stack.append(current)  # 将当前编号的碗进栈
            current += 1  # 指针后移,指向下一个需要进栈的碗
        stack.pop()  # 如果栈顶元素等于当前出栈顺序的元素,则弹出栈顶元素
    
    return 1 if current == M + 1 else 0  # 如果所有碗都正确进栈并出栈,返回 1,否则返回 0

140 套碗游戏的取碗顺序问题(二)

问题描述

小F正在玩一个套碗的游戏,每个碗都有一个编号,从1到n,它们从大到小被套在一根木棍上。小F只能从木棍上取最上面的碗,每次只能取一个。现在你需要计算总共有多少种取碗的顺序。

例如,对于2个碗,取碗的顺序可以是 2 1 或 1 2,这两种顺序都是合法的。而对于3个碗,给定顺序 3 1 2 不可能通过合法操作实现,因此该顺序不可行。

解题思路

同上题,将1-n从小到大按顺序进栈,计算有多少种合法的出栈顺序。

可以使用卡特兰数(Catalan Number)来计算。卡特兰数是一个在组合数学中常见的数列,用于解决许多组合问题,包括栈的出栈顺序问题。

  1. 卡特兰数

    • 卡特兰数 C(n) 表示 n 个元素的出栈顺序的数量。
    • 卡特兰数的递推公式为:
      [C(n)=i=0n1C(i)C(n1i)][ C(n) = \sum_{i=0}^{n-1} C(i) \cdot C(n-1-i) ]
    • 初始条件为 C(0) = 1
  2. 计算卡特兰数

    • 这是一个递推的过程,可以使用动态规划来计算卡特兰数。
    • 创建一个数组 catalan,其中 catalan[i] 表示 i 个元素的出栈顺序的数量。
    • 根据递推公式计算每个 catalan[i]
def solution(n):
    # 初始化卡特兰数数组
    catalan = [0] * (n + 1)
    
    # 初始条件
    catalan[0] = 1
    
    # 计算卡特兰数
    for i in range(1, n + 1):
        for j in range(i):
            catalan[i] += catalan[j] * catalan[i - 1 - j]
    
    return catalan[n]