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.


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值