673. 最长递增子序列的个数
给定一个未排序的整数数组,找到最长递增子序列的个数。
示例 1:
输入: [1,3,5,4,7]
输出: 2
解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。
示例 2:
输入: [2,2,2,2,2]
输出: 5
解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。
注意: 给定的数组长度不超过 2000 并且结果一定是32位有符号整数。
动态规划 中等
300. 最长递增子序列 的进阶版
代码
1.朴素想法是把长度等于最长长度的子序列都记下来
class Solution:
def findNumberOfLIS(self, nums: List[int]) -> int:
n, max_len, ans = len(nums), 0, 0
dp = [0] * n
cnt = [0] * n
for i, x in enumerate(nums):
dp[i] = 1
cnt[i] = 1
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
2. 二分的方法有些难懂
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