简体   繁体   English

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

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

I want to find the longest increasing subsequence without sorting it, and to then sum the numbers of the period, for example like:我想找到最长的递增子序列而不对其进行排序,然后对期间的数字求和,例如:

12, 15, 16, 4, 7, 10, 20,25
  • 12,15,16 is an increasing subsequence. 12,15,16是递增子序列。
  • 4,7,10,20 is another increasing subsequence. 4,7,10,20是另一个增加的子序列。

but since 4,7,10,20,25 are 5 elements and 12,15,16 are 3 which is less than the 4 , the output should be the sum of the longer period which is the sum of the 5 elements, 66 .但由于4,7,10,20,255元素,而12,15,163 ,小于4 ,因此 output 应该是较长周期的总和,即5元素的总和66

How could such a thing be done using ?怎么可能使用来完成这样的事情? I am new to C so this is all what I could think of.我是 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;
}

You really need two loops.你真的需要两个循环。

One that iterates through all elements.一种遍历所有元素。 This is the "starting" index of a sequence.这是序列的“起始”索引。

Then, an inner loop that starts at one element to the right of the start.然后,一个内部循环从开头右侧的一个元素开始。 It loops to the end of the array but stops if it sees the current element is out of sequence.它循环到数组的末尾,但如果它发现当前元素顺序不对则停止。

After the second loop ends, the difference of these two indexes is the sequence length.第二次循环结束后,这两个索引的差就是序列长度。


Here is some refactored code.这是一些重构代码。 It is annotated:是这样注释的:

#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;
}

Here is the program output:这是程序 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

UPDATE:更新:

A [considerable] speedup for the above is to change:上述的[相当大的]加速是改变:

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

Into:进入:

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

And, move the int irhs;并且,移动int irhs; above the outer loop.在外环之上。

This reduces the time from O(n^2) to O(n)这将时间从 O(n^2) 减少到 O(n)

Here's an outline of one possible algorithm that will solve it using one loop.这是一种可能的算法的概述,该算法将使用一个循环来解决它。

Building blocks:建筑模块:

  • A variable that stores the number of elements in the longest sequence encountered so far, let's call it longest_seq .存储到目前为止遇到的最长序列中元素数量的变量,我们称之为longest_seq
  • A variable that stores the sum of the longest sequence encountered so far, longest_sum .存储迄今为止遇到的最长序列之和的变量longest_sum
  • A variable for counting the length of the sequence you are currently examining, running_seq .用于计算您当前正在检查的序列长度的变量running_seq
  • A variable keeping the sum of the current sequence, running_sum .保存当前序列总和的变量running_sum

Start by initializing:从初始化开始:

  • longest_seq = 0
  • longest_sum = 0

Then initialize the running variables to handle the first element.然后初始化运行变量来处理第一个元素。 The way the following loop is created should make it clear why.创建以下循环的方式应该清楚原因。

  • running_seq = 1
  • running_sum = arr[0]

Now to the interesting part:现在到了有趣的部分:

  • Let an index variable, i , loop from 1 (not 0 as usual, we handled the first element before the loop) to the number of elements you have in arr , minus 1 .让索引变量i1 (不像往常一样是0 ,我们在循环之前处理了第一个元素)循环到arr中的元素数减去1
    • If arr[i] is greater than arr[i-1] (the previous element), the running sequence is still going on, so如果arr[i]大于arr[i-1] (前一个元素),则运行序列仍在继续,因此
      • Increase running_seq by 1 .running_seq增加1
    • else, if arr[i] is not greater than arr[i-1] , the running sequence is broken, so否则,如果arr[i]大于arr[i-1] ,则运行序列被破坏,因此
      • Check if running_seq is greater than longest_seq .检查running_seq是否大于longest_seq If it is:如果是:
        • Save running_seq and running_sum to longest_seq and longest_sum .running_seqrunning_sum保存到longest_seqlongest_sum
      • Reset running_seq = 1 and running_sum = 0 .重置running_seq = 1running_sum = 0
    • Unconditionally add arr[i] to running_sum无条件地将arr[i]添加到running_sum

When the loop is done, you need to check if running_seq is greater than longest_seq again (and save the values in case it is) just in case the longest sequence happened to be at the end of the array.循环完成后,您需要再次检查running_seq是否大于longest_seq (并保存值以防万一)以防最长序列恰好位于数组的末尾。

The answers when this is done are in longest_seq and longest_sum .完成后的答案在longest_seqlongest_sum中。

Demo implementation演示实现


A variant with a minor difference is to change the loop slightly with regards to the updating of running_sum :一个有细微差别的变体是在更新running_sum方面稍微改变循环:

  • Let an index variable, i , loop from 1 (not 0 as usual, we handled the first element before the loop) to the number of elements you have in arr , minus 1 .让索引变量i1 (不像往常一样是0 ,我们在循环之前处理了第一个元素)循环到arr中的元素数减去1
    • If arr[i] is greater than arr[i-1] (the previous element), the running sequence is still going on, so如果arr[i]大于arr[i-1] (前一个元素),则运行序列仍在继续,因此
      • Increase running_seq by 1 .running_seq增加1
      • Add arr[i] to running_sumarr[i]添加到running_sum
    • else, if arr[i] is not greater than arr[i-1] , the running sequence is broken, so否则,如果arr[i]大于arr[i-1] ,则运行序列被破坏,因此
      • Check if running_seq is greater than longest_seq .检查running_seq是否大于longest_seq If it is:如果是:
        • Save running_seq and running_sum to longest_seq and longest_sum .running_seqrunning_sum保存到longest_seqlongest_sum
      • Reset running_seq = 1 and running_sum = arr[i] .重置running_seq = 1running_sum = arr[i]

Demo implementation演示实现

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

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