繁体   English   中英

如何在不排序的情况下找到最长的递增子序列?

[英]How to find the longest increasing subsequence without sorting?

我想找到最长的递增子序列而不对其进行排序,然后对期间的数字求和,例如:

12, 15, 16, 4, 7, 10, 20,25
  • 12,15,16是递增子序列。
  • 4,7,10,20是另一个增加的子序列。

但由于4,7,10,20,255元素,而12,15,163 ,小于4 ,因此 output 应该是较长周期的总和,即5元素的总和66

怎么可能使用来完成这样的事情? 我是 C 的新手,所以这就是我能想到的。

#include<stdio.h>
 int main() {
 int count = 0;
 int n;
 int max = 0;
 scanf("%d", &n);
 int arr[1000];
 for(int i = 0;i<n;i++){
  if(arr[i+1>arr[i])
   count++;
   if(count>max)
    max = count;
}

你真的需要两个循环。

一种遍历所有元素。 这是序列的“起始”索引。

然后,一个内部循环从开头右侧的一个元素开始。 它循环到数组的末尾,但如果它发现当前元素顺序不对则停止。

第二次循环结束后,这两个索引的差就是序列长度。


这是一些重构代码。 是这样注释的:

#include <stdio.h>

int arr[] = { 17, 18, 19, 5, 6, 23, 24, 25, 24, 25, 17, 18, 19 };

// show -- print a sequence
void
show(int begidx,int count,const char *tag)
{

    printf("%s: %d %d --",tag,begidx,count);

    for (;  count > 0;  --count, ++begidx)
        printf(" %d",arr[begidx]);

    printf("\n");
}

// sum -- get sum of the sequence
int
sum(int begidx,int count)
{
    int sum = 0;

    for (;  count > 0;  --count, ++begidx)
        sum += arr[begidx];

    return sum;
}

int
main(void)
{

    int count = sizeof(arr) / sizeof(arr[0]);
    int maxlen = 0;
    int maxidx = -1;

    show(0,count,"ORIG");

    // loop through all possible starting points for sequence
    for (int ilhs = 0;  ilhs < count;  ++ilhs) {
        int lval = arr[ilhs];

        // loop through all numbers to the right of the starter
        // stop at the array end or when we get a number that is out of sequence
        int irhs;
        for (irhs = ilhs + 1;  irhs < count;  ++irhs) {
            int rval = arr[irhs];

            // out of sequence -- we've hit the end
            if (rval < lval)
                break;

            lval = rval;
        }

        // get length of the sequence we just saw
        int curlen = irhs - ilhs;

        // remember a larger sequence
        if (curlen > maxlen) {
            maxlen = curlen;
            maxidx = ilhs;
            show(maxidx,maxlen,"NEW");
        }
    }

    // show the maximum sequence
    show(maxidx,maxlen,"FINAL");

    // sum the sequence
    printf("SUM: %d\n",sum(maxidx,maxlen));

    return 0;
}

这是程序 output:

ORIG: 0 13 -- 17 18 19 5 6 23 24 25 24 25 17 18 19
NEW: 0 3 -- 17 18 19
NEW: 3 5 -- 5 6 23 24 25
FINAL: 3 5 -- 5 6 23 24 25
SUM: 83

更新:

上述的[相当大的]加速是改变:

for (int ilhs = 0;  ilhs < count;  ++ilhs) {

进入:

for (int ilhs = 0;  ilhs < count;  ilhs = irhs) {

并且,移动int irhs; 在外环之上。

这将时间从 O(n^2) 减少到 O(n)

这是一种可能的算法的概述,该算法将使用一个循环来解决它。

建筑模块:

  • 存储到目前为止遇到的最长序列中元素数量的变量,我们称之为longest_seq
  • 存储迄今为止遇到的最长序列之和的变量longest_sum
  • 用于计算您当前正在检查的序列长度的变量running_seq
  • 保存当前序列总和的变量running_sum

从初始化开始:

  • longest_seq = 0
  • longest_sum = 0

然后初始化运行变量来处理第一个元素。 创建以下循环的方式应该清楚原因。

  • running_seq = 1
  • running_sum = arr[0]

现在到了有趣的部分:

  • 让索引变量i1 (不像往常一样是0 ,我们在循环之前处理了第一个元素)循环到arr中的元素数减去1
    • 如果arr[i]大于arr[i-1] (前一个元素),则运行序列仍在继续,因此
      • running_seq增加1
    • 否则,如果arr[i]大于arr[i-1] ,则运行序列被破坏,因此
      • 检查running_seq是否大于longest_seq 如果是:
        • running_seqrunning_sum保存到longest_seqlongest_sum
      • 重置running_seq = 1running_sum = 0
    • 无条件地将arr[i]添加到running_sum

循环完成后,您需要再次检查running_seq是否大于longest_seq (并保存值以防万一)以防最长序列恰好位于数组的末尾。

完成后的答案在longest_seqlongest_sum中。

演示实现


一个有细微差别的变体是在更新running_sum方面稍微改变循环:

  • 让索引变量i1 (不像往常一样是0 ,我们在循环之前处理了第一个元素)循环到arr中的元素数减去1
    • 如果arr[i]大于arr[i-1] (前一个元素),则运行序列仍在继续,因此
      • running_seq增加1
      • arr[i]添加到running_sum
    • 否则,如果arr[i]大于arr[i-1] ,则运行序列被破坏,因此
      • 检查running_seq是否大于longest_seq 如果是:
        • running_seqrunning_sum保存到longest_seqlongest_sum
      • 重置running_seq = 1running_sum = arr[i]

演示实现

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM