题目地址:Number of Longest Increasing Subsequence - LeetCode
做这道题目前建议先做:Longest Increasing Subsequence - LeetCode
文章地址:LeetCode 300. Longest Increasing Subsequence–O(n log n)–Java,C++,Python解法
Given an unsorted array of integers, find the number of longest increasing subsequence.
Example 1:
Input: [1,3,5,4,7]
Output: 2
Explanation: The two longest increasing subsequence are [1, 3, 4, 7] and [1, 3, 5, 7].
Example 2:
Input: [2,2,2,2,2]
Output: 5
Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences' length is 1, so output 5.
Note: Length of the given array will be not exceed 2000 and the answer is guaranteed to be fit in 32-bit signed int.
这道题目是Longest Increasing Subsequence的升级版本。
比较容易想到的是O(N^2)的解法,也就是LIS的动态规划的升级版本。
O(N^2)的Java解法示例如下:
class Solution {
public int findNumberOfLIS(int[] nums) {
int N = nums.length;
if (N <= 1) return N;
int[] lengths = new int[N]; //lengths[i] = length of longest ending in nums[i]
int[] counts = new int[N]; //count[i] = number of longest ending in nums[i]
Arrays.fill(counts, 1);
for (int j = 0; j < N; ++j) {
for (int i = 0; i < j; ++i) if (nums[i] < nums[j]) {
if (lengths[i] >= lengths[j]) {
lengths[j] = lengths[i] + 1;
counts[j] = counts[i];
} else if (lengths[i] + 1 == lengths[j]) {
counts[j] += counts[i];
}
}
}
int longest = 0, ans = 0;
for (int length: lengths) {
longest = Math.max(longest, length);
}
for (int i = 0; i < N; ++i) {
if (lengths[i] == longest) {
ans += counts[i];
}
}
return ans;
}
}
但是既然LIS有O(N log N )的解法,那么这道题应该也有类似的解法
python3解法:
from collections import Counter
class Solution:
def findNumberOfLIS(self, nums: List[int]) -> int:
if not nums:
return 0
N = len(nums)
tails, tail_counts, mins = [[nums[0]]], [[1]], [nums[0]]
for i in range(1, N):
x = nums[i]
if x > mins[-1]:
mins.append(x)
extends = sum(tail_counts[-1][:bisect.bisect_left(tails[-1], x)])
tails.append([x])
tail_counts.append([extends])
elif x <= mins[0]:
if x < mins[0]:
tails[0].insert(0, x)
tail_counts[0].insert(0, 1)
mins[0] = x
else:
tail_counts[0][0] += 1
else:
tlen = bisect.bisect_left(mins, x) - 1
extends = sum(tail_counts[tlen][:bisect.bisect_left(tails[tlen], x)])
idx = 0
if tails[tlen+1][idx] == x:
tail_counts[tlen+1][idx] += extends
else:
tails[tlen+1].insert(idx, x)
tail_counts[tlen+1].insert(idx, extends)
mins[tlen+1] = min(mins[tlen+1], x)
# print("tails:%s, tail_counts:%s, mins:%s"%(tails, tail_counts, mins))
return sum(tail_counts[-1])
c++解法:
class Solution {
public:
int findNumberOfLIS(std::vector<int>& nums) {
std::vector<std::vector<std::pair<int,int>>> aux;
std::vector<int> v;
for (int i : nums) {
int ind = 0;
if (v.empty() || i > v.back()) {
v.push_back(i);
aux.push_back(std::vector<std::pair<int,int>>());
aux[v.size() - 1].push_back({ i, 0 });
ind = v.size() - 1;
}
else {
auto t = std::lower_bound(v.begin(), v.end(), i);
*t = i;
ind = t - v.begin();
aux[ind].push_back({ i, 0 });
}
if (ind == 0) aux[ind].back().second = 1;
else {
int k = 0;
for (auto& t : aux[ind - 1]) {
if (t.first < i) {
k += t.second;
}
}
aux[ind].back().second = k;
}
}
int res = 0;
if(aux.size() > 0){
for (auto& t : aux.back()) {
res += t.second;
}
}
return res;
}
};
java 解法:
class Solution {
public int findNumberOfLIS(int[] nums) {
if(nums.length<=1)return nums.length;
int[] dp = new int[nums.length];
int sp=0;
ArrayList<ArrayList<Node>> sol = new ArrayList<>();
//main loop starts
for(int i=0;i<nums.length;i++){
int l = 0, r=sp;
while(l!=r){
int mid = (l+r)/2;
if(dp[mid]<nums[i])l=mid+1;
else r=mid;
}
dp[l]=nums[i];
if(l==sp)++sp;
collect(sol,nums[i],l);
}
int res = 0;
for(Node i:sol.get(sol.size()-1)){
res+=i.count;
}
return res;
}
public void collect(ArrayList<ArrayList<Node>> sol, int val, int dest){
if(dest==sol.size())sol.add(new ArrayList<Node>());
Node cur = new Node(val,0);
if(dest==0)cur.count=1;
else{
for(Node i:sol.get(dest-1)){
if(i.val<cur.val)cur.count+=i.count;
}
}
sol.get(dest).add(cur);
}
public static class Node {
int count, val;
public Node(int val, int count){
this.val=val;
this.count=count;
}
}
}