c++刷題(6/100)最長上升子序列


題目一:區間子數組個數

給定一個元素都是正整數的數組A ,正整數 L 以及 R (L <= R)。

求連續、非空且其中最大元素滿足大於等於L 小於等於R的子數組個數。

例如 :
輸入: 
A = [2, 1, 4, 3]
L = 2
R = 3
輸出: 3
解釋: 滿足條件的子數組: [2], [2, 1], [3].

注意:

  • L, R  和 A[i] 都是整數,范圍在 [0, 10^9]
  • 數組 A 的長度范圍在[1, 50000]

思路:比較簡單,維護住子數組中的那個最大值就行了,如果這個最大值超過了上界,那么直接break,因為再擴大子數組也是徒勞

class Solution {
public:
    int numSubarrayBoundedMax(vector<int>& A, int L, int R) {
        int tempMax ;
        int count = 0 ;
        for(int i=0;i<A.size();i++){
            tempMax = -1 ;
            for(int j=i;j<A.size();j++){
                if(A[j]>tempMax){
                    tempMax = A[j] ;
                }
                if(L<=tempMax&&tempMax<=R){
                    count++ ;
                }else{
                    if(tempMax>R)break ;
                }
            }
        }
        return count ;
    }
};

 

題目二:最長上升子序列

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

示例:

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

說明:

  • 可能會有多種最長上升子序列的組合,你只需要輸出對應的長度即可。
  • 你算法的時間復雜度應該為 O(n2) 。

進階: 你能將算法的時間復雜度降低到 O(n log n) 嗎?

思路:經典題目,用動態規划可以到n^2的時間復雜度,但是動態規划我老想不出來,總覺得狀態轉移方程比較難想,多積累吧

動態規划的做法,dp數組中存,每一個以dp[i]結尾的最長上升子序列,更新的時候:

                if(nums[i]>nums[j]){
                    dp[i] = max(dp[i],dp[j]+1) ;
                }

整個代碼:

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if(nums.size()<=1){
            return nums.size() ;
        }
        int ans = 1;
        vector<int> dp(nums.size(),1) ;
        for(int i=1;i<nums.size();i++){
            for(int j=0;j<i;j++){
                if(nums[i]>nums[j]){
                    dp[i] = max(dp[i],dp[j]+1) ;
                }
            }
        }   
        for(int i=0;i<nums.size();i++){
            ans = max(ans,dp[i]) ;
        }
        return ans ;
    } 
};

題目中還說了,有nlogn的算法,網上查了一下,這篇博客說的比較好:https://blog.csdn.net/will130/article/details/50575967

具體思路是,維護一個上升序列,每次有元素進來,要么直接加后面,要么更新前面第一個比它大的數,這里簡單搬運一下

class Solution {
public://
    int lengthOfLIS(vector<int>& nums) {
        int n=nums.size();
        if(n <= 1) return n;
        //tail[i]表示長度為i的遞增序列末尾的數字
        //tail[]數組性質:tail[0]<tail[1]<...tail[n] !!!
        vector<int> tail(n);//初始化為n個值為0的元素
        //1.len為當前最長的遞增序列長度(為方便操作將len減1,從0開始,最后再加上1)
        int len=0;
        tail[0]=nums[0];
        //2.每次讀入一個新元素nums[i]
        for(int i=1;i<n;i++)
        {//遍歷nums[]中的數
            if(nums[i] < tail[0])
            {//(1)nums[i]比所有遞增序列的末尾都小,則長度為1的序列更新為這個更小的末尾。
                tail[0]=nums[i];
            }
            else if(nums[i] > tail[len])
            {//(2)nums[i]比所有序列的末尾都大,則直接將nums[i]加到后面
                tail[++len]=nums[i];
            }
            else
            {//(3)在中間,則更新那個末尾數字剛好大於等於nums[i]的那個序列,nums[i]替換其末尾數字
                tail[biSearch(tail, 0, len, nums[i])]=nums[i];
            }
        }
        return len+1;
    }
    int biSearch(vector<int>& tail, int low, int high, int target)
    {//由於tail數組是有序的,故可二分查找其中元素
        while(low <= high)//不能是low<high
        {//當low=high時還要進行一次循環!!!
         //此時mid=low=high.若tail[mid]<target,則low=mid+1.而不是直接返回low!!!
            int mid = low + (high-low)/2;
            if(tail[mid] == target) return mid;
            else if(tail[mid] > target)
            {
                high=mid-1;
            }
            else
            {
                low=mid+1;
            }
        }
        return low;
    }
};

 題目三:乘積最大子序列

給定一個整數數組 nums ,找出一個序列中乘積最大的連續子序列(該序列至少包含一個數)。

示例 1:

輸入: [2,3,-2,4]
輸出: 6
解釋: 子數組 [2,3] 有最大乘積 6。

示例 2:

輸入: [-2,0,-1]
輸出: 0
解釋: 結果不能為 2, 因為 [-2,-1] 不是子數組。
思路:這個題確切的來說應該是子數組,跟最長上升子序列就動歸而言有點像,由於是子數組不是子序列,所以可以o(n)完成(子序列需要遍歷狀態i之前的所有狀態,而子數組是連續的,子需要記錄上一個狀態就行)
但是由於是乘法,所以有符號的問題,上一個狀態是負的,乘上一個負數反而可能變的很大,所以這道題的關鍵是維護兩個狀態,當前最大和當前最小,每次計算都更新這兩個狀態,不過只有最大值和ans比較
class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int len = nums.size() ;
        if(len==0){
            return 0 ;
        }
        int tempMax = nums[0] ;
        int tempMin = nums[0] ;
        int ans = nums[0] ;
        int lastMax = nums[0];
        for(int i=1;i<len;i++){
            tempMax = max(max(lastMax*nums[i],nums[i]),tempMin*nums[i]) ;
            tempMin = min(min(lastMax*nums[i],nums[i]),tempMin*nums[i]) ;
            lastMax = tempMax ;
            if(tempMax>ans){
                ans = tempMax ;
            }
        }
        return ans ;
    }
};

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM