解法一:转化为最长公共子序列
首先将数组排序,最长递增子序列转化为最长公共子序列问题。
- 设数组 { 3, 9, 7, 1, 5, 8 } 为 A
- 对数组 A 排序,排序后的数组为 B = { 1, 3, 5, 7, 8, 9 }
- 于是,求数组 A 的最长递增子序列,就是求数组 A 与数组 B 的最长公共子序列
这个方法时间复杂度为 O ( n 2 ) O(n^2) O(n2)
解法二:动态规划法
解法一中转化问题后使用动态规划,这里不进行转化而直接在原问题上用动态规划。
最优子结构:
对于长度为N的数组
A
[
N
]
=
{
a
0
,
a
1
,
⋯
,
a
n
}
A[N] = \{a_0,a_1,\cdots ,a_n\}
A[N]={a0,a1,⋯,an},令
L
[
i
]
L[i]
L[i]为以
a
i
a_i
ai结尾的最长递增子序列,那么有
L
[
n
]
=
max
0
≤
i
<
n
,
a
i
<
a
n
{
L
[
i
]
+
1
}
L[n]=\max_{0\le i\lt n,a_i<a_n}\{L[i]+1\}
L[n]=0≤i<n,ai<anmax{L[i]+1}
//得到L[i]
for(i = 0; i < len; i++){
lis[i] = 1;
for(j = 0; j < i; j++){
if(a[i] > a[j] && lis[i] < lis[j] + 1)
lis[i] = lis[j] + 1;
}
}
这个方法时间复杂度为 O ( n 2 ) O(n^2) O(n2)
解法三:有序辅助数组
具体操作如下:
- 建立一个辅助数组
a
r
r
a
y
array
array,依次读取数组元素
x
x
x与数组末尾元素
t
o
p
top
top比较:
- x > t o p : x\gt top: x>top:将 x x x放在数组末尾
- x < t o p : x\lt top: x<top:二分查找数组中第一个大于 x x x的数,并用 x x x替换
结束一遍遍历后, a r r a y array array中元素个数即为最长递增子序列的长度,与前面方法不同的是,方法三并不能得到最长递增子序列,而只能得到他的长度,但是时间复杂度达到了 O ( n log n ) O(n\log n) O(nlogn)。
算法正确性说明:
- 首先, a r r a y array array中存放的是有序的元素,因此可以用二分查找
- 其次,观察可以发现,
a
r
r
a
y
[
i
]
array[i]
array[i]中的元素的含义是长度为
i
+
1
\bm{i+1}
i+1的递增子序列的末尾元素的最小值,或者说
a r r a y [ i ] = min { a [ m i ] ∣ ∃ m 0 < ⋯ < m i , a [ m 0 ] < ⋯ < a [ m i ] } {array[i]=\min_{}\{a[m_i]~|~ \exists ~m_0<\cdots <m_i ,a[m_0]<\cdots <a[m_i]\}} array[i]=min{a[mi] ∣ ∃ m0<⋯<mi,a[m0]<⋯<a[mi]} - 以上两条性质通过数学归纳法比较容易证明,算法的正确性也就一目了然了
这就是我第一篇博客的全部内容了。