Codility-Peak

Task description

A non-empty zero-indexed array A consisting of N integers is given.

peak is an array element which is larger than its neighbors. More precisely, it is an index P such that 0 < P < N − 1,  A[P − 1] < A[P] and A[P] > A[P + 1].

For example, the following array A:

    A[0] = 1
    A[1] = 2
    A[2] = 3
    A[3] = 4
    A[4] = 3
    A[5] = 4
    A[6] = 1
    A[7] = 2
    A[8] = 3
    A[9] = 4
    A[10] = 6
    A[11] = 2

has exactly three peaks: 3, 5, 10.

We want to divide this array into blocks containing the same number of elements. More precisely, we want to choose a number K that will yield the following blocks:

  • A[0], A[1], ..., A[K − 1],
  • A[K], A[K + 1], ..., A[2K − 1],
    ...
  • A[N − K], A[N − K + 1], ..., A[N − 1].

What's more, every block should contain at least one peak. Notice that extreme elements of the blocks (for example A[K − 1] or A[K]) can also be peaks, but only if they have both neighbors (including one in an adjacent blocks).

The goal is to find the maximum number of blocks into which the array A can be divided.

Array A can be divided into blocks as follows:

  • one block (1, 2, 3, 4, 3, 4, 1, 2, 3, 4, 6, 2). This block contains three peaks.
  • two blocks (1, 2, 3, 4, 3, 4) and (1, 2, 3, 4, 6, 2). Every block has a peak.
  • three blocks (1, 2, 3, 4), (3, 4, 1, 2), (3, 4, 6, 2). Every block has a peak. Notice in particular that the first block (1, 2, 3, 4) has a peak at A[3], because A[2] < A[3] > A[4], even though A[4] is in the adjacent block.

However, array A cannot be divided into four blocks, (1, 2, 3), (4, 3, 4), (1, 2, 3) and (4, 6, 2), because the (1, 2, 3) blocks do not contain a peak. Notice in particular that the (4, 3, 4) block contains two peaks: A[3] and A[5].

The maximum number of blocks that array A can be divided into is three.

Write a function:

int solution(vector<int> &A);

that, given a non-empty zero-indexed array A consisting of N integers, returns the maximum number of blocks into which A can be divided.

If A cannot be divided into some number of blocks, the function should return 0.

For example, given:

    A[0] = 1
    A[1] = 2 
    A[2] = 3 
    A[3] = 4 
    A[4] = 3 
    A[5] = 4 
    A[6] = 1 
    A[7] = 2 
    A[8] = 3 
    A[9] = 4 
    A[10] = 6 
    A[11] = 2

the function should return 3, as explained above.

Assume that:

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

Complexity:

  • expected worst-case time complexity is O(N*log(log(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.

思路:先求出第i个元素之前的peak数peakSum和相邻peak间的最大距离maxD,则最小分割长度的值可能在[maxD/2,N)之间:

1.当maxD大于N/2时,则显然只能分为两部分;

2.当k大于maxD时,k只要能被N整除即是可能解;

3.当k小于等于maxD时,若存在某个分组中无peak,则k不是可能解;

代码:

// you can use includes, for example:
 #include 
   
   
    
    

// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;

int solution(vector
    
    
     
      &A) {
    // write your code in C++11
    int maxD = 0;//相邻peak间的最大距离
    int N = A.size();
    vector
     
     
      
       peakSum(N+1,0);//存储第i个元素(不含)之前的peak数量
    int lastpeak = -1;//考虑第一个peak到数组最前端的距离
    for(int i=1;i
      
      
       
       A[i-1]&&A[i]>A[i+1])
        {
            peakSum[i+1] = peakSum[i] + 1;
            maxD = max(maxD,i - lastpeak);
            lastpeak = i;
        }
        else
        {
            peakSum[i+1] = peakSum[i];
        }
    }
    peakSum[N]=peakSum[N-1];
    if(peakSum[N]==0)//若第N个元素之前无peak,则返回0
    return 0;
    maxD = max(maxD,N - lastpeak);//考虑最后一个peak到尾部的距离
    if(maxD > N/2)//若相邻两peak间最大距离超过N/2,则必然只能分为两部分
    return 1;
    for(int k = maxD/2;k<=maxD;++k)
    {
        if(N%k==0)
        {
            bool isvalid = true;
            int c = N/k;
            for(int i=1;i<=c;++i)
            {
                if(peakSum[i*k]==peakSum[(i-1)*k])//若数组拆分后第i部分之前和第i-1部分之前peak数一样
                                                  //则第i部分无peak,方案不合理
                isvalid = false;
            }
            if(isvalid)
            return c;
        }
    }
    for(int k = maxD+1;;k++)//若每部分的长度k大于maxD+1,则只要k能被N整除,这种划分就是合理的
    {
        if(N%k==0) return N/k;
    }
}

      
      
     
     
    
    
   
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值