最小切片位置 - 阶 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 > c
、(b+c)/2 > 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 算法的主要内容,如果未能解决你的问题,请参考以下文章
寻找旋转排序数组中的最小值 II(数组二分查找)打印1000以内的所有素数,并从键盘输入一个正整数,判断是否为素数数组元素统计(算法初阶基础知识)