最大和递增子序列问题是寻找给定序列的最大和子序列,使得该子序列的所有元素按递增顺序排序。
例子:
Input: [1, 101, 2, 3, 100, 4, 5]
Output: [1, 2, 3, 100]
Input: [3, 4, 5, 10]
Output: [3, 4, 5, 10]
Input: [10, 5, 4, 3]
Output: [10]
Input: [3, 2, 6, 4, 5, 1]
Output: [3, 4, 5]
在上一篇文章中,我们讨论了最大和递增子序列问题。但是,该帖子仅涉及与查找递增子序列的最大和相关的代码,而不涉及子序列的构造。在这篇文章中,我们将讨论如何构建最大和递增子序列本身。
令 arr[0..n-1] 为输入数组。我们定义向量 L 使得 L[i] 本身是一个向量,它存储以 arr[i] 结尾的 arr[0..i] 的最大和递增子序列。因此对于索引 i,L[i] 可以递归地写为
L[0] = {arr[0]}
L[i] = {MaxSum(L[j])} + arr[i] where j < i and arr[j] < arr[i]
= arr[i], if there is no j such that arr[j] < arr[i]
例如,对于数组 [3, 2, 6, 4, 5, 1],
L[0]: 3
L[1]: 2
L[2]: 3 6
L[3]: 3 4
L[4]: 3 4 5
L[5]: 1
下面是上述想法的实现——
C++
/* Dynamic Programming solution to construct
Maximum Sum Increasing Subsequence */
#include
#include
using namespace std;
// Utility function to calculate sum of all
// vector elements
int findSum(vector arr)
{
int sum = 0;
for (int i : arr)
sum += i;
return sum;
}
// Function to construct Maximum Sum Increasing
// Subsequence
void printMaxSumIS(int arr[], int n)
{
// L[i] - The Maximum Sum Increasing
// Subsequence that ends with arr[i]
vector > L(n);
// L[0] is equal to arr[0]
L[0].push_back(arr[0]);
// start from index 1
for (int i = 1; i < n; i++) {
// for every j less than i
for (int j = 0; j < i; j++) {
/* L[i] = {MaxSum(L[j])} + arr[i]
where j < i and arr[j] < arr[i] */
if ((arr[i] > arr[j])
&& (findSum(L[i]) < findSum(L[j])))
L[i] = L[j];
}
// L[i] ends with arr[i]
L[i].push_back(arr[i]);
// L[i] now stores Maximum Sum Increasing
// Subsequence of arr[0..i] that ends with
// arr[i]
}
vector res = L[0];
// find max
for (vector x : L)
if (findSum(x) > findSum(res))
res = x;
// max will contain result
for (int i : res)
cout << i << " ";
cout << endl;
}
// Driver Code
int main()
{
int arr[] = { 3, 2, 6, 4, 5, 1 };
int n = sizeof(arr) / sizeof(arr[0]);
// construct and print Max Sum IS of arr
printMaxSumIS(arr, n);
return 0;
}
Java
/* Dynamic Programming solution to construct
Maximum Sum Increasing Subsequence */
import java.util.*;
class GFG {
// Utility function to calculate sum of all
// vector elements
static int findSum(Vector arr)
{
int sum = 0;
for (int i : arr)
sum += i;
return sum;
}
// Function to construct Maximum Sum Increasing
// Subsequence
static void printMaxSumIs(int[] arr, int n)
{
// L[i] - The Maximum Sum Increasing
// Subsequence that ends with arr[i]
@SuppressWarnings("unchecked")
Vector[] L = new Vector[n];
for (int i = 0; i < n; i++)
L[i] = new Vector<>();
// L[0] is equal to arr[0]
L[0].add(arr[0]);
// start from index 1
for (int i = 1; i < n; i++) {
// for every j less than i
for (int j = 0; j < i; j++) {
/*
* L[i] = {MaxSum(L[j])} + arr[i]
where j < i and arr[j] < arr[i]
*/
if ((arr[i] > arr[j])
&& (findSum(L[i]) < findSum(L[j]))) {
for (int k : L[j])
if (!L[i].contains(k))
L[i].add(k);
}
}
// L[i] ends with arr[i]
L[i].add(arr[i]);
// L[i] now stores Maximum Sum Increasing
// Subsequence of arr[0..i] that ends with
// arr[i]
}
Vector res = new Vector<>(L[0]);
// res = L[0];
// find max
for (Vector x : L)
if (findSum(x) > findSum(res))
res = x;
// max will contain result
for (int i : res)
System.out.print(i + " ");
System.out.println();
}
// Driver Code
public static void main(String[] args)
{
int[] arr = { 3, 2, 6, 4, 5, 1 };
int n = arr.length;
// construct and print Max Sum IS of arr
printMaxSumIs(arr, n);
}
}
// This code is contributed by
// sanjeev2552
Python3
# Dynamic Programming solution to construct
# Maximum Sum Increasing Subsequence */
# Utility function to calculate sum of all
# vector elements
def findSum(arr):
summ = 0
for i in arr:
summ += i
return summ
# Function to construct Maximum Sum Increasing
# Subsequence
def printMaxSumIS(arr, n):
# L[i] - The Maximum Sum Increasing
# Subsequence that ends with arr[i]
L = [[] for i in range(n)]
# L[0] is equal to arr[0]
L[0].append(arr[0])
# start from index 1
for i in range(1, n):
# for every j less than i
for j in range(i):
# L[i] = {MaxSum(L[j])} + arr[i]
# where j < i and arr[j] < arr[i]
if ((arr[i] > arr[j]) and
(findSum(L[i]) < findSum(L[j]))):
for e in L[j]:
if e not in L[i]:
L[i].append(e)
# L[i] ends with arr[i]
L[i].append(arr[i])
# L[i] now stores Maximum Sum Increasing
# Subsequence of arr[0..i] that ends with
# arr[i]
res = L[0]
# find max
for x in L:
if (findSum(x) > findSum(res)):
res = x
# max will contain result
for i in res:
print(i, end=" ")
# Driver Code
arr = [3, 2, 6, 4, 5, 1]
n = len(arr)
# construct and prMax Sum IS of arr
printMaxSumIS(arr, n)
# This code is contributed by Mohit Kumar
C#
/* Dynamic Programming solution to construct
Maximum Sum Increasing Subsequence */
using System;
using System.Collections.Generic;
class GFG {
// Utility function to calculate sum of all
// vector elements
static int findSum(List arr)
{
int sum = 0;
foreach(int i in arr) sum += i;
return sum;
}
// Function to construct Maximum Sum Increasing
// Subsequence
static void printMaxSumIs(int[] arr, int n)
{
// L[i] - The Maximum Sum Increasing
// Subsequence that ends with arr[i]
List[] L = new List[ n ];
for (int i = 0; i < n; i++)
L[i] = new List();
// L[0] is equal to arr[0]
L[0].Add(arr[0]);
// start from index 1
for (int i = 1; i < n; i++) {
// for every j less than i
for (int j = 0; j < i; j++) {
/*
* L[i] = {MaxSum(L[j])} + arr[i]
where j < i and arr[j] < arr[i]
*/
if ((arr[i] > arr[j])
&& (findSum(L[i]) < findSum(L[j]))) {
foreach(int k in
L[j]) if (!L[i].Contains(k))
L[i]
.Add(k);
}
}
// L[i] ends with arr[i]
L[i].Add(arr[i]);
// L[i] now stores Maximum Sum Increasing
// Subsequence of arr[0..i] that ends with
// arr[i]
}
List res = new List(L[0]);
// res = L[0];
// find max
foreach(List x in L) if (findSum(x)
> findSum(res)) res
= x;
// max will contain result
foreach(int i in res) Console.Write(i + " ");
Console.WriteLine();
}
// Driver Code
public static void Main(String[] args)
{
int[] arr = { 3, 2, 6, 4, 5, 1 };
int n = arr.Length;
// construct and print Max Sum IS of arr
printMaxSumIs(arr, n);
}
}
// This code is contributed by PrinciRaj1992
Javascript
C++14
/* Dynamic Programming solution to construct
Maximum Sum Increasing Subsequence */
#include
using namespace std;
// Function to construct and print the Maximum Sum
// Increasing Subsequence
void constructMaxSumIS(vector arr, int n)
{
// L[i] stores the value of Maximum Sum Increasing
// Subsequence that ends with arr[i] and the index of
// previous element used to construct the Subsequence
vector > L(n);
int index = 0;
for (int i : arr) {
L[index] = { i, index };
index++;
}
// Set L[0].second equal to -1
L[0].second = -1;
// start from index 1
for (int i = 1; i < n; i++) {
// for every j less than i
for (int j = 0; j < i; j++) {
if (arr[i] > arr[j]
and L[i].first < arr[i] + L[j].first) {
L[i].first = arr[i] + L[j].first;
L[i].second = j;
}
}
}
int maxi = INT_MIN, currIndex, track = 0;
for (auto p : L) {
if (p.first > maxi) {
maxi = p.first;
currIndex = track;
}
track++;
}
// Stores the final Subsequence
vector result;
// Index of previous element
// used to construct the Subsequence
int prevoiusIndex;
while (currIndex >= 0) {
result.push_back(arr[currIndex]);
prevoiusIndex = L[currIndex].second;
if (currIndex == prevoiusIndex)
break;
currIndex = prevoiusIndex;
}
for (int i = result.size() - 1; i >= 0; i--)
cout << result[i] << " ";
}
// Driver Code
int main()
{
vector arr = { 1, 101, 2, 3, 100, 4, 5 };
int n = arr.size();
// Function call
constructMaxSumIS(arr, n);
return 0;
}
Java
// Dynamic Programming solution to construct
// Maximum Sum Increasing Subsequence
import java.util.*;
import java.awt.Point;
class GFG{
// Function to construct and print the Maximum Sum
// Increasing Subsequence
static void constructMaxSumIS(List arr, int n)
{
// L.get(i) stores the value of Maximum Sum Increasing
// Subsequence that ends with arr.get(i) and the index of
// previous element used to construct the Subsequence
List L = new ArrayList();
int index = 0;
for(int i : arr)
{
L.add(new Point(i, index));
index++;
}
// Set L[0].second equal to -1
L.set(0, new Point(L.get(0).x, -1));
// Start from index 1
for(int i = 1; i < n; i++)
{
// For every j less than i
for(int j = 0; j < i; j++)
{
if (arr.get(i) > arr.get(j) &&
L.get(i).x < arr.get(i) +
L.get(j).x)
{
L.set(i, new Point(arr.get(i) +
L.get(j).x, j));
}
}
}
int maxi = -100000000, currIndex = 0, track = 0;
for(Point p : L)
{
if (p.x > maxi)
{
maxi = p.x;
currIndex = track;
}
track++;
}
// Stores the final Subsequence
List result = new ArrayList();
// Index of previous element
// used to construct the Subsequence
int prevoiusIndex;
while (currIndex >= 0)
{
result.add(arr.get(currIndex));
prevoiusIndex = L.get(currIndex).y;
if (currIndex == prevoiusIndex)
break;
currIndex = prevoiusIndex;
}
for(int i = result.size() - 1; i >= 0; i--)
System.out.print(result.get(i) + " ");
}
// Driver Code
public static void main(String []s)
{
List arr = new ArrayList();
arr.add(1);
arr.add(101);
arr.add(2);
arr.add(3);
arr.add(100);
arr.add(4);
arr.add(5);
int n = arr.size();
// Function call
constructMaxSumIS(arr, n);
}
}
// This code is contributed by rutvik_56
Python3
# Dynamic Programming solution to construct
# Maximum Sum Increasing Subsequence
import sys
# Function to construct and print the Maximum Sum
# Increasing Subsequence
def constructMaxSumIS(arr, n) :
# L[i] stores the value of Maximum Sum Increasing
# Subsequence that ends with arr[i] and the index of
# previous element used to construct the Subsequence
L = []
index = 0
for i in arr :
L.append([i, index])
index += 1
# Set L[0].second equal to -1
L[0][1] = -1
# start from index 1
for i in range(1, n) :
# for every j less than i
for j in range(i) :
if (arr[i] > arr[j] and L[i][0] < arr[i] + L[j][0]) :
L[i][0] = arr[i] + L[j][0]
L[i][1] = j
maxi, currIndex, track = -sys.maxsize, 0, 0
for p in L :
if (p[0] > maxi) :
maxi = p[0]
currIndex = track
track += 1
# Stores the final Subsequence
result = []
while (currIndex >= 0) :
result.append(arr[currIndex])
prevoiusIndex = L[currIndex][1]
if (currIndex == prevoiusIndex) :
break
currIndex = prevoiusIndex
for i in range(len(result) - 1, -1, -1) :
print(result[i] , end = " ")
arr = [ 1, 101, 2, 3, 100, 4, 5 ]
n = len(arr)
# Function call
constructMaxSumIS(arr, n)
# This code is contributed by divyeshrabadiya07
C#
/* Dynamic Programming solution to construct
Maximum Sum Increasing Subsequence */
using System;
using System.Collections.Generic;
class GFG
{
// Function to construct and print the Maximum Sum
// Increasing Subsequence
static void constructMaxSumIS(List arr, int n)
{
// L[i] stores the value of Maximum Sum Increasing
// Subsequence that ends with arr[i] and the index of
// previous element used to construct the Subsequence
List> L = new List>();
int index = 0;
foreach(int i in arr) {
L.Add(new Tuple(i, index));
index++;
}
// Set L[0].second equal to -1
L[0] = new Tuple(L[0].Item1, -1);
// start from index 1
for (int i = 1; i < n; i++)
{
// for every j less than i
for (int j = 0; j < i; j++)
{
if (arr[i] > arr[j] &&
L[i].Item1 < arr[i] +
L[j].Item1)
{
L[i] = new Tuple(arr[i] + L[j].Item1, j);
}
}
}
int maxi = Int32.MinValue,
currIndex = 0, track = 0;
foreach(Tuple p in L)
{
if (p.Item1 > maxi)
{
maxi = p.Item1;
currIndex = track;
}
track++;
}
// Stores the final Subsequence
List result = new List();
// Index of previous element
// used to construct the Subsequence
int prevoiusIndex;
while (currIndex >= 0)
{
result.Add(arr[currIndex]);
prevoiusIndex = L[currIndex].Item2;
if (currIndex == prevoiusIndex)
break;
currIndex = prevoiusIndex;
}
for (int i = result.Count - 1; i >= 0; i--)
Console.Write(result[i] + " ");
}
static void Main()
{
List arr = new List(new
int[] { 1, 101, 2, 3, 100, 4, 5 });
int n = arr.Count;
// Function call
constructMaxSumIS(arr, n);
}
}
// This code is contributed by divyesh072019
3 4 5
我们可以通过删除 findSum()函数来优化上述 DP 解决方案。相反,我们可以维护另一个向量/数组来存储以 arr[i] 结尾的最大和递增子序列的总和。实现可以在这里看到。
上述动态规划解决方案的时间复杂度为 O(n 2 )。
程序使用的辅助空间为O(n 2 )。
方法2:(使用 使用 O(N) 空间的动态规划
上述方法涵盖了如何在 O(N 2 ) 时间和 O(N 2 ) 空间中构造最大和递增子序列。在这种方法中,我们将优化空间复杂度并在 O(N 2 ) 时间和 O(N) 空间中构造最大和递增子序列。
- 令 arr[0..n-1] 为输入数组。
- 我们定义了一个 L 对向量,使得 L[i] 首先存储以 arr[i] 结尾的 arr[0..i] 的最大和递增子序列,而 L[i].second 存储使用的前一个元素的索引用于生成总和。
- 由于第一个元素没有任何先前的元素,因此它的索引在 L[0] 中将为 -1。
例如,
array = [3, 2, 6, 4, 5, 1]
L[0]: {3, -1}
L[1]: {2, 1}
L[2]: {9, 0}
L[3]: {7, 0}
L[4]: {12, 3}
L[5]: {1, 5}
正如我们在上面看到的,最大和递增子序列的值为 12。为了构造实际的子序列,我们将使用存储在 L[i].second 中的索引。构建子序列的步骤如下所示:
- 在向量结果中,存储找到最大和增加子序列的元素的值(即在 currIndex = 4 处)。所以在结果向量中,我们将添加 arr[currIndex]。
- 将 currIndex 更新为 L[currIndex].second 并重复步骤 1,直到 currIndex 不为 -1 或它不改变(即 currIndex == previousIndex)。
- 以相反的顺序显示结果向量的元素。
下面是上述想法的实现:
C++14
/* Dynamic Programming solution to construct
Maximum Sum Increasing Subsequence */
#include
using namespace std;
// Function to construct and print the Maximum Sum
// Increasing Subsequence
void constructMaxSumIS(vector arr, int n)
{
// L[i] stores the value of Maximum Sum Increasing
// Subsequence that ends with arr[i] and the index of
// previous element used to construct the Subsequence
vector > L(n);
int index = 0;
for (int i : arr) {
L[index] = { i, index };
index++;
}
// Set L[0].second equal to -1
L[0].second = -1;
// start from index 1
for (int i = 1; i < n; i++) {
// for every j less than i
for (int j = 0; j < i; j++) {
if (arr[i] > arr[j]
and L[i].first < arr[i] + L[j].first) {
L[i].first = arr[i] + L[j].first;
L[i].second = j;
}
}
}
int maxi = INT_MIN, currIndex, track = 0;
for (auto p : L) {
if (p.first > maxi) {
maxi = p.first;
currIndex = track;
}
track++;
}
// Stores the final Subsequence
vector result;
// Index of previous element
// used to construct the Subsequence
int prevoiusIndex;
while (currIndex >= 0) {
result.push_back(arr[currIndex]);
prevoiusIndex = L[currIndex].second;
if (currIndex == prevoiusIndex)
break;
currIndex = prevoiusIndex;
}
for (int i = result.size() - 1; i >= 0; i--)
cout << result[i] << " ";
}
// Driver Code
int main()
{
vector arr = { 1, 101, 2, 3, 100, 4, 5 };
int n = arr.size();
// Function call
constructMaxSumIS(arr, n);
return 0;
}
Java
// Dynamic Programming solution to construct
// Maximum Sum Increasing Subsequence
import java.util.*;
import java.awt.Point;
class GFG{
// Function to construct and print the Maximum Sum
// Increasing Subsequence
static void constructMaxSumIS(List arr, int n)
{
// L.get(i) stores the value of Maximum Sum Increasing
// Subsequence that ends with arr.get(i) and the index of
// previous element used to construct the Subsequence
List L = new ArrayList();
int index = 0;
for(int i : arr)
{
L.add(new Point(i, index));
index++;
}
// Set L[0].second equal to -1
L.set(0, new Point(L.get(0).x, -1));
// Start from index 1
for(int i = 1; i < n; i++)
{
// For every j less than i
for(int j = 0; j < i; j++)
{
if (arr.get(i) > arr.get(j) &&
L.get(i).x < arr.get(i) +
L.get(j).x)
{
L.set(i, new Point(arr.get(i) +
L.get(j).x, j));
}
}
}
int maxi = -100000000, currIndex = 0, track = 0;
for(Point p : L)
{
if (p.x > maxi)
{
maxi = p.x;
currIndex = track;
}
track++;
}
// Stores the final Subsequence
List result = new ArrayList();
// Index of previous element
// used to construct the Subsequence
int prevoiusIndex;
while (currIndex >= 0)
{
result.add(arr.get(currIndex));
prevoiusIndex = L.get(currIndex).y;
if (currIndex == prevoiusIndex)
break;
currIndex = prevoiusIndex;
}
for(int i = result.size() - 1; i >= 0; i--)
System.out.print(result.get(i) + " ");
}
// Driver Code
public static void main(String []s)
{
List arr = new ArrayList();
arr.add(1);
arr.add(101);
arr.add(2);
arr.add(3);
arr.add(100);
arr.add(4);
arr.add(5);
int n = arr.size();
// Function call
constructMaxSumIS(arr, n);
}
}
// This code is contributed by rutvik_56
蟒蛇3
# Dynamic Programming solution to construct
# Maximum Sum Increasing Subsequence
import sys
# Function to construct and print the Maximum Sum
# Increasing Subsequence
def constructMaxSumIS(arr, n) :
# L[i] stores the value of Maximum Sum Increasing
# Subsequence that ends with arr[i] and the index of
# previous element used to construct the Subsequence
L = []
index = 0
for i in arr :
L.append([i, index])
index += 1
# Set L[0].second equal to -1
L[0][1] = -1
# start from index 1
for i in range(1, n) :
# for every j less than i
for j in range(i) :
if (arr[i] > arr[j] and L[i][0] < arr[i] + L[j][0]) :
L[i][0] = arr[i] + L[j][0]
L[i][1] = j
maxi, currIndex, track = -sys.maxsize, 0, 0
for p in L :
if (p[0] > maxi) :
maxi = p[0]
currIndex = track
track += 1
# Stores the final Subsequence
result = []
while (currIndex >= 0) :
result.append(arr[currIndex])
prevoiusIndex = L[currIndex][1]
if (currIndex == prevoiusIndex) :
break
currIndex = prevoiusIndex
for i in range(len(result) - 1, -1, -1) :
print(result[i] , end = " ")
arr = [ 1, 101, 2, 3, 100, 4, 5 ]
n = len(arr)
# Function call
constructMaxSumIS(arr, n)
# This code is contributed by divyeshrabadiya07
C#
/* Dynamic Programming solution to construct
Maximum Sum Increasing Subsequence */
using System;
using System.Collections.Generic;
class GFG
{
// Function to construct and print the Maximum Sum
// Increasing Subsequence
static void constructMaxSumIS(List arr, int n)
{
// L[i] stores the value of Maximum Sum Increasing
// Subsequence that ends with arr[i] and the index of
// previous element used to construct the Subsequence
List> L = new List>();
int index = 0;
foreach(int i in arr) {
L.Add(new Tuple(i, index));
index++;
}
// Set L[0].second equal to -1
L[0] = new Tuple(L[0].Item1, -1);
// start from index 1
for (int i = 1; i < n; i++)
{
// for every j less than i
for (int j = 0; j < i; j++)
{
if (arr[i] > arr[j] &&
L[i].Item1 < arr[i] +
L[j].Item1)
{
L[i] = new Tuple(arr[i] + L[j].Item1, j);
}
}
}
int maxi = Int32.MinValue,
currIndex = 0, track = 0;
foreach(Tuple p in L)
{
if (p.Item1 > maxi)
{
maxi = p.Item1;
currIndex = track;
}
track++;
}
// Stores the final Subsequence
List result = new List();
// Index of previous element
// used to construct the Subsequence
int prevoiusIndex;
while (currIndex >= 0)
{
result.Add(arr[currIndex]);
prevoiusIndex = L[currIndex].Item2;
if (currIndex == prevoiusIndex)
break;
currIndex = prevoiusIndex;
}
for (int i = result.Count - 1; i >= 0; i--)
Console.Write(result[i] + " ");
}
static void Main()
{
List arr = new List(new
int[] { 1, 101, 2, 3, 100, 4, 5 });
int n = arr.Count;
// Function call
constructMaxSumIS(arr, n);
}
}
// This code is contributed by divyesh072019
1 2 3 100
时间复杂度: O(N 2 )
空间复杂度: O(N)
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。