给定一个大小为 N 的整数数组,您必须将其划分为最少数量的“严格递增子序列”
例如:令序列为{1, 3, 2, 4},则答案为2。在这种情况下,第一个递增序列为{1, 3, 4},第二个为{2}。
例子:
Input : arr[] = {1 3 2 4}
Output: 2
There are two increasing subsequences {1, 3, 4} and {2}
Input : arr[] = {4 3 2 1}
Output : 4
Input : arr[] = {1 2 3 4}
Output : 1
Input : arr[] = {1 6 2 4 3}
Output : 3
如果我们关注这个例子,我们可以看到最小递增子序列的数量等于最长递减子序列的长度,其中最长递减子序列的每个元素代表一个递增子序列,因此可以在 N*Log(N) 时间内找到通过将所有元素乘以-1,与最长递增子序列的复杂度相同。
我们对所有元素进行迭代并在排序数组(多重集)S 中存储到目前为止发现的每个递增子序列中的最后一个元素,对于每个元素 X,我们在 S 中选择小于 X 的最大元素 – 使用二分搜索 -并用 X 替换它,这意味着我们将当前元素添加到以 X 结尾的递增子序列中,否则,如果 S 中没有小于 X 的元素,我们将其插入 S 中,形成一个新的递增子序列,依此类推,直到最后一个元素我们最后的答案将是 S 的大小。
CPP
// C++ program to count the Minimum number of
// increasing subsequences
#include
using namespace std;
int MinimumNumIncreasingSubsequences(int arr[], int n)
{
multiset last;
// last element in each increasing subsequence
// found so far
for (int i = 0; i < n; i++) {
// here our current element is arr[i]
multiset::iterator it = last.lower_bound(arr[i]);
// iterator to the first element larger
// than or equal to arr[i]
if (it == last.begin())
// if all the elements in last larger
// than or to arr[i] then insert it into last
last.insert(arr[i]);
else {
it--;
// the largest element smaller than arr[i] is the number
// before *it which is it--
last.erase(it); // erase the largest element smaller than arr[i]
last.insert(arr[i]); // and replace it with arr[i]
}
}
return last.size(); // our answer is the size of last
}
// Driver program
int main()
{
int arr[] = { 8, 4, 1, 2, 9 };
int n = sizeof(arr) / sizeof(int);
cout << "Minimum number of increasing subsequences are : "
<< MinimumNumIncreasingSubsequences(arr, n);
return 0;
}
Java
// Java program for the above approach
import java.util.*;
public class Main {
static int longestDecrasingSubsequence(int A[], int N)
{
// Initialise Dp array
int dp[] = new int[N + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// All the elements are in range
// of Integer minvalue
// to maxvalue
// dp[i] indicate the min element
// of subsequence of
// length i is dp[i]
dp[0] = Integer.MIN_VALUE;
// For each number search for the correct position
// of number and insert the number in array
for (int i = 0; i < N; i++) {
// search for th position
int index = search(dp, A[i]);
// update the dp array
if (index != -1)
dp[index] = Math.min(dp[index], A[i]);
}
int len = 0;
for (int i = 1; i <= N; i++) {
if (dp[i] != Integer.MAX_VALUE)
len = Math.max(i, len);
}
return len;
}
// to search for correct position of num in array dp
static int search(int dp[], int num)
{
// initialise low,high and ans
int low = 0, high = dp.length - 1;
int ans = -1;
while (low <= high) {
// get mid
int mid = low + (high - low) / 2;
// if mid element is >=num search for left half
if (dp[mid] >= num) {
ans = mid;
high = mid - 1;
}
else
low = mid + 1;
}
return ans;
}
// Driver Code
public static void main(String args[])
{
int n = 4;
int a[] = { 1, 2, 3, 4 };
for (int i = 0; i < n; i++)
a[i] = -a[i];
System.out.print(longestDecrasingSubsequence(a, n));
}
}
Minimum number of increasing subsequences are : 3
时间复杂度:O(N log(N))
辅助空间:O(N)
方法2 :想法是找到最长的递减子序列
- 初始化一个长度为 n 的 dp 数组。
- 反转数组的所有元素。
- 对于数组中的每个元素。
- 如果当前元素在 dp 数组中,则查找索引。
- 找到有效的最大索引。
- dp[i] 表示以长度 i 子序列结尾的最小元素。
以下是上述方法的实现:
Java
// Java program for the above approach
import java.util.*;
public class Main {
static int longestDecrasingSubsequence(int A[], int N)
{
// Initialise Dp array
int dp[] = new int[N + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// All the elements are in range
// of Integer minvalue
// to maxvalue
// dp[i] indicate the min element
// of subsequence of
// length i is dp[i]
dp[0] = Integer.MIN_VALUE;
// For each number search for the correct position
// of number and insert the number in array
for (int i = 0; i < N; i++) {
// search for th position
int index = search(dp, A[i]);
// update the dp array
if (index != -1)
dp[index] = Math.min(dp[index], A[i]);
}
int len = 0;
for (int i = 1; i <= N; i++) {
if (dp[i] != Integer.MAX_VALUE)
len = Math.max(i, len);
}
return len;
}
// to search for correct position of num in array dp
static int search(int dp[], int num)
{
// initialise low,high and ans
int low = 0, high = dp.length - 1;
int ans = -1;
while (low <= high) {
// get mid
int mid = low + (high - low) / 2;
// if mid element is >=num search for left half
if (dp[mid] >= num) {
ans = mid;
high = mid - 1;
}
else
low = mid + 1;
}
return ans;
}
// Driver Code
public static void main(String args[])
{
int n = 4;
int a[] = { 1, 2, 3, 4 };
for (int i = 0; i < n; i++)
a[i] = -a[i];
System.out.print(longestDecrasingSubsequence(a, n));
}
}
1