給定一個無序的整數數組,找到其中最長上升子序列的長度。
輸入: [10,9,2,5,3,7,101,18]
輸出: 4
解釋: 最長的上升子序列是 [2,3,7,101],它的長度是 4。
1,動態規劃,(本題動態規劃是比較好理解的,但顯然效率比較低)
int lengthOfLIS(vector<int>& nums) {
int len=nums.size();
int maxlen=0;
//if(len==0) return 0;
//if(len==1) return 1;
vector<int> dp(len,1);
for(int i=0;i<len;i++){
for(int j=0;j<i;j++){
if(nums[j]<nums[i])
dp[i]=max(dp[i],dp[j]+1);
}
maxlen=max(maxlen,dp[i]);
}
return maxlen;
}
dp[i] 表示以 nums[i] 這個數結尾的最長遞增子序列的長度。
當時作此題時,dp數組習慣初始化爲0.,結果一直不對,比結果少一,。後來參考了,才知道**dp需要初始化爲1,**這樣進行理解,不管整體結果,本身當前值就是一個最小子序列,長度爲1。
時間複雜度 O(N^2)。
2,二分查找(真的很難想到,也不好理解)(在安利一次啊,不明白流程如何操作循環的,去debug一下l)
紙牌方法解釋此題
每次處理一張撲克牌不是要找一個合適的牌堆頂來放嗎,牌堆頂的牌不是有序嗎,這就能用到二分查找了:用二分查找來搜索當前牌應放置的位置。
int lengthOfLIS(vector<int>& nums) {
int len=nums.size();
vector<int> res(len);
int maxlen=0;
//for(int num : nums){
//int num=nums[i];
//按照左側邊界進行二分查找
for(int i=0;i<len;i++){
//要處理的撲克牌
int left=0,right=maxlen;
while(left<right){
int mid=(left+right)/2;
if(res[mid]<nums[i])
left=mid+1;
else
right=mid;
}
/*********************************/
// 沒找到合適的牌堆,新建一堆
if(maxlen==left)
maxlen++;
// 把這張牌放到牌堆頂
res[left]=nums[i];
}
return maxlen;
}
int main() {
vector<int> nums{ 6,3,5,10,11,2,9,14,13,7,4,8,12 };
lengthOfLIS(nums);
return 0;
}