C++ 查找数组中元素和最大的子序列

C++ 查找数组中元素和最大的子序列,c++,c,algorithm,C++,C,Algorithm,我最近采访了一家公司,他们让我写一个算法,找到数组中元素总和最大的子序列。数组中的元素可以是负数。有O(n)解决方案吗?非常感谢任何好的解决方案。我想你指的是最长的递增子序列 没有O(n)解决方案 一个非常简单的解决方案是创建一个重复的数组,在O(NlogN)中对其进行排序,然后找到排序后的数组和原始数组的LCS,该数组采用O(N^2) 还有一种基于直接DP的解决方案,类似于LCS,它也需要O(N^2),您可以看到 但如果你指的是最长的递增序列(连续)。这可以在O(N)中完成,如果您指的是最长的

我最近采访了一家公司,他们让我写一个算法,找到数组中元素总和最大的子序列。数组中的元素可以是负数。有O(n)解决方案吗?非常感谢任何好的解决方案。

我想你指的是最长的递增子序列

没有
O(n)
解决方案

一个非常简单的解决方案是创建一个重复的数组,在
O(NlogN)
中对其进行排序,然后找到排序后的数组和原始数组的
LCS
,该数组采用
O(N^2)

还有一种基于直接DP的解决方案,类似于
LCS
,它也需要
O(N^2)
,您可以看到


但如果你指的是最长的递增序列(连续)。这可以在
O(N)
中完成,如果您指的是最长的递增子序列,请参见codaddict的答案

另一方面,如果您的意思是查找具有最大和的子数组(只有负值才有意义),那么有一个优雅的动态规划风格的线性时间解决方案:


如果您想要序列号的最大和,那么类似的方法可能会奏效:

$cur = $max = 0;
foreach ($seq as $n)
{
  $cur += $n;
  if ($cur < 0) $cur = 0;
  if ($cur > $max) $max = $cur;
}
$cur=$max=0;
foreach($n)
{
$cur+=$n;
如果($cur<0)$cur=0;
如果($cur>$max)$max=$cur;
}
这只是我的想法,但似乎是对的。(忽略它假设0是空集和所有负集的答案。)

编辑:

如果还需要序列位置:

$cur = $max = 0;
$cur_i = $max_i = 0; 
$max_j = 1;

foreach ($seq as $i => $n)
{
  $cur += $n;
  if ($cur > $max)
  {
    $max = $cur;
    if ($cur_i != $max_i)
    {
      $max_i = $cur_i;
      $max_j = $max_i + 1;
    }
    else
    {
      $max_j = $i + 1;
    }
  }

  if ($cur < 0)
  {
    $cur = 0;
    $cur_i = $i + 1;
  }
}

var_dump(array_slice($seq, $max_i, $max_j - $max_i), $max);
$cur=$max=0;
$cur_i=$max_i=0;
$max_j=1;
foreach($i=>n)
{
$cur+=$n;
如果($cur>$max)
{
$max=$cur;
如果($cur_i!=$max_i)
{
$max_i=$cur_i;
$max_j=$max_i+1;
}
其他的
{
$max_j=$i+1;
}
}
如果($cur<0)
{
$cur=0;
$cur_i=$i+1;
}
}
var_dump(数组_切片($seq、$max_i、$max_j-$max_i),$max);
也许有一种更简洁的方法可以做到这一点。同样,它具有相同的假设(至少一个正整数)。而且,它只找到第一个最大的序列


编辑:将其更改为使用
max_j
(专用)而不是
max_len

C函数如下所示:

int largest(int arr[], int length)
{
  int sum= arr[0];
  int tempsum=0;
  for(int i=0;i<length;i++){
     tempsum+=arr[i];
     if(tempsum>sum)
        sum=tempsum;
     if(tempsum<0)
        tempsum=0;
  }
  return sum;
}
int最大值(int-arr[],int-length)
{
int sum=arr[0];
int tempsum=0;
对于(int i=0;isum)
sum=tempsum;

如果(tempsum尝试以下代码:

#include <stdio.h>

int main(void) {
    int arr[] = {-11,-2,3,-1,2,-9,-4,-5,-2, -3};
    int cur = arr[0] >= 0? arr[0] : 0, max = arr[0];
    int start = 0, end = 0;
    int i,j = cur == 0 ? 1 : 0;
    printf("Cur\tMax\tStart\tEnd\n");
    printf("%d\t%d\t%d\t%d\n",cur,max,start,end);
    for (i = 1; i < 10; i++) {
        cur += arr[i];
        if (cur > max) {
            max = cur;
            end = i;
            if (j > start) start = j;
        }     
        if (cur < 0) {
            cur = 0;
            j = i+1;
        }
        printf("%d\t%d\t%d\t%d\n",cur,max,start,end);
    }
    getchar();
}
#包括
内部主(空){
int arr[]={-11,-2,3,-1,2,-9,-4,-5,-2,-3};
int cur=arr[0]>=0?arr[0]:0,max=arr[0];
int start=0,end=0;
int i,j=cur==0?1:0;
printf(“Cur\tMax\tStart\tEnd\n”);
printf(“%d\t%d\t%d\t%d\t%d\n”,cur,max,start,end);
对于(i=1;i<10;i++){
cur+=arr[i];
如果(电流>最大值){
max=cur;
end=i;
如果(j>start)start=j;
}     
if(cur<0){
cur=0;
j=i+1;
}
printf(“%d\t%d\t%d\t%d\t%d\n”,cur,max,start,end);
}
getchar();
}
void longsub(int a[],int len){
int localsum=int_MIN;
int globalsum=int_MIN;
int startindex=0,i=0;
int stopindex=0;
int localstart=0;
对于(i=0;iglobalsum){
startindex=localstart;
globalsum=localsum;
停止指数=i;
}
}
printf(“开始索引和结束索引为%d->%d(%d)。\n)”,开始索引、停止索引、全局索引;
}

这个问题可以用两种不同的方法解决

第一种方法是使用两个变量,分别称为
sum
MaxSum

  • 我们将继续向和添加值,并将与MaxSum进行比较,如果和的值大于MaxSum-将向MaxSum分配和值

  • 如果在此过程中,总和的值低于0,我们将重置总和,并从上一个索引开始添加新数字。 上述解决方案的示例代码如下所示:

    private static void FindMaxSum(int[] array)
    {
        int sum = 0;
        int MaxSum = 0;
    
        for (int i = 0; i < array.Length; i++)
        {
            sum += array[i];
    
            if (sum > MaxSum)
            {
                MaxSum = sum;
            }
            else if (sum < 0)
            {
                sum = 0;
            }
        }
        Console.WriteLine("Maximum sum is: " + MaxSum);
    }   
    
    私有静态void FindMaxSum(int[]数组)
    {
    整数和=0;
    int最大和=0;
    for(int i=0;i最大总和)
    {
    最大和=和;
    }
    else if(总和<0)
    {
    总和=0;
    }
    }
    Console.WriteLine(“最大总和为:“+MaxSum”);
    }   
    
  • 解决这个问题的第二种方法是,我们将遍历数组中的每个元素。我们将有相同的两个变量sum和MaxSum

  • 首先,我们将比较sum与下一个数组元素的加法和sum本身。谁更大-该值将存储在sum变量中

  • 接下来,我们将比较sum和MaxSum的值,无论谁的值更大,我们将把该值保存在MaxSum变量中。 示例代码如下所述:

    private static void FindMaxSum(int[] array)
    {
        int sum = array[0], Maxsum = array[0];
    
        for (int i = 1; i < array.Length; i++)
        {
            sum = Max(sum + array[i], array[i]);
            Maxsum = Max(sum, Maxsum);               
        }
    
        Console.WriteLine("Maximum sum is: " + Maxsum);
    }
    
    private static int Max(int a, int b)
    {
        return a > b ? a : b;
    }
    
    私有静态void FindMaxSum(int[]数组)
    {
    整数和=数组[0],最大和=数组[0];
    for(int i=1;ib?a:b;
    }
    

  • 如果你问什么是求和最大的连续子序列,我找到了4个算法:-

  • 蛮力:使用嵌套循环查找所有可能的和,如果发现的和大于先前设置的maxSum值,则继续更新maxSum
    private static void FindMaxSum(int[] array)
    {
        int sum = array[0], Maxsum = array[0];
    
        for (int i = 1; i < array.Length; i++)
        {
            sum = Max(sum + array[i], array[i]);
            Maxsum = Max(sum, Maxsum);               
        }
    
        Console.WriteLine("Maximum sum is: " + Maxsum);
    }
    
    private static int Max(int a, int b)
    {
        return a > b ? a : b;
    }
    
    Arrays.sort(a, Collections.reverseOrder());
    int sum = 0;
    for (int i = 0; i < a.length; i++) {
     sum = sum + a[i];
         if (sum > maxSum) 
             maxSum = sum;
    }
    System.out.println(maxSum);