Arrays 每个k=1..n的大小为k的所有子阵列的最大和

Arrays 每个k=1..n的大小为k的所有子阵列的最大和,arrays,algorithm,data-structures,dynamic-programming,interval-tree,Arrays,Algorithm,Data Structures,Dynamic Programming,Interval Tree,给定一个大小为n的数组,对于从1到n的每个k,求大小为k的相邻子数组的最大和 该问题具有明显的时间复杂度O(N2)和O(1)空间解。Lua代码: array = {7, 1, 3, 1, 4, 5, 1, 3, 6} n = #array function maxArray(k) ksum = 0 for i = 1, k do ksum = ksum + array[i] end max_ksum = ksum for i = k +

给定一个大小为n的数组,对于从1到n的每个k,求大小为k的相邻子数组的最大和

该问题具有明显的时间复杂度O(N2)和O(1)空间解。Lua代码:

array = {7, 1, 3, 1, 4, 5, 1, 3, 6}
n = #array

function maxArray(k)
    ksum = 0
    for i = 1, k do
        ksum = ksum + array[i]
    end
    max_ksum = ksum
    for i = k + 1, n do
        add_index = i
        sub_index = i - k
        ksum = ksum + array[add_index] - array[sub_index]
        max_ksum = math.max(ksum, max_ksum)
    end
    return max_ksum
end

for k = 1, n do
    print(k, maxArray(k))
end
有没有时间复杂度更低的算法?例如,O(N logn)+额外的内存

相关主题:


    • 下面的流程可能会对您有所帮助

      1) 选择前k个元素并创建大小为k的自平衡二叉搜索树(BST)

      2) 在i=0到n–k之间运行一个循环

      ..…a)从BST获取最大元素,并打印它

      ..…b)在BST中搜索arr[i]并将其从BST中删除

      ..…c)将arr[i+k]插入BST

      时间复杂性:
      步骤1的时间复杂度为O(kLogk)。步骤2(a)、2(b)和2(c)的时间复杂度为O(Logk)。由于步骤2(a)、2(b)和2(c)在一个循环中运行n-k+1次,所以完整算法的时间复杂度为O(kLogk+(n-k+1)*Logk,也可以写成O(nLogk)。

      如果不添加任何其他约束,我认为没有比O(n²)更有效的解决方案。换句话说,除了探索所有其他子阵列之外,没有其他方法可以确定您已经找到了最大和子阵列

      因此,最不复杂的解决方案由O(N²/2)组成,O(N²/2)是给定长度N的阵列的连续子阵列的总数

      就我个人而言,我将用动态规划方法实现这一点。其想法是使用一个楔形的部分结果,并使用它们来构建子阵列的当前和(代替通过计算整个和)。无论如何,这只提供了一个恒定的加速比,因此复杂度是O(N²/2)~O(N²)

      以下是伪代码-很抱歉没有说Lua

      // here we place temporary results, row by row alternating in 0 or 1
      int[2][N] sum_array_buffer
      // stores the start of the max subarray
      int[N] max_subarray_start
      // stores the value
      int[N] max_subarray_value
      
      array = {7, 1, 3, 1, 4, 5, 1, 3, 6}
      // we initialize the buffer with the array (ideally 1-length subarrays)
      sum_array_buffer[1] = array
      // the length of subarrays - we can also start from 1 if considered
      for k = 1 ; k <= (N); ++k:
          // the starting position fo the sub-array
          for j = 0; j < (N-k+1); ++j:
              sum_array_buffer[k%2][j] = sum_array_buffer[(k+1)%2][j] + array[j+k-1]
              if j == 0 || sum_array_buffer[k%2][j] > max_subarray_value[k]:
                  max_subarray_value = sum_array_buffer[k%2][j]
                  max_subarray_start[k] = j
      
      
      for k = 1 ; k <= (N); ++k:
          print(k, max_subarray_value[k])
      
      //这里我们放置临时结果,在0或1中逐行交替
      int[2][N]和数组缓冲区
      //存储最大子阵列的开始
      int[N]最大子阵列开始
      //存储值
      int[N]最大子数组值
      数组={7,1,3,1,4,5,1,3,6}
      //我们使用数组初始化缓冲区(理想情况下为1个长度的子数组)
      和数组缓冲区[1]=数组
      //子阵列的长度-如果考虑的话,我们也可以从1开始
      对于k=1;k最大子阵列值[k]:
      最大子数组值=和数组缓冲区[k%2][j]
      最大子阵列开始[k]=j
      
      对于k=1;k我们创建一个队列,即容量为k的Qi,它只存储当前k元素窗口中的有用元素。如果某个元素位于当前窗口中且大于当前窗口中该元素左侧的所有其他元素,则该元素非常有用。我们逐个处理所有数组元素,并维护Qi以包含当前窗口的有用元素,这些有用元素按排序顺序进行维护。Qi前面的元素是当前窗口中最大的元素,Qi后面的元素是最小的元素。

      该问题可以归结为最小和问题,请参见中的第2.4节(MCSP)。因此,目前您可以预期的最佳复杂性可能是O(n^2/polylog(n))。

      intmaxcrossingsum(intarr[],intl,intm,inth)
      { 
      //在mid的左侧包含元素。
      整数和=0;
      int left_sum=int_MIN;
      对于(int i=m;i>=l;i--)
      { 
      总和=总和+arr[i];
      如果(总和>左总和)
      左和=和;
      } 
      //包括中间右侧的元素
      总和=0;
      int right_sum=int_MIN;
      for(int i=m+1;i右和)
      右和=和;
      } 
      //返回mid左侧和右侧元素的总和
      返回左求和+右求和;
      } 
      //返回aa[l..h]中最大和子数组的和
      整数最大子数组和(整数arr[],整数l,整数h)
      { 
      //基本情况:只有一个元素
      如果(l==h)
      返回arr[l];
      //找到中间点
      int m=(l+h)/2;
      /*最多返回以下三种可能的情况
      a) 左半部分的最大子数组和
      b) 右半部分的最大子数组和
      c) 使子阵列穿过中点的最大子阵列和*/
      返回最大值(最大子阵列和(arr,l,m),
      最大子阵列和(arr,m+1,h),
      maxCrossingSum(arr,l,m,h));
      } 
      
      解释

      使用分治方法,我们可以在O(nLogn)时间内找到最大子阵和。下面是分治算法

      1) 将给定数组分成两半

      2) 返回以下三个值中的最大值

      ..a)左半部分的最大子数组和(进行递归调用)

      ..b)右半部分的最大子数组和(进行递归调用)


      请在这里找到代码

       class Program
          {
              static void Main(string[] args)
              {
                  int sum=0;
                  int max=0;
                  int size=9;
                 string input="7, 1, 3, 1, 4, 5, 1, 3, 6";
                 string[] values=input.Split(',');
                 int length=values.Length;
                 int k=size-1;
                 for(int i=0;i<=k;i++)
                 {
                   sum=sum+int.Parse(values[i]);
                   max=sum;
                 }
                 for(int j=0;k<length-1;j++)
                 {
                     ++k;
                  sum=(sum-int.Parse(values[j]))+int.Parse(values[k]);
                  if(sum>max)
                  max=sum;
                 }
                 Console.WriteLine(max);
              }
          }
      
      类程序
      {
      静态void Main(字符串[]参数)
      {
      整数和=0;
      int max=0;
      int size=9;
      字符串输入=“7,1,3,1,4,5,1,3,6”;
      string[]value=input.Split(',');
      int length=values.length;
      int k=尺寸-1;
      
      对于(int i=0;i一个有效的解决方案是基于这样一个事实,即大小为k的子阵列(或窗口)的和可以使用前一个子阵列(或窗口)的和在O(1)时间内获得大小为k。除了大小为k的第一个子数组外,对于其他子数组,我们通过删除最后一个窗口的第一个元素并添加当前窗口的最后一个元素来计算总和

      下面是相同的实现

      int maxSum(int arr[], int n, int k) 
      { 
      // k must be greater 
      if (n < k) 
      { 
         cout << "Invalid"; 
         return -1; 
      } 
      
      // Compute sum of first window of size k 
      int res = 0; 
      for (int i=0; i<k; i++) 
         res += arr[i]; 
      
      // Compute sums of remaining windows by 
      // removing first element of previous 
      // window and adding last element of  
      // current window. 
      int curr_sum = res; 
      for (int i=k; i<n; i++) 
      { 
         curr_sum += arr[i] - arr[i-k]; 
         res = max(res, curr_sum); 
      } 
      
      return res; 
       } 
      
      intmaxsum(intarr[],intn,intk)
      { 
      //k必须更大
      if(n当对每个
      k=1,…,n
      进行计算时,它是
      O(n^2logn)
      。比OP的解差。使用滑动窗口在O(n)中找到k个相邻元素的最高和。不需要
      O(nlogk)
      树解。-1.我可以解决O(n)中固定k的子问题问题的关键是,从1到n的每个k都需要最大和的k子阵。
       class Program
          {
              static void Main(string[] args)
              {
                  int sum=0;
                  int max=0;
                  int size=9;
                 string input="7, 1, 3, 1, 4, 5, 1, 3, 6";
                 string[] values=input.Split(',');
                 int length=values.Length;
                 int k=size-1;
                 for(int i=0;i<=k;i++)
                 {
                   sum=sum+int.Parse(values[i]);
                   max=sum;
                 }
                 for(int j=0;k<length-1;j++)
                 {
                     ++k;
                  sum=(sum-int.Parse(values[j]))+int.Parse(values[k]);
                  if(sum>max)
                  max=sum;
                 }
                 Console.WriteLine(max);
              }
          }
      
      int maxSum(int arr[], int n, int k) 
      { 
      // k must be greater 
      if (n < k) 
      { 
         cout << "Invalid"; 
         return -1; 
      } 
      
      // Compute sum of first window of size k 
      int res = 0; 
      for (int i=0; i<k; i++) 
         res += arr[i]; 
      
      // Compute sums of remaining windows by 
      // removing first element of previous 
      // window and adding last element of  
      // current window. 
      int curr_sum = res; 
      for (int i=k; i<n; i++) 
      { 
         curr_sum += arr[i] - arr[i-k]; 
         res = max(res, curr_sum); 
      } 
      
      return res; 
       }