673. 最长递增子序列的个数
方法一:动态规划
, 分别表示以
状态转移方程为:
对于 ,其等于所有满足 的
class Solution:
def findNumberOfLIS(self, nums: List[int]) -> int:
n, max_len, ans = len(nums), 0, 0
dp = [1] * n
cnt = [1] * n
for i, x in enumerate(nums):
for j in range(i):
if x > nums[j]:
if dp[j] + 1 > dp[i]:
dp[i] = dp[j] + 1
cnt[i] = cnt[j] # 重置计数
elif dp[j] + 1 == dp[i]:
cnt[i] += cnt[j]
if dp[i] > max_len:
max_len = dp[i]
ans = cnt[i] # 重置计数
elif dp[i] == max_len:
ans += cnt[i]
return ans
方法二:贪心 + 前缀和 + 二分查找
将数组 d 扩展成一个二维数组,其中 d[i] 数组表示所有能成为长度为 i 的最长上升子序列的末尾元素的值。具体地,将更新 这一操作替换成将 置于 数组末尾。这样 中就保留了历史信息,且
类似地,也可以定义一个二维数组 ,其中 记录了以 为结尾的最长上升子序列的个数。为了计算 ,可以考察 和 ,将所有满足 的 累加到 ,这样最终答案就是
在代码实现时,由于 中的元素是有序的,可以二分得到最小的满足 的下标 k。另一处优化是将 改为其前缀和,并在开头填上 0,此时 对应的最长上升子序列的个数就是 ,这里
class Solution:
def findNumberOfLIS(self, nums: List[int]) -> int:
d, cnt = [], []
for v in nums:
i = bisect(len(d), lambda i: d[i][-1] >= v)
c = 1
if i > 0:
k = bisect(len(d[i - 1]), lambda k: d[i - 1][k] < v)
c = cnt[i - 1][-1] - cnt[i - 1][k]
if i == len(d):
d.append([v])
cnt.append([0, c])
else:
d[i].append(v)
cnt[i].append(cnt[i][-1] + c)
return cnt[-1][-1]
def bisect(n: int, f: Callable[[int], bool]) -> int:
l, r = 0, n
while l < r:
mid = (l + r) // 2
if f(mid):
r = mid
else:
l = mid + 1
return l