leetcode-300 最长上升子序列
生活随笔
收集整理的這篇文章主要介紹了
leetcode-300 最长上升子序列
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目描述:
給定一個無序的整數數組,找到其中最長上升子序列的長度。
示例:
輸入: [10,9,2,5,3,7,101,18]
輸出: 4
解釋: 最長的上升子序列是 [2,3,7,101],它的長度是 4。
說明:
可能會有多種最長上升子序列的組合,你只需要輸出對應的長度即可。
你算法的時間復雜度應該為 O(n^2) 。
方法一(暴力法):
即針對數組的每一個元素都有兩種選擇,取或者不取(取的前提是當前元素大于上一個元素,則上升子序列++),最終遞歸到最后的一個元素,將結果返回。
實現如下:
int lengthOfLIS(vector<int>& nums) {return get_lengthOfLIS(nums, -1, 0);
}
int get_lengthOfLIS(vector<int> &num, int prev, int curr) {if(curr == num.size()) {return 0;}int taken = 0;if(num[curr] > prev) {taken = get_lengthOfLIS(num, num[curr], curr+1);}int notaken = get_lengthOfLIS(num, prev, curr+1);return max(taken, notaken);
}
但是因為暴力解法的時間復雜度較高,針對每個元素都有兩種選擇,時間復雜度為O(2^n)
方法二(DP動態規劃):
- 狀態的定義
dp[i] 代表以當前元素 nums[i]結尾(最長上升子序列包括nums[i])的最長上升子序列的大小 - 狀態轉移方程
dp[i] = (nums[i] > nums[j]) ? max{dp[0]…dp[j]} + 1 ,1; (j>=0 && j < i)
以上方程的意思是,找到所有nums[i]左側比nums[i]小的元素的個數,在其基礎上+1
實現如下:
int lengthOfLIS(vector<int>& nums) {if(nums.size() <= 1) return nums.size();vector<int> dp(nums.size(),0);int res = 1,i = 1, j = 0;dp[0] = 1;for(i = 1;i < nums.size(); ++i) {dp[i] = 1;for (j = 0;j < i; ++j) {if(nums[i] > nums[j] && dp[i] < dp[j] + 1) { //找到nums[i]左邊比nums[i]小的元素,取它的dp[j] + 1給到dp[i]dp[i] = dp[j]+1;}}if(res < dp[i]) { //res取最大即可res = dp[i];}}return res;
}
以上方法的時間復雜度為O(n^2),j的遍歷的層數和i的個數基本一致
方法三(遞增棧 + 二分):
維護一個持續遞增的棧,元素添加進來有兩種規則:
- 當要添加的元素大于棧頂元素,則壓棧
- 當要添加的元素小于棧頂元素,那么在棧中找到該元素的插入位置,將其替換該位置的元素
只有當滿足第一中情況的時候棧的大小才會增加,否則棧的大小是固定的,優化的辦法是使用二分法查找待插入的位置
實現如下:
int lengthOfLIS(vector<int>& nums) {if (nums.size() == 0) return 0;vector<int> stack;//使用vector代替棧stack.push_back(nums[0]);for (int i = 1;i < nums.size(); ++i) {if (nums[i] > stack.back()) {stack.push_back(nums[i]);} else {int pos = binary_search(stack,nums[i]);stack[pos] = nums[i];}}return stack.size();
}//二分查找,返回待插入元素的下標
int binary_search(vector<int> &stack,int target) {int index = -1;int begin = 0;int end = stack.size() - 1;while (index == -1) {int mid = (begin + end) / 2;if (target == stack[mid]) {index = mid;} else if (target < stack[mid]) {if (mid == 0 || target > stack[mid - 1]) {index = mid;}end = mid - 1;} else {if (mid == stack.size() - 1 || target < stack[mid + 1] ) {index = mid + 1;}begin = mid + 1;}}return index;
}
時間復雜度為O(N*logn),遍歷n次,每次二分查找的時間復雜度是logn
總結
以上是生活随笔為你收集整理的leetcode-300 最长上升子序列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 备孕多久需要查输卵管造影
- 下一篇: 设计模式 之美 --- 初篇