又有一长为n的数列:
a
0
,
a
1
,
…
,
a
n
−
1
a_0,a_1,…,a_{n-1}
a0,a1,…,an−1.求出这个序列中最长的上升子序列长度。上升子序列指的是对于任意
i
<
j
i<j
i<j都满足
a
i
<
a
j
a_i<a_j
ai<aj。
限制条件:
i
≤
n
≤
1000
i≤n≤1000
i≤n≤1000
0
≤
a
i
≤
1000000
0≤a_i≤1000000
0≤ai≤1000000
题解:
动态规划:
步骤:
dp数组含义:
d
p
[
i
]
dp[i]
dp[i]=以
a
i
a_i
ai为结尾的最长上升子序列的长度。
初始条件:
d
p
[
0
]
dp[0]
dp[0]不使用
d
p
[
1
]
=
1
dp[1]=1
dp[1]=1
递推公式:
d
p
[
i
]
=
m
a
x
{
1
,
d
p
[
j
]
+
1
∣
j
<
i
且
a
j
<
a
i
}
dp[i]=max\{1,dp[j]+1|j<i且a_j<a_i\}
dp[i]=max{1,dp[j]+1∣j<i且aj<ai}
结果:
m
a
x
{
d
p
[
i
]
∣
1
<
=
i
<
=
n
}
max\{dp[i]|1<=i<=n\}
max{dp[i]∣1<=i<=n}
时间复杂度 :
O
(
n
2
)
O(n^2)
O(n2)
代码 :函数
s
o
l
v
e
1
(
)
solve1()
solve1()
优化算法:
根据上面
d
p
dp
dp数组的含义,我们知道上面
d
p
dp
dp数组主要记录了两个信息:
i
i
i表示
a
i
,
d
p
a_i,dp
ai,dp数组里面存的是长度。我要优化该算法就必须从这个两个方向入手。我们知道在长度相同的上升序列中末尾元素越小越好,基于这个想法我们得到下面的动态规划:
步骤:
dp数组含义:
d
p
[
i
]
dp[i]
dp[i]=长度为i的上升子序列中末尾元素的最小值,如果长度i不存在就记为
i
n
f
inf
inf(无穷大)
初始化:
d
p
[
0
]
dp[0]
dp[0]不使用, dp[1-n]=inf
递推公式:循环整个数列的每个元素
a
i
a_i
ai,对每个元素
a
i
a_i
ai循环
d
p
dp
dp数组,找到第一个大于
a
i
a_i
ai的
d
p
[
j
]
dp[j]
dp[j],更新
d
p
[
j
]
=
m
i
n
a
i
,
d
p
[
j
]
dp[j]=min{a_i,dp[j]}
dp[j]=minai,dp[j]
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)
可以进一步优化,因为对于每个
a
i
a_i
ai循环
d
p
dp
dp数组时
d
p
dp
dp数组时单调递增的,所有我们查找
d
p
[
j
]
dp[j]
dp[j]可以使用二分查找法,这样时间复杂度变为:
O
(
n
l
o
g
2
n
)
O(nlog_2 n)
O(nlog2n)