サブシーケンスを増やすleetcode 300最長は、動的プログラミングの最も長いシーケンスを上昇します

サブシーケンスを増やすleetcode 300最長は最も長いシーケンスを上昇します

leetcode 2020年3月には、日々の質問パンチは、
Huawei社は、この質問をすると言われています

質問:
所定の整数配列障害、請求最長見出さ立ち上がりシーケンスの長さ。
例:
入力:[10,9,2,5,3,7,101,18]
出力:4の
説明:最長シーケンスが増加する[2,3,7,101]、その長さは4です。
注:最長上昇シーケンスの様々な組み合わせがあるかもしれない、あなただけの出力に対応する長さを必要とします。あなたのアルゴリズムの時間計算量はO(N2)でなければなりません。
高度:あなたはOにアルゴリズムの時間の複雑さを軽減(N Nログ)行うことができますか?

オリジナルタイトルリンクします。https://leetcode-cn.com/problems/longest-increasing-subsequence

知識: ダイナミックプログラミング

問題の固定ルールを解決するための適しました:

  1. 最適なサブ構造を通報します。
  2. 後効果、多指なし最適解を見つけます。

ゲージの問題解決のアイデアを移動します:

  1. サブ分割問題
  2. 状態を判断し
  3. 状態遷移方程式を決定します
  4. 開始条件や境界条件の決定

再帰的ルールの変更、再帰関数はn次元配列に、n個のパラメータを含むことがあり、格納された値は、再帰関数の戻り値に等しいです。

思考: Pythonの動的プログラミング、子供は、[I]は、i番目の要素のシーケンスNUMSを表し増加サブシーケンスの長さの端部で最も長いです。サブ問題:i番目の要素を解決する前にシーケンスの最長サブ立ち上がり長さです。ステータス:子[i]を。状態遷移方程式:以前のすべての要素NUMS [j]を介して各サブ質問、もしNUMS [J] <NUMS [I ]は、 子供[I]は、内のすべての子[J] +1の最大値に等しいです。境界条件:1の開始値。時間計算:計算状態、必要のO(N)時間前の状態を横断するときに、合計時間はO(N ^ 2)であるので、O(N ^ 2)、動的プログラミング状態の数は、nです。空間複雑:O(N)、なぜなら長さnの配列のさらなる使用。

詳細:

  1. NUMSを除外することは空であります
  2. best_i 1に設定された値を開始し、0にすることはできません

コード:

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 动态规划 O(N^2)
        child=[] # child[i]表示以nums里第i个元素结尾的序列里最长上升子序列的长度
        if nums == []:
            return 0
        child.append(1)
        for i in range(1,len(nums)):
            best_i=1
            for j in range(0,i):
                if nums[i]>nums[j]:
                    tem=child[j]+1
                    if tem>best_i:
                        best_i=tem
            child.append(best_i)
        return max(child)

方法2:貪欲+バイナリ検索:参照してください公式の説明を貪欲アルゴリズムの核となるアイデアは、局所最適を見つけることです。時間複雑性O(NlogN)。この問題は、出力の長さのみであり、この方法の代わりに使用することができ、そのような配列が出力される、それはそうすることはできません。

class Solution(object):
    def lengthOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        # 贪心+二分查找 O(NlogN)
        if nums == []:
            return 0
        tail=[nums[0]] # 存长度最长上升子序列的最后一个元素值
        len=1 # 最长上升子序列的长度
        
        for num in nums[1:]:
            if num>tail[len-1]:
                tail.append(num)
                len+=1
            else:
                # 二分查找比num大的最小的元素及位置
                l=0
                r=len-1
                while l<r:
                    mid = int((l+r)/2)
                    if tail[mid] == num:
                        l=mid
                        break
                    if tail[mid]<num:
                        l=mid+1
                        continue
                    elif tail[mid]>num:
                        r=mid
                        continue
                tail[l]=num
            
        return len

PS。第2の方法は一般的ではないが、第1の焦点が理解されます。
このブログは、オリジナル作品である指針を歓迎し、再現し、ソースを示し、この記事へのリンクを添付し、あなたに感謝して下さい

公開された20元の記事 ウォンの賞賛1 ビュー206

おすすめ

転載: blog.csdn.net/weixin_43973433/article/details/104856044