最小切片位置 - 阶 N 算法

Posted

技术标签:

【中文标题】最小切片位置 - 阶 N 算法【英文标题】:minimum slice position - Order N algorithm 【发布时间】:2015-07-30 21:17:27 【问题描述】:

给出了一个由 N 个整数组成的非空零索引数组 A。一对整数 (P, Q),使得 0 ≤ P

写一个函数:

int 解(int A[], int N);

给定一个由 N 个整数组成的非空零索引数组 A,返回具有最小平均值的切片的起始位置。 如果有多个切片具有最小平均值,则应返回该切片的最小起始位置。

假设:

N 是 [2..100,000] 范围内的整数; 数组 A 的每个元素都是 [−10,000..10,000] 范围内的整数。 复杂性:

预期的最坏情况时间复杂度为 O(N); 预期的最坏情况空间复杂度为 O(N),超出输入存储(不计算输入参数所需的存储)。

你能只发布订单 N 的解决方案吗?

【问题讨论】:

A中的整数都是正数吗? 不一定,我加了更多信息 我确信没有 N 阶解决方案 【参考方案1】:

如果A 仅有正数,您可以不用这样:

pos = 0
min_avg = A[0] + A[1]
for (i=2; i<N; i++)
    m = A[i-1] + A[i]
    if (m < min_avg)
        min_avg = m
        pos = i-1
return pos

这只是取两个数字的切片的平均值,因为较大切片的平均值不能小于较小切片的最小值。

如果A有负数,你可以先向上调整所有值:

offset = min(A)
for (i=0; i<N; i++)
    A[i] -= offset

结合之前的算法:

offset = min(A) * 2              (because we're adding two numbers below)
pos = 0
min_avg = A[0] + A[1] - offset
for (i=2; i<N; i++)
    m = A[i-1] + A[i] - offset
    if (m < min_avg)
        min_avg = m
        pos = i-1
return pos

【讨论】:

“较大切片的平均值不能小于较小切片的最小值。”我不确定你的意思是什么。当你取所有东西时,[1,10,1] 有其最小平均值,而不是更小的切片。 @Teepeemm 你是对的,在某些情况下,较大的切片可能具有较小的平均值,但这些情况并不常见。请看我的其他回答。 具体来说,对于一个三数序列[a, b, c],它必须满足:(a+b)/2 &gt; c(b+c)/2 &gt; a(a+b+c)/3 小于任何其他平均值。 考虑到这一点,我认为这个想法是正确的。您只需检查所有长度为 3 的切片以及长度为 2 的切片。【参考方案2】:

我认为你是对的,我能做的最好的就是 O(N2) 解决方案(这是在 Python 中):

from random import randint

N = 1000
A = [randint(-10000, 10000) for _ in xrange(N)]

def solution(A, N):
    min_avg = 10001
    for p in xrange(N):
        s = A[p]
        for q in xrange(1,N-p):
            s += A[p+q]
            a = s / (q+1.)
            if a < min_avg:
                min_avg = a
                pos = (p, q+1)
    return pos

print solution(A, N)

但是,较大切片的平均值倾向于原始范围的平均值(中间)。在这种情况下,平均值为零,介于 -10000 和 10000 之间。大多数情况下,最小的平均值是两个值的切片,但有时它可以是三个值的切片,很少是更多值.所以我认为我之前的答案在大多数(> 90%)的情况下都有效。这真的取决于数据值。

【讨论】:

【参考方案3】:
    #include <assert.h>
    struct Slice  unsigned P, Q; ;
    struct Slice MinSlice( int A[], unsigned N ) 
        assert( N>=2 );
        // find min slice of length 2
        unsigned P = 0;
        double min_sum = A[P] + A[P+1];
        for (unsigned i = 1; i < N-1; ++i)
            if ( min_sum > A[i] +A[i+1] ) 
                P = i;
                min_sum = A[P] + A[P+1];
            
        unsigned Q = P+1;
        double min_avg = min_sum / 2;
        //extend the min slice if the avg can be reduced.
        //(in the direction that most reduces the avg)
        for (;;) 
            if ( P > 0 && ( Q >= N-1 || A[P-1] <= A[Q+1] ) ) 
                //reducing P might give the best reduction in avg
                double new_sum = A[P-1] + min_sum;
                double new_avg = new_sum / (Q - P + 2);
                if ( min_avg < new_avg )
                    break;
                min_sum = new_sum; 
                min_avg = new_avg; 
                --P;
              else if ( Q < N-1 && ( P <= 0 || A[P-1] >= A[Q+1] ) ) 
                //increasing Q might give the best reduction in avg
                double new_sum = min_sum + A[Q+1];
                double new_avg = new_sum / (Q - P + 2);
                if ( min_avg < new_avg )
                    break;
                min_sum = new_sum; 
                min_avg = new_avg; 
                ++Q;
              else
                 break;
        
        struct Slice slice =  .P = P, .Q= Q ;
        return slice;
    

【讨论】:

请解释一下。

以上是关于最小切片位置 - 阶 N 算法的主要内容,如果未能解决你的问题,请参考以下文章

C——幻方算法

寻找旋转排序数组中的最小值 II(数组二分查找)打印1000以内的所有素数,并从键盘输入一个正整数,判断是否为素数数组元素统计(算法初阶基础知识)

深度学习的优化算法

[算法]在数组中找到一个局部最小的位置

常用算法的时间复杂度分析

数据结构与算法入门