LeetCode--300. 最長遞增子序列

題目:給定一個無序的整數數組,找到其中最長上升子序列的長度。

示例:

輸入: [10,9,2,5,3,7,101,18]
輸出: 4 
解釋: 最長的上升子序列是 [2,3,7,101],它的長度是 4.

解析思路1:

創建一個臨時數組new_arr(用於存放一組最長上升子列),首先將nums[0]插入其中,而後遍歷nums[1:]

  • 若是遍歷到的元素val <= new_arr[0],咱們更新new_arr[0]=val(也就是遍歷到的元素比最長上升子序列中的最小元素小,咱們經過貪心的策略,固然是越小越好,因此替換以前元素)
  • 若是new_arr[0] < val <= new_arr[-1],咱們經過二分搜索法找到第一個>=val的元素位置,而後用val替換掉它(和上面的作法相同)
  • 若是new_arr[-1] < val,咱們更新new_arr.append(val)(也就是新加入的元素比最長上升子序列中的最後一個元素大,那麼必然構成解)

---------------------

做者:coordinate_blog

來源:CSDN

原文:https://blog.csdn.net/qq_17550379/article/details/82871892

實現代碼:

class Solution:
    def lengthOfLIS(self, nums) -> int:
        length = len(nums)
        new_arr = [] # 最長上升子列數組
        if length == 0:  # 原數組爲空
            return 0
        elif length == 1:  # 原數組只有一個元素
            return 1
        else:
            new_arr.append(nums[0])
            for i in range(1, length):
                if nums[i] <= new_arr[0]:  # 若是遍歷的元素比子列中最小值還小或相等,則替換
                    new_arr[0] = nums[i]
                elif (new_arr[0] < nums[i]) and (nums[i] <= new_arr[-1]):  # 若是遍歷的元素值大小在子列中間,則查找到第一個大於或等於此元素的子列元素,進行替換;new_arr目前是已經有序的,因此能夠用二分查找提升檢索效率
                    low,high = 0,len(new_arr)-1
                    while low <= high:
                        mid = (low+high)//2
                        if new_arr[mid] >= nums[i]:
                            new_arr[mid] = nums[i]
                            break
                        else:
                            low = mid + 1
                elif nums[i] > new_arr[-1]:  # 若是遍歷的元素比子列最大元素還大,則追加到子列尾部
                    new_arr.append(nums[i])
            return len(new_arr)

執行用時 : 52 ms, 在Longest Increasing Subsequence的Python3提交中擊敗了96.97% 的用戶 內存消耗 : 13.1 MB, 在Longest Increasing Subsequence的Python3提交中擊敗了96.54% 的用戶java

解題思路2:

依次求出以初始序列中各個元素爲尾元素的最長遞增子序列的長度,而後經過對其大小的判斷,不斷更新最長遞增子序列的最大長度,每次更新最大長度的時候將當前遞增子序列尾元素的前向元素添加進來,最後添加最長遞增子序列的尾元素,由此,便可求出最長遞增子序列長度,也可求出最長遞增子序列(不惟一)。

  • 如對於初始序列[10,9,2,5,3,7,101,18],要依次計算出以10,9,2,5,3,7,101,18做爲尾元素的最長遞增序列的長度,而後去進行大小判斷和更新。
  • 以10結尾的最長遞增子序列:[10]
  • 以9結尾的最長遞增子序列:[9]
  • 以2結尾的最長遞增子序列:[2]
  • 以5結尾的最長遞增子序列:[2,5]
  • 以3結尾的最長遞增子序列:[2,3]
  • 以7結尾的最長遞增子序列:[2,3,7]或[2,5,7]
  • 以101結尾的最長遞增子序列:[2,3,7,101]或[2,5,7,101]
  • 以18結尾的最長遞增子序列:[2,3,7,18]或[2,5,7,18] 每日後計算一個就將其最長遞增子序列長度與前一個比較

實現代碼:

import java.util.ArrayList;
import java.util.Scanner;
import java.util.List;

public class SubSequence {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] s = new int[n];
        for(int i=0; i<n; i++){
            s[i] = sc.nextInt();
        }
        int max_len = getSubSequenceLen(n, s);
        System.out.println("最長遞增子序列長度:"+max_len);
    }

    public static int getSubSequenceLen(int n, int[] s){
        int[] liss = new int[n];  // 以各元素結尾的最長遞增子序列長度
        int[] pre = new int[n];  // 以各元素結尾的最長遞增子序列的當前元素的前向元素
        List<Integer> maxSubSequence = new ArrayList<Integer>();
        int max_len = 1;  // 最長遞增子序列長度
        int end_index = 0;  // 長遞增子序列尾元素地址
        // 初始化
        for(int i=0; i<n; i++){
            liss[i] = 1;
            pre[i] = s[i];
        }
        for(int p=1; p<n; p++){
            for(int q=0; q<p; q++){
                if(s[q]<s[p] && liss[q]+1>liss[p]){
                    liss[p] = liss[q]+1;
                    pre[p] = s[q];
                    end_index = p;
                }
            }
            if(max_len<liss[p]){
                max_len = liss[p];
                maxSubSequence.add(pre[p]);  // 將最長遞增子序列中當前元素的前向元素添加進來
            }
        }
        maxSubSequence.add(s[end_index]);  // 將最長遞增子序列的尾元素添加進來
        System.out.println("最長遞增子序列:"+maxSubSequence);
        return max_len;
    }
}

思路來源:https://blog.csdn.net/qq_34369618/article/details/72852740

代碼僅供參考

相關文章
相關標籤/搜索