找到总和最大的递增子序列

Posted

技术标签:

【中文标题】找到总和最大的递增子序列【英文标题】:Find the increasing subsequence with maximum sum 【发布时间】:2020-11-10 10:41:01 【问题描述】:

我正在尝试查找数组的子数组(也:子序列)。到目前为止,我找到了正确的最大和,但不知道如何找到元素本身。 例如:

输入= [10,70,20,30,50,11,30] 输出 = [110, [10,20,30,50]]

我的代码找到了 110,但我很难找到元素。 我的代码:

const maxSubequence = (arr) => 
  let i, j;
  let msis = arr.slice(); //Copy input array

  //result variables
  let resultSeq = [];
  let maxSum = 0;
  let result = [];

  /* Compute maximum sum values in bottom up manner */
  for (i = 1; i < arr.length; i++) 
    for (j = 0; j < i; j++) 
      if (arr[i] > arr[j] && msis[i] < msis[j] + arr[i]) 
        msis[i] = msis[j] + arr[i];
      
    
  
  // console.log(tempSeq);
  /* Pick maximum of all  msis values */
  let maxIndex = 0;
  for (i = 0; i < msis.length; i++) 
    if (maxSum < msis[i]) 
      maxSum = msis[i];
      maxIndex = i;
    
  
  //Retrieve the max sequence elements using msis max sums - NOT WORKING
  var tempSeq = [msis[maxIndex]];
  resultSeq = [arr[maxIndex]];
  for (i = maxIndex - 1; i >= 0; i--) 
    if (msis[i] < tempSeq[0]) 
      tempSeq.unshift(msis[i])
      resultSeq.unshift(arr[i])
    
  
  result = [maxSum, resultSeq];
  return result;



console.log(
  maxSubequence([10, 70, 20, 30, 50, 11, 30])
)

【问题讨论】:

你会分享一些输入和输出样本吗? arrayTwo = [30,20, 10,50];输出:[60,[10,50]] 一般需要维护maxSumStartIndexmaxSumEndIndex(或maxSumArrLength)。 maxSumStartIndex 和 maxSumEndIndex(或 maxSumArrLength) - 已经尝试过类似的东西,但它不起作用 @חייםחדד 答案不应该是 [80, [30, 50] ] 吗? 【参考方案1】:

考虑将索引i 加入书签,其中先前的最大递增和序列结束于索引j 处的当前数字扩展。如果当前数字不扩展任何先前的序列,则将其设置为 -1。现在找到最大和的索引后,您可以使用书签返回,直到索引变为-1。反转的数组将是您预期的最大递增和序列。

const maxSubequence = (arr) => 
  let i, j;
  let msis = arr.slice(); //Copy input array

  //result variables
  let resultSeq = [];
  let maxSum = 0;
  let result = [];
  var bookmark = new Array(arr.length);
  bookmark[0] = -1;
  /* Compute maximum sum values in bottom up manner */
  for (i = 1; i < arr.length; i++) 
    bookmark[i] = -1;
    for (j = 0; j < i; j++) 
      if (arr[i] > arr[j] && msis[i] < msis[j] + arr[i]) 
        msis[i] = msis[j] + arr[i];
        bookmark[i] = j;
      
    
  
  // console.log(tempSeq);
  /* Pick maximum of all  msis values */
  let maxIndex = 0;
  for (i = 0; i < msis.length; i++) 
    if (maxSum < msis[i]) 
      maxSum = msis[i];
      maxIndex = i;
    
  

  resultSeq = [arr[maxIndex]];
  for (i = bookmark[maxIndex]; i >= 0; i = bookmark[i]) 
      resultSeq.unshift(arr[i])
  
  result = [maxSum, resultSeq];
  return result;



console.log(
  maxSubequence([30,20, 10,50])
)

【讨论】:

【参考方案2】:
        const findSum = arr => 
            var sum = 0;
            arr.forEach(element=>
                sum = sum + element
            );
            return sum;
        



        const maxSubequenceSum = arr =>

        // L[i] - The Maximum Sum Increasing
        // Subsequence that ends with arr[i]
        var L = [];

        for (var i = 0; i < arr.length; i++)
                L[i] = [];

        // L[0] is equal to arr[0]
        L[0].push(arr[0]);

        // Start from index 1
        for (var i = 1; i < arr.length; i++) 

            // For each j less than i
            for (var j = 0; j < i; j++) 

            /*
            * L[i] = MaxSum(L[j]) + arr[i]
            where j < i and arr[j] < arr[i]
            */
                var sumLi = findSum(L[i]);
                var sumLj = findSum(L[j]);

                if ( (arr[i] > arr[j]) && (sumLi < sumLj) ) 
                    console.log(`$arr[i] > $arr[j] && $sumLi < $sumLj`);
                    L[j].forEach( k=>
                        if (!L[i].includes(k))
                            L[i].push(k);
                            console.log(L);
                            
                             
                    );
                
                
            

            // L[i] ends with arr[i]

            L[i].push(arr[i]);

            // L[i] now stores Maximum Sum Increasing
            // Subsequence of arr[0..i] that ends with arr[i]

        

        // res = L[0];
        var res = [L[0]];
        
        // Find max
        L.forEach( x =>
            if (findSum(x) > findSum(res))
                res = x;

        );

        // Results variables
        var max = 0;
        var subSequence=[];
        var result;

        //Summing res elements = Max sum
        //Each res element = subsequence 
        res.forEach(i=>
            max = max + i;
            subSequence.push(i);
        );


        result = [max,subSequence];
        //Time complexity: O(n^2))
        return result;

【讨论】:

由于您的 findsum 函数,您的解决方案是 O(n^3) 时间。我的答案中产生递增和序列的解决方案更好,因为它是 O(n^2) 时间。此外,它只需要 O(n) 额外空间,而您的解决方案需要 O(n^2) 额外空间。

以上是关于找到总和最大的递增子序列的主要内容,如果未能解决你的问题,请参考以下文章

力扣技巧之动态规划力扣300:最大递增子序列C++

动态规划之最大递增子序列

最大递增子序列问题

最大子序和

最长递增子序列 && 最大子序列最长递增子序列最长公共子串最长公共子序列字符串编辑距离

将一个序列调整为单调序列的最小代价问题