Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2a1038d

Browse files
dp: longest increase sbu seq
1 parent 4d0d2fb commit 2a1038d

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* @lc app=leetcode.cn id=300 lang=cpp
3+
*
4+
* [300] 最长递增子序列
5+
*
6+
* https://leetcode.cn/problems/longest-increasing-subsequence/description/
7+
*
8+
* algorithms
9+
* Medium (54.72%)
10+
* Likes: 3198
11+
* Dislikes: 0
12+
* Total Accepted: 732.1K
13+
* Total Submissions: 1.3M
14+
* Testcase Example: '[10,9,2,5,3,7,101,18]'
15+
*
16+
* 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
17+
*
18+
* 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7]
19+
* 是数组 [0,3,1,6,2,2,7] 的子序列。
20+
*
21+
*
22+
* 示例 1:
23+
*
24+
*
25+
* 输入:nums = [10,9,2,5,3,7,101,18]
26+
* 输出:4
27+
* 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
28+
*
29+
*
30+
* 示例 2:
31+
*
32+
*
33+
* 输入:nums = [0,1,0,3,2,3]
34+
* 输出:4
35+
*
36+
*
37+
* 示例 3:
38+
*
39+
*
40+
* 输入:nums = [7,7,7,7,7,7,7]
41+
* 输出:1
42+
*
43+
*
44+
*
45+
*
46+
* 提示:
47+
*
48+
*
49+
* 1 <= nums.length <= 2500
50+
* -10^4 <= nums[i] <= 10^4
51+
*
52+
*
53+
*
54+
*
55+
* 进阶:
56+
*
57+
*
58+
* 你能将算法的时间复杂度降低到 O(n log(n)) 吗?
59+
*
60+
*
61+
*/
62+
63+
#include <vector>
64+
using namespace std;
65+
66+
// @lc code=start
67+
class Solution {
68+
public:
69+
int lengthOfLIS(vector<int> &nums) { return nLogN(nums); }
70+
71+
private:
72+
// dp题目,过程中维护最长子序列,人工分析规律来找状态转移方程
73+
// [9,2,5,3,10,12,6,7,13],
74+
// 遍历到3时,可以跟2组成23,遍历到10时,有2310和2510两种可能,12则可以跟10连起来
75+
// 遍历到6,有256和236两种,7也可以跟6的连起来,遍历到13的时候,可以跟12也可以跟7连起来
76+
// 因此,可以看到每个元素都要跟之前的每个元素比较一下,从而得到包含该元素的最长序列
77+
// 从而可定义dp[i]是包含该元素的最长子序列,dp[i]=max(dp[j]...)+1,
78+
// 其中0<=j<i且nums[j]<nums[i] 所以结果就是max(dp[i]...),
79+
// 遍历每个元素时往回遍历所有元素,复杂度是O(n^2)
80+
int n2(vector<int> &nums) {
81+
int n = nums.size();
82+
if (n <= 1) {
83+
return n;
84+
}
85+
int ret = 1;
86+
vector<int> dp(n, 1);
87+
for (int i = 1; i < n; i++) {
88+
for (int j = i - 1; j >= 0; j--) {
89+
dp[i] = nums[i] > nums[j] ? max(dp[i], dp[j] + 1) : dp[i];
90+
}
91+
ret = max(ret, dp[i]);
92+
}
93+
return ret;
94+
}
95+
96+
// 上面的例子里面5和3其实可以直接丢弃5了,因为同等长度下,3更小,未来有更多可能,最小末尾数是3。
97+
// 同理,遍历到7时,长度为4的子序列其实就是2367了,最小末尾数是7,10和12都可以丢弃了,后面不会再用到。
98+
// 而遍历每个元素的时候,当前元素如果比长度为1的最小末尾数大,那可以组成长度为2的子序列,
99+
// 再依次比较234...n的子序列,n为当前最长递增长度,就可以知道当前可以组成的最长子序列
100+
int nLogN(vector<int> &nums) {
101+
int n = nums.size();
102+
if (n <= 1) {
103+
return n;
104+
}
105+
int ret = 1;
106+
vector<int> tails(n, 0);
107+
tails[0] = nums[0];
108+
for (int i = 1; i < nums.size(); i++) {
109+
int num = nums[i];
110+
if (num > tails[ret - 1]) {
111+
tails[ret++] = num;
112+
continue;
113+
}
114+
int l = 0, r = ret;
115+
while (l < r) {
116+
int mid = l + (r - l) / 2;
117+
if (num > tails[mid]) {
118+
l = mid + 1;
119+
} else {
120+
r = mid;
121+
}
122+
}
123+
tails[l] = num;
124+
}
125+
return ret;
126+
}
127+
};
128+
// @lc code=end

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /