【LeetCode】503、次の大きな要素 II。難易度:中程度。一般的に使用される単調スタック手法「次に大きい/小さい問題」についての深い理解

0. トピック

循環配列 nums (nums[nums.length - 1] の次の要素は nums[0]) の場合、nums の各要素の次に大きい要素を返します。

数値 x の次に大きい要素は、配列の走査順序でこの数値の後の最初の大きい数値です。つまり、次に大きい数値を検索するにはループする必要があります。存在しない場合は、-1 を出力します。

例 1:

输入: nums = [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数; 
第二个 1 的下一个最大的数需要循环搜索,结果也是 2

例 2:

输入: nums = [1,2,3,4,3]
输出: [2,3,4,-1,4]

1. 私の解決策: 単調スタック

1.1 分析

この質問は、[LeetCode] 739、毎日の温度と同じです難易度:中程度。さまざまな解決策があり、勉強する価値があります非常に似ているため、最初に 739 の質問を読むことをお勧めします

この問題が739問よりも難しい点は次の2点です。

  1. 配列は端から端までループする必要があるため、配列ループのトラバーサルを実装する方法を見つけてください。
  2. 特定の数値に対してそれより大きい数値がない場合は -1 が返されますが、実際には配列内の最大値の位置をすべて検索するためです (最大値は 1 より大きくなります)。

これらの問題には両方とも賢明な解決策があります。

  1. 配列を直接ループするのは非常に面倒です。別の考え方としては、配列をコピーして、元の配列の 2 倍の長さの新しい配列をアセンブルすることです。新しい配列を 1 回走査することは、元の配列を 2 回ループすることと同じではないでしょうか?
  2. 戻り値リストを -1 で初期化します。値の大きい位置は新しい値で上書きされ、最大値の位置は処理されず、-1 が保持されます。

このようにして両方の困難は解決され、次にどのような方法を使用するかを検討します。結論は次のとおりです。

「現在の値より大きい/小さい最も近い値を見つける」という問題については、単調スタックを使用して解決できます。

この種の問題に単調スタックが使用できるのはなぜでしょうか? 詳しい説明は「モノトニックスタックを使う理由」をご覧ください。「単調なスタック」を理解するための「単純な解決策」の観点から

1.2 単調スタックの考え方に従って直接書かれたプライマリコード

単調スタックの考え方に従って直接書かれたコードは次のとおりです。

class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        # 实现循环的一种方法:将数组复制一遍;取前 nums 个结果即可
        new_nums=nums*2
        length=len(new_nums)
        ans=[-1]*length    # 为了避免单独判断最大的元素的位置,用-1初始化数组

        stack=[]
        for i in range(length):
            if not stack:
                stack.append([i,new_nums[i]])
            else:
                if new_nums[i]>stack[-1][1]:
                    while stack and new_nums[i]>stack[-1][1]:
                        ans[stack[-1][0]]=new_nums[i]
                        stack.pop()
                    stack.append([i,new_nums[i]])
                else:
                    stack.append([i,new_nums[i]])
        return ans[:length//2]

1.3 簡略化されたコード

明らかに、1.2 のコードは簡略化できます。簡略化されたコードは次のとおりです。

class Solution:
    def nextGreaterElements(self, nums: List[int]) -> List[int]:
        # 实现循环的一种方法:将数组复制一遍;取前 nums 个结果即可
        new_nums=nums*2
        length=len(new_nums)
        ans=[-1]*length    # 为了避免单独判断最大的元素的位置,用-1初始化数组

        stack=[]
        for i in range(length):
            if not stack:
                stack.append([i,new_nums[i]])
            else:
                while stack and new_nums[i]>stack[-1][1]:
                    ans[stack[-1][0]]=new_nums[i]
                    stack.pop()
                stack.append([i,new_nums[i]])
        return ans[:length//2]

おすすめ

転載: blog.csdn.net/qq_43799400/article/details/131730916