Codility Lesson 3 MinAvgTwoSlice解答

本文探讨了一个算法问题,目标是在给定数组中找到具有最小平均数的连续子数组,通过数学证明和简单算法实现,解决复杂度限制下的高效搜索策略。

*大多数朋友如果找到这篇文章,就是来看解答的,所以完整的题目放到文章的最后了。


思路:

1、首先根据题目,大家第一反应就是无脑嵌套遍历所有情况,这样的时间复杂度是O(n^2+n)/2,远远超出O(n)的题目里的要求。

2、其次就是找规律了,这个slice一定发生在最小值周围吗?不一定!比如[-1, -1, 12, -9, 10]。所以不用去思考先找到最小值,再向两边递归的思路了。

3、其实,这里有一个数学证明,就是对于这个最小avg的slice(n,m),m-n+1一定是2或者3,也就是这个最小avg的slice由2个或者3个元素组成。

4、说说为什么会想到上面这个思路:因为题目中说明0<=n<m<N,因此可以得出2个或者3个元素是最小的组合,比如length=3的数组,你无法一次分出2个slice,length=2的数组也一样。为什么要这么去想呢?因为你要“比较”出最小的avg,怎么才能“比较”?那就是必须一次至少有2个slice才能相互比较。那么当N>=4时,我们就能一次最少分出2个slice。举length=4的例子,情况有以下几种:slice(0,1) slice(1,2) slice(2,3) slice(0,2) slice(1,3) slice(0,3)。可以看出前3个是2个元素的slice,后4-6个是3个元素的slice,最后一个是4个元素的slice。再来回想以下我们的命题,就是“min avg一定存在2/3个元素的slice中”,那么反过来就是length>=4的slice一定不是min avg。这个结论是肯定的,因为当元素>=4个时,我们把它分为2个sliceA sliceB,这两个slice肯定有一个大于另一个,或者2个相等。那么我们得出结论当sliceA>sliceB时,取sliceB为当前min avg的slice(反之亦然),当sliceA=sliceB时,则sliceA和sliceB都为当前min avg的slice。显然,原始slice已经被拆分了,它的存在是不正确的(子slice更优)或者是可被替代的(子slice和它相等)。如此继续拆分slice直到,length=2或者3时,我们就无法确定这个slice不是最优的,因此要去计算和记录它,并和其他slice的比较。

5、得到这个结论后,算法就变得异常简单,就是遍历数组,求连续2或者3个元素的avg,直接看到代码吧!


class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        double min = 10001;
        int minIndex = -1;
        for (int i = 0; i < A.length - 1; i ++) {
            double current2 = (A[i] + A[i + 1]) / 2d;
            if (current2 < min) {
                min = current2;
                minIndex = i;
            }
            
            if (i != A.length - 2) {
                double current3 = (A[i] + A[i + 1] + A[i + 2]) / 3d;
                if (current3 < min) {
                    min = current3;
                    minIndex = i;
                } 
            }
        }
        
        return minIndex;
    }
}


下面是原题:

Task description

A non-empty zero-indexed array A consisting of N integers is given. A pair of integers (P, Q), such that 0 ≤ P < Q < N, is called a slice of array A (notice that the slice contains at least two elements). The average of a slice (P, Q) is the sum of A[P] + A[P + 1] + ... + A[Q] divided by the length of the slice. To be precise, the average equals (A[P] + A[P + 1] + ... + A[Q]) / (Q − P + 1).

For example, array A such that:

    A[0] = 4
    A[1] = 2
    A[2] = 2
    A[3] = 5
    A[4] = 1
    A[5] = 5
    A[6] = 8

contains the following example slices:

  • slice (1, 2), whose average is (2 + 2) / 2 = 2;
  • slice (3, 4), whose average is (5 + 1) / 2 = 3;
  • slice (1, 4), whose average is (2 + 2 + 5 + 1) / 4 = 2.5.

The goal is to find the starting position of a slice whose average is minimal.

Write a function:

class Solution { public int solution(int[] A); }

that, given a non-empty zero-indexed array A consisting of N integers, returns the starting position of the slice with the minimal average. If there is more than one slice with a minimal average, you should return the smallest starting position of such a slice.

For example, given array A such that:

    A[0] = 4
    A[1] = 2
    A[2] = 2
    A[3] = 5
    A[4] = 1
    A[5] = 5
    A[6] = 8

the function should return 1, as explained above.

Assume that:

  • N is an integer within the range [2..100,000];
  • each element of array A is an integer within the range [−10,000..10,000].

Complexity:

  • expected worst-case time complexity is O(N);
  • expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).

Elements of input arrays can be modified.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值