13

我正在尝试解决最新的 codility.com 问题(只是为了提高我的技能)。我尝试了分配但没有得到超过 30 分,所以现在很好奇我的解决方案中到底缺少什么。

问题说

给出了一个由 N 个整数组成的非空零索引数组 A。一个峰值是一个数组元素,它比它的邻居大。更准确地说,它是一个索引 P 使得

0 < P < N − 1 and A[P − 1] < A[P] > A[P + 1]

例如下面的数组 A:

A[0] = 1 
A[1] = 5 
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

恰好有四个峰:元素 1、3、5 和 10。

您将前往一系列山脉,其相对高度由数组 A 表示。您必须选择随身携带的旗帜数量。目标是根据某些规则在峰上设置最大数量的标志。

标志只能设置在峰上。更重要的是,如果你取K个标志,那么任何两个标志之间的距离应该大于或等于K。索引P和Q之间的距离是绝对值|P-Q|。

例如,给定上面数组 A 表示的山脉,N = 12,如果你取:

> two flags, you can set them on peaks 1 and 5; 

> three flags, you can set them on peaks 1, 5 and 10; 

> four flags, you can set only three flags, on peaks 1, 5 and 10.

因此,在这种情况下,您最多可以设置三个标志。

编写一个函数,给定一个由 N 个整数组成的非空零索引数组 A,返回可以在数组峰值上设置的最大标志数。例如,给定上面的数组

如上所述,该函数应返回 3。

假使,假设:

N 是 [1..100,000] 范围内的整数;

数组 A 的每个元素都是 [0..1,000,000,000] 范围内的整数。

复杂:

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

所以我根据我对问题的理解尝试了这段代码

var A = [1,5,3,4,3,4,1,2,3,4,6,2];

function solution(A) {
 array = new Array();  
   for (i = 1; i < A.length - 1; i++) {  
    if (A[i - 1] < A[i] && A[i + 1] < A[i]) {  
     array.push(i);  
    }  
   }  

  //console.log(A);
  //console.log(array);
  var position = array[0];
  var counter = 1;
  var len = array.length;
  for (var i = 0; i < len; i++) {
    if (Math.abs(array[i+1] - position) >= len) {
        position = array[i+1];
        counter ++;
        }
    }

  console.log("total:",counter);
  return counter;

}

上面的代码适用于示例数组元素:[1,5,3,4,3,4,1,2,3,4,6,2] Get peaks at indices: [1, 3, 5, 10]and set flags at1, 5, and 10 (total 3)

但是 codility.com 说它在数组上失败[7, 10, 4, 5, 7, 4, 6, 1, 4, 3, 3, 7] 我的代码在索引处达到峰值:[1, 4, 6, 8]并在 1 和 6 处设置标志(总共 2 个),但 coditity.com 说它应该是 3 个标志。(不知道为什么)我是否误解了这个问题?

请我只是在寻找提示/算法。我知道有人已经问过这个问题并在私人聊天室中解决了,但在那个页面上,我试图向那个人寻求帮助,但成员们宁愿将我的帖子标记为不恰当的答案,所以我再次在这里问这个问题。

PS:您可以在这里尝试自己编写挑战!

4

21 回答 21

5

这是一个具有更好的上限复杂度的解决方案:

  • 时间复杂度:O(sqrt(N) * log(N))
  • 空间复杂度:(O(1)超过原始输入存储)

Python 实现

from math import sqrt

def transform(A):
    peak_pos = len(A)
    last_height = A[-1]
    for p in range(len(A) - 1, 0, -1):
        if (A[p - 1] < A[p] > last_height):
            peak_pos = p
        last_height = A[p]
        A[p] = peak_pos
    A[0] = peak_pos

def can_fit_flags(A, k):
    flag = 1 - k
    for i in range(k):
        # plant the next flag at A[flag + k]
        if flag + k > len(A) - 1:
            return False
        flag = A[flag + k]
    return flag < len(A)  # last flag planted successfully

def solution(A):
    transform(A)
    lower = 0
    upper = int(sqrt(len(A))) + 2
    assert not can_fit_flags(A, k=upper)
    while lower < upper - 1:
        next = (lower + upper) // 2
        if can_fit_flags(A, k=next):
            lower = next
        else:
            upper = next
    return lower

描述

O(N)预处理(就地完成):

A[i] := next peak or end position after or at position i
        (i for a peak itself, len(A) after last peak)

如果我们可以插k旗,那么我们当然也可以插k' < k旗。如果我们不能插k旗,那我们当然也不能插k' > k旗。我们总是可以设置 0 个标志。让我们假设我们不能设置X标志。现在我们可以使用二分搜索来准确找出可以种植多少个标志。

Steps:
  1. X/2
  2. X/2 +- X/4
  3. X/2 +- X/4 +- X/8
  ...
  log2(X) steps in total

通过之前的预处理,k可以在操作中执行每个测试是否可以种植标志的步骤O(k)

  • 标志(0)=下一个(0)
  • 标志(1) = 下一个(标志(1) + k) ...
  • 标志(k-1)=下一个(标志(k-2)+ k)

总成本 - 最坏情况 -X - 1可以种植旗帜时:

== X * (1/2 + 3/4 + ... + (2^k - 1)/(2^k))
== X * (log2(X) - 1 + (<1))
<= X * 日志(X)

使用X == N会起作用,并且很可能也是次线性的,但不足以用于证明该算法的总上限低于O(N).

现在一切都取决于找到一个好的X,并且由于k标志占据了k^2适合的位置,似乎应该在某个地方找到一个很好的标志数量上限sqrt(N)

如果X == sqrt(N)或接近它的东西有效,那么我们得到一个O(sqrt(N) * log(sqrt(N)))绝对是次线性的上限,因为log(sqrt(N)) == 1/2 * log(N)该上限等于O(sqrt(N) * log(N))

让我们寻找一个更精确的关于所需标志数量的上限sqrt(N)

  • 我们知道k标志需要Nk := k^2 - k + 3标志
  • 通过求解等式k^2 - k + 3 - N = 0k我们发现如果k >= 3,则任意数量的标志 <= 结果k可以适合某个长度为 N 的序列,而更大的则不能;该方程的解是1/2 * (1 + sqrt(4N - 11))
  • 因为N >= 9我们知道我们可以容纳 3 个标志 ==> 对于N >= 9,k = floor(1/2 * (1 + sqrt(4N - 11))) + 1是我们可以容纳的标志数量的严格上限N
  • 因为N < 9我们知道 3 是一个严格的上限,但是这些情况并不关心我们找到大 O 算法的复杂度

地板(1/2 * (1 + sqrt(4N - 11))) + 1
== 地板(1/2 + sqrt(N - 11/4)) + 1
<= 地板(sqrt(N - 11/4) ) + 2
<= 楼层(sqrt(N)) + 2

==>floor(sqrt(N)) + 2对于许多可以放入元素的标志也是一个很好的严格上限N+ 这个甚至适用于N < 9所以它也可以在我们的实现中用作通用的严格上限

如果我们选择X = floor(sqrt(N)) + 2,我们会得到以下总算法上限:

O((floor(sqrt(N)) + 2) * log(floor(sqrt(N)) + 2))
   {floor(...) <= ...}
O((sqrt(N) + 2) * log(sqrt(N) + 2))
   {for large enough N >= 4: sqrt(N) + 2 <= 2 * sqrt(N)}
O(2 * sqrt(N) * log(2 * sqrt(N)))
   {lose the leading constant}
O(sqrt(N) * (log(2) + loq(sqrt(N)))
O(sqrt(N) * log(2) + sqrt(N) * log(sqrt(N)))
   {lose the lower order bound}
O(sqrt(N) * log(sqrt(N)))
   {as noted before, log(sqrt(N)) == 1/2 * log(N)}
O(sqrt(N) * log(N))
                                  QED
于 2014-11-09T00:13:45.553 回答
3
import java.util.Arrays;
import java.lang.Integer;
import java.util.ArrayList;
import java.util.List;
public int solution(int[] A) 
{
    ArrayList<Integer> array = new ArrayList<Integer>();  
        for (int i = 1; i < A.length - 1; i++) 
        {  
            if (A[i - 1] < A[i] && A[i + 1] < A[i]) 
            {  
                array.add(i);  
            }  
        }  
   if (array.size() == 1 || array.size() == 0) 
   {  
        return array.size();  
   }  
    int sf = 1;  
    int ef = array.size();  
    int result = 1;  
    while (sf <= ef) 
    {  
        int flag = (sf + ef) / 2;  
        boolean suc = false;  
        int used = 0;  
        int mark = array.get(0);  
        for (int i = 0; i < array.size(); i++) 
        {  
            if (array.get(i) >= mark) 
            {  
                used++;  
                mark = array.get(i) + flag;  
                    if (used == flag) 
                    {                       
                        suc = true;  
                        break;  
                    }  
            }  
        }  
        if (suc) 
        {  
            result = flag;  
            sf = flag + 1;  
        } 
        else 
        {  
            ef = flag - 1;  
        }  
    }  
   return result;  
 }
于 2013-10-24T13:37:11.423 回答
3

缺少 100% PHP 解决方案 :)

function solution($A)
{
    $p = array(); // peaks
    for ($i=1; $i<count($A)-1; $i++)
        if ($A[$i] > $A[$i-1] && $A[$i] > $A[$i+1])
            $p[] = $i;

    $n = count($p);
    if ($n <= 2)
        return $n;

    $maxFlags = min(intval(ceil(sqrt(count($A)))), $n); // max number of flags
    $distance = $maxFlags; // required distance between flags
    // try to set max number of flags, then 1 less, etc... (2 flags are already set)
    for ($k = $maxFlags-2; $k > 0; $k--)
    {
        $left = $p[0];
        $right = $p[$n-1];
        $need = $k; // how many more flags we need to set

        for ($i = 1; $i<=$n-2; $i++)
        {
            // found one more flag for $distance
            if ($p[$i]-$left >= $distance && $right-$p[$i] >= $distance)
            {
                if ($need == 1)
                    return $k+2;
                $need--;
                $left = $p[$i];
            }

            if ($right - $p[$i] <= $need * ($distance+1))
                break; // impossible to set $need more flags for $distance
        }

        if ($need == 0)
            return $k+2;

        $distance--;
    }
    return 2;
}
于 2013-10-31T09:19:35.720 回答
2

具有 O(N) 复杂度的 100% Java 解决方案。

https://app.codility.com/demo/results/trainingPNYEZY-G6Q/

class Solution {
    public int solution(int[] A) {
        // write your code in Java SE 8
        int[] peaks = new int[A.length];
        int peakStart = 0;
        int peakEnd = 0;
        
        //Find the peaks.
        //We don't want to traverse the array where peaks hasn't started, yet, 
        //or where peaks doesn't occur any more.
        //Therefore, find start and end points of the peak as well.
        for(int i = 1; i < A.length-1; i++) {
            if(A[i-1] < A[i] && A[i+1] < A[i]) {
                peaks[i] = 1;
                peakEnd = i + 1;
            }
            if(peakStart == 0) {
                peakStart = i;
            }
        }
        
        int x = 1;
        //The maximum number of flags can be √N
        int limit = (int)Math.ceil(Math.sqrt(A.length));
        int prevPeak = 0;
        int counter = 0;
        int max = Integer.MIN_VALUE;
        
        while(x <= limit) {
            counter = 0;
            prevPeak = 0;
            for(int y = peakStart; y < peakEnd; y++) {
                //Find the peak points when we have x number of flags.
                if(peaks[y] == 1 && (prevPeak == 0 || x <= (y - prevPeak))) {
                    counter++;
                    prevPeak = y;
                }
                //If we don't have any more flags stop.
                if(counter == x ) {
                    break;
                }
            }
            //if the number of flags set on the peaks starts to reduce stop searching.
            if(counter <= max) {
                return max;
            }
            //Keep the maximum number of flags we set on.
            max = counter;
            x++;
        }
        return max;
    }
}
  • 我们可以随身携带的标志数量与我们可以设置的标志数量之间存在比率。我们不能设置超过 √N 个标志,因为 N/√N = √N。如果我们设置超过 √N,我们最终会在峰值上设置的标志数量减少。

  • 当我们增加随身携带的标志数量时,我们可以设置的标志数量会增加到一个点。在那之后,我们可以设置的标志数量将减少。因此,当我们可以设置的标志数量开始减少一次时,我们不必检查其余可能的解决方案。

  • 我们在代码的开头标记了峰值点,我们也标记了第一个和最后一个峰值点。这减少了不必要的检查,其中峰值从大数组的最后一个元素开始,或者最后一个峰值出现在大数组的第一个元素处。

于 2020-07-11T12:35:10.687 回答
2

C++ 解决方案,检测到 O(N)

#include <algorithm>

int solution(vector<int> &a) {

    if(a.size() < 3) return 0;

    std::vector<int> peaks(a.size());

    int last_peak = -1;

    peaks.back() = last_peak;

    for(auto i = ++a.rbegin();i != --a.rend();i++)
    {

        int index = a.size() - (i - a.rbegin()) - 1;
        if(*i > *(i - 1) && *i > *(i + 1))
            last_peak = index;
        peaks[index] = last_peak;
    }

    peaks.front() = last_peak;

    int max_flags = 0;

    for(int i = 1;i*i <= a.size() + i;i++)
    {
        int next_peak = peaks[0];
        int flags = 0;
        for(int j = 0;j < i && next_peak != -1;j++, flags++)
        {               
            if(next_peak + i >= a.size())
                next_peak = -1;
            else
                next_peak = peaks[next_peak + i];            
        }
        max_flags = std::max(max_flags, flags);
    }

    return max_flags;

}
于 2016-04-17T15:21:03.653 回答
1

这是一个得分为 100% 的 C++ 解决方案

int test(vector<int> &peaks,int i,int n)
{
int j,k,sum,fin,pos;

fin =  n/i;
for (k=0; k< i; k++) 
{
     sum=0;
     for (j=0; j< fin; j++) 
     {   pos = j + k * fin;
         sum=sum + peaks[ pos  ];        
     }
     if (0==sum) return 0;
}   
return 1;   
}

int solution(vector<int> &A) {
// write your code in C++98 
int i,n,max,r,j,salir;
n = A.size();  
vector<int> peaks(n,0);

if (0==n) return 0;
if (1==n) return 0;

for (i=1; i< (n-1) ; i++)
{     
    if (  (A[i-1] < A[i]) && (A[i+1] < A[i]) ) peaks[i]=1;   
}
i=1;
max=0;
salir =0;
while ( ( i*i < n) && (0==salir) )
{
    if ( 0== n % i)
    {
        r=test(peaks,i,n);
        if (( 1==r ) && (i>max)) max=i; 

        j = n/i;
        r=test(peaks,j,n);
        if (( 1==r ) && (j>max)) max=j; 
        if ( max > n/2) salir =1;
    }
    i++;
}

if (0==salir)
{
    if (i*i == n) 
    {

        if ( 1==test(peaks,i,n) ) max=i;

    } 
}



return max;

}
于 2013-12-20T22:49:48.440 回答
1

第一个想法是我们不能设置多个sqrt(N)标志。让我们假设我们已经拿了N标志,在这种情况下,我们应该至少有N * N项目来设置所有标志,因为N它是标志之间的最小距离。因此,如果我们有N项目,则不可能设置超过sqrt(N)标志。

function solution(A) {
    const peaks = searchPeaks(A);
    const maxFlagCount = Math.floor(Math.sqrt(A.length)) + 1;

    let result = 0;
    for (let i = 1; i <= maxFlagCount; ++i) {
        const flagsSet = setFlags(peaks, i);
        result = Math.max(result, flagsSet);
    }

    return result;
}

function searchPeaks(A) {
    const peaks = [];

    for (let i = 1; i < A.length - 1; ++i) {
        if (A[i] > A[i - 1] && A[i] > A[i + 1]) {
            peaks.push(i);
        }
    }

    return peaks;
}

function setFlags(peaks, flagsTotal) {
    let flagsSet = 0;
    let lastFlagIndex = -flagsTotal;

    for (const peakIndex of peaks) {
        if (peakIndex >= lastFlagIndex + flagsTotal) {
            flagsSet += 1;
            lastFlagIndex = peakIndex;

            if (flagsSet === flagsTotal) {
                return flagsSet;
            }
        }
    }

    return flagsSet;
}

这种解决方案具有O(N)复杂性。我们应该迭代A以找到峰值并迭代从1尝试sqrt(N)设置所有标志的标志计数。所以我们有O(N + 1 + 2 + 3 ... sqrt(N))= O(N + sqrt(N*N))=O(N)复杂性。

上面的解决方案非常快并且得到了100%结果,但它可以更加优化。这个想法是对标志计数进行二进制搜索。让我们拿起F标志并尝试设置它们。如果留下多余的标志,答案是 less tan F。但是,如果所有标志都已设置并且有更多标志的空间,则答案大于F

function solution(A) {
    const peaks = searchPeaks(A);
    const maxFlagCount = Math.floor(Math.sqrt(A.length)) + 1;
    return bSearchFlagCount(A, peaks, 1, maxFlagCount);
}

function searchPeaks(A) {
    const peaks = [];

    for (let i = 1; i < A.length - 1; ++i) {
        if (A[i] > A[i - 1] && A[i] > A[i + 1]) {
            peaks.push(i);
        }
    }

    return peaks;
}

function bSearchFlagCount(A, peaks, start, end) {
    const mid = Math.floor((start + end) / 2);
    const flagsSet = setFlags(peaks, mid);

    if (flagsSet == mid) {
        return mid;
    } else if (flagsSet < mid) {
        return end > start ? bSearchFlagCount(A, peaks, start, mid) : mid - 1;
    } else {
        return bSearchFlagCount(A, peaks, mid + 1, end);
    }
}

function setFlags(peaks, flagsTotal) {
    let flagsSet = 0;
    let lastFlagIndex = -flagsTotal;

    for (const peakIndex of peaks) {
        if (peakIndex >= lastFlagIndex + flagsTotal) {
            flagsSet += 1;
            lastFlagIndex = peakIndex;

            // It only matters that we can set more flags then were taken.
            // It doesn't matter how many extra flags can be set.
            if (flagsSet > flagsTotal) {
                return flagsSet;
            }
        }
    }

    return flagsSet;
}

这是该任务的官方 Codility 解决方案。

于 2020-02-22T15:59:11.277 回答
0
import sys

def get_max_num_peaks(arr):
    peaks = [i for i in range(1, len(arr)-1, 1) if arr[i]>arr[i-1] and arr[i]>arr[i+1]]
    max_len = [1 for i in peaks]
    smallest_diff = [0 for i in peaks]
    smallest_diff[0] = sys.maxint
    for i in range(1, len(peaks), 1):
        result = 1
        for j in range(0, i, 1):
            m = min(smallest_diff[j], peaks[i]-peaks[j])
            if smallest_diff[j]>0 and m>=max_len[j]+1:
                max_len[i] = max_len[j]+1
                smallest_diff[i] = m 
                result = max(result, max_len[i])
    return result

if __name__ == "__main__":
    result = get_max_num_peaks([7, 10, 4, 5, 7, 4, 6, 1, 4, 3, 3, 7])
    print result

我用DP来解决这个问题。这里是 python 代码: The max num of flags can be set for array ending at i is the max num of flags can be set on j if min(min_diff(0 .. j), j to i) is not less than max_len (0 .. j)+1 如果我错了或有 O(N) 解决方案,请纠正我

于 2013-10-23T18:29:36.707 回答
0
public int solution(int[] A) {
     int p = 0;
     int q = 0;
     int k = 0;

        for (int i = 0; i < A.length; i++) {

        if (i > 0 && i < A.length && (i + 1) < A.length - 1) {
            if (A[i] > A[i - 1] && A[i] > A[i + 1]) {
                p = i;

                if (i < A.length / 2)
                    k++;

            }

            if (i > 0 && i < A.length && (A.length - i + 1) < A.length) {
                if (A[A.length - i] > A[A.length - i - 1]
                        && A[A.length - i] > A[A.length - i + 1] ) {
                    q = A.length - i;

                    if (i < A.length / 2)
                        k++;
                    else {
                        if (Math.abs(p - q) < k && p != q)
                            k--;
                    }

                }
            }

        }

    }
    return k;
}
于 2013-10-22T10:24:37.933 回答
0

我知道答案是由 francesco Malagrino 提供的,但我已经编写了自己的代码。对于数组 {1,5,3,4,3,4,1,2,3,4,6,2} 和 { 7, 10, 4, 5, 7, 4, 6, 1, 4, 3, 3, 7 } 我的代码运行良好。当我参加代码考试时,我在 {9, 9, 4, 3, 5, 4, 5, 2, 8, 9, 3, 1} 上失败了

我的回答导致最多 3 个标志。我理解它的方式应该是 3,但正确的答案是 2,而且还与 francesco Malagrino 的解决方案有关。

我的代码中似乎有什么问题,为什么答案应该只是 2 峰 4、6、9 之间的距离遵循规则的事实。

private static int getpeak(int[] a) {
    List<Integer> peak = new ArrayList<Integer>();
    int temp1 = 0;
    int temp2 = 0;
    int temp3 = 0;

    for (int i = 1; i <= (a.length - 2); i++) {
        temp1 = a[i - 1];
        temp2 = a[i];
        temp3 = a[i + 1];
        if (temp2 > temp1 && temp2 > temp3) {
            peak.add(i);
        }
    }

    Integer[] peakArray = peak.toArray(new Integer[0]);
    int max = 1;
    int lastFlag = 0;

    for (int i = 1; i <= peakArray.length - 1; i++) {
        int gap = peakArray[i] - peakArray[lastFlag];
        gap = Math.abs(gap);
        if (gap >= i+1) {
            lastFlag = i;
            max = max + 1;
        }
    }
    return max;
}
于 2013-10-30T01:55:52.263 回答
0

解决这个问题:

  1. 你必须找到高峰
  2. 计算每 2 个峰之间的距离(指数差异)
  3. 最初标志的数量是相同的峰值数量
  4. 将每 2 个峰值之间的距离与最初指定的标志数进行比较 ( [P - Q] >= K)
  5. 比较之后你会发现你要避开一些峰
  6. 最大标志的最终数量与剩余峰值的数量相同

** 我仍在寻找如何为这个问题编写最佳优化的代码

于 2013-10-21T19:59:07.247 回答
0

我想出了一个算法来解决这个问题,它既是 O(N),又通过了所有的代码测试。主要思想是标志的数量不能超过 N 的平方根。所以为了保持总阶的线性,每次迭代也应该小于 N 的平方根,也就是标志本身的数量。

所以首先,我构建了一个数组 nextPeak ,它为 A 的每个索引提供索引之后最接近的标志。然后,在第二部分中,我将 f 遍历所有可能的标志数,从 N 的根返回到 0,以找到可以应用于数组的最大标志数。在每次迭代中,我尝试应用标志并使用 nextPeak 数组在恒定时间内找到下一个峰值。

代码如下所示:

public int solution(int[] A){
    if( A==null || A.length<3){
        return 0;
    }

    int[] next = new int[A.length];
    int nextPeak=-1;
    for(int i =1; i<A.length; i++){
        if(nextPeak<i){
            for(nextPeak=i; nextPeak<A.length-1; nextPeak++){
                if(A[nextPeak-1]<A[nextPeak] && A[nextPeak]>A[nextPeak+1]){
                    break;
                }
            }
        }

        next[i] = nextPeak;
    }

    next[0] = next[1];

    int max = new Double(Math.sqrt(A.length)).intValue();

    boolean failed = true ;
    int f=max;
    while(f>0 && failed){
        int v=0;
        for(int p=0; p<A.length-1 && next[p]<A.length-1 && v<f; v++, p+=max){
            p = next[p];
        }

        if(v<f){
            f--;
        } else {
            failed = false;
        }

    }

    return f;
}
于 2013-12-29T20:31:02.117 回答
0
def solution(A):
    peak=[x for x in range(1,len(A))if A[x-1]<A[x]>A[x+1]]
    max_flag=len(peak)
    for x in range(1,max_flag+1):
        for y in range(x-1):
            if abs(peak[y]-peak[y+1])>=max_flag:
                max_flag=max_flag-1
    print(max_flag)**strong text**
于 2021-06-12T20:10:15.013 回答
0

我的 C++ 解决方案 100% 结果

bool check(const vector<int>& v, int flags, int mid) {
    if (not v.empty()) {
        flags--;
    }
    int start = 0;
    for (size_t i = 1; i < v.size(); ++i) {
        if (v[i] - v[start] >= mid) {
            --flags;
            start = i;
        }
    }
    return flags <= 0;
}
int solution(vector<int> &A) {
    vector<int> peaks;
    for (size_t i = 1; i < A.size() - 1; ++i) {
        if (A[i] > A[i - 1] and A[i] > A[i + 1]) {
            peaks.push_back(i);
        }
    }
    int low = 0;
    int high = peaks.size();
    int res = 0;
   
    while (low <= high) {
        int mid = high - (high - low) / 2;
        if (check(peaks, mid, mid)) {
            low = mid + 1;
            res = mid;
        } else {
            high = mid - 1;
        }
    }
    return res;
}
于 2021-01-08T21:14:02.360 回答
0

检测到 100% 蟒蛇 O(N)。

import math
def solution(A):
 N=len(A)
#Trivial cases
 if N<3:
    return 0
 Flags_Idx=[]

 for p in range(1,N-1):
     if A[p-1]<A[p] and A[p]>A[p+1] :
         Flags_Idx.append(p)

 if len(Flags_Idx)==0:
    return 0
 if len(Flags_Idx)<=2:
     return len(Flags_Idx)
 Start_End_Flags=Flags_Idx[len(Flags_Idx)-1]-Flags_Idx[0]  
#Maximum number of flags N is such that Start_End_Flags/(N-1)>=N
#After solving a second degree equation we obtain the maximal value of N
 num_max_flags=math.floor(1.0+math.sqrt(4*Start_End_Flags+1.0))/2.0

#Set the current number of flags to its total number      
 len_flags=len(Flags_Idx)
 min_peaks=len(Flags_Idx)
 p=0

#Compute the minimal number of flags by checking each indexes
#and comparing to the maximal theorique value num_max_flags
 while p<len_flags-1:
    add = 1
#Move to the next flag until the condition Flags_Idx[p+add]-Flags_Idx[p]>=min(num_max_flags,num_flags) 
    while Flags_Idx[p+add]-Flags_Idx[p]<min(num_max_flags,min_peaks):
         min_peaks-=1
         if p+add<len_flags-1:
          add+=1
         else:
             p=len_flags
             break
    p+=add

 if num_max_flags==min_peaks:
  return min_peaks
#Bisect the remaining flags : check the condition
#for flags in [min_peaks,num_max_flags]
 num_peaks=min_peaks
 for nf in range (min_peaks,int(num_max_flags)+1):
  cnt=1
  p=0
  while p<len_flags-1:
    add = 1
    while Flags_Idx[p+add]-Flags_Idx[p]<nf:
         if p+add<len_flags-1:
          add+=1
         else:
             cnt-=1
             p=len_flags
             break
    p+=add
    cnt+=1
  num_peaks=max(min(cnt,nf),num_peaks)  
 return num_peaks

我首先计算了验证条件 Interval/(N-1) >= N 的最大可能标志数,其中 Interval 是第一个和最后一个标志之间的索引差。然后浏览与此值的最小值和当前标志数进行比较的所有标志。如果条件未得到验证,则减去。获得最小数量的标志并将其作为起点检查剩余标志的条件(在区间 [min_flag,max_flag] 中)。

于 2019-11-17T21:28:22.357 回答
0

我在 Java 中得到了 100% 的这个解决方案。我为第一个循环做了一件事来找到峰值,即在找到峰值后我跳过下一个元素,因为它小于峰值。我知道这个解决方案可以由小组成员进一步优化,但这是我目前能做的最好的,所以请让我知道如何进一步优化它。

检测到的时间复杂度:O(N) https://app.codility.com/demo/results/trainingG35UCA-7B4/

public static int solution(int[] A) {
        int N = A.length;
        if (N < 3)
            return 0;
        
        ArrayList<Integer> peaks = new ArrayList<Integer>();
 
        for (int i = 1; i < N - 1; i++) {
 
            if (A[i] > A[i - 1]) {
                if (A[i] > A[i + 1]) {
                    peaks.add(i);
                    i++;// skip for next as A[i + 1] <  A[i] so no need to check again
 
                }
            }
        }
 
        
        int size = peaks.size();
        if (size < 2)
            return size;
 
        int k = (int) Math.sqrt(peaks.get(size - 1) - peaks.get(0))+1; // added 1 to round off
        int flagsLeft = k - 1; // one flag is used for first element
        int maxFlag = 0;
        int prevEle = peaks.get(0);
 
        while (k > 0) { // will iterate in descending order
            flagsLeft = k - 1; // reset first peak flag 
            prevEle = peaks.get(0);  // reset the flag to first element
 
            for (int i = 1; i < size && flagsLeft > 0; i++) {
 
                if (peaks.get(i) - prevEle >= k) {
                    flagsLeft--;
                    prevEle = peaks.get(i);
                }
 
                if ((size - 1 - i) < flagsLeft) { // as no. of peaks < flagsLeft
                    break;
                    
                }
            }
 
            
            if (flagsLeft == 0 && maxFlag < k) {
                maxFlag = k;
                break; // will break at first highest flag as iterating in desc order
            }
 
            k--;
        }
 
        return maxFlag;
    }
于 2021-07-15T21:02:12.267 回答
0

100% python 解决方案,比@Jurko Gospodnetić 上面发布的解决方案简单得多

https://github.com/niall-oc/things/blob/master/codility/flags.py

https://app.codility.com/demo/results/training2Y78NP-VHU/

你不需要对这个问题进行二分搜索。MAX flags 是(第一个和最后一个标志之间传播的平方根)+1。索引 9 处的第一个峰值和索引 58 处的最后一个峰值意味着价差为 sqrt(49),即 (7)+1。所以尝试 8 个标志,然后是 7 个,然后是 6 个,依此类推。您应该在解决方案达到峰值后休息!没必要鞭打死马!

于 2020-11-03T22:49:31.477 回答
0

获得 100% 分数的 C# 解决方案。

using System;
using System.Collections.Generic;



class Solution {
    public int solution(int[] A) {
    // write your code in C# 6.0 with .NET 4.5 (Mono)
    List<int> peaks = new List<int>();
        for (int i = 1; i < A.Length - 1; i++)
        {
            if (A[i - 1] < A[i] && A[i + 1] < A[i])
            {
                peaks.Add(i);
            }
        }
        if (peaks.Count == 1 || peaks.Count == 0)
        {
            return peaks.Count;
        }
        int leastFlags = 1;
        int mostFlags = peaks.Count;
        int result = 1;
        while (leastFlags <= mostFlags)
        {
            int flags = (leastFlags + mostFlags) / 2;
            bool suc = false;
            int used = 0;
            int mark = peaks[0];
            for (int i = 0; i < peaks.Count; i++)
            {
                if (peaks[i] >= mark)
                {
                    used++;
                    mark = peaks[i] + flags;
                    if (used == flags)
                    {
                        suc = true;
                        break;
                    }
                }
            }
            if (suc)
            {
                result = flags;
                leastFlags = flags + 1;
            }
            else
            {
                mostFlags = flags - 1;
            }
        }
        return result;
}

}

于 2018-10-17T04:10:22.017 回答
0

100% 工作的 JS 解决方案:

function solution(A) {
    let peaks = [];

    for (let i = 1; i < A.length - 1; i++) {
        if (A[i] > A[i - 1] && A[i] > A[i + 1]) {
            peaks.push(i);  
        }
    }

    let n = peaks.length;
    if (n <= 2) {
        return n;
    }

    let maxFlags = Math.min(n, Math.ceil(Math.sqrt(A.length)));
    let distance = maxFlags;
    let rightPeak = peaks[n - 1];

    for (let k = maxFlags - 2; k > 0; k--) {
        let flags = k;
        let leftPeak = peaks[0];

        for (let i = 1; i <= n - 2; i++) {
            if (peaks[i] - leftPeak >= distance && rightPeak - peaks[i] >= distance) {
                if (flags === 1) {
                    return k + 2;    
                }

                flags--;
                leftPeak = peaks[i];
            }

            if (rightPeak - peaks[i] <= flags * (distance + 1)) {
                break;
            }
        }

        if (flags === 0) {
            return k + 2;
        }

        distance--;
    }

    return 2;
}
于 2019-04-18T14:26:26.920 回答
0

这是一个 100% 的 Java 解决方案

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

        int[] nextPeaks = nextPeaks(A);

        int flagNumebr = 1;
        int result = 0;

        while ((flagNumebr-1)*flagNumebr <= A.length) {

            int flagPos = 0;
            int flagsTaken = 0;

            while (flagPos < A.length && flagsTaken < flagNumebr) {
                flagPos = nextPeaks[flagPos];

                if (flagPos == -1) {
                    // we arrived at the end of the peaks;
                    break;
                }

                flagsTaken++;
                flagPos += flagNumebr;
            }
            result = Math.max(result, flagsTaken);
            flagNumebr++;

        }

        return  result;



    }

    private boolean[] createPeaks(int[] A) {
        boolean[] peaks = new boolean[A.length];
        for (int i = 1; i < A.length-1; i++) {
            if (A[i - 1] < A[i] && A[i] > A[i + 1]) {
                peaks[i] = true;
            }
        }

        return  peaks;
    }

    private int[] nextPeaks (int[] A) {
        boolean[] peaks = createPeaks(A);
        int[] nextPeaks = new int[A.length];
        // the last position is always -1
        nextPeaks[A.length-1] = -1;

        for (int i = A.length-2; i >= 0 ; i--) {
            nextPeaks[i] = peaks[i] ? i : nextPeaks[i+1];
        }

        return  nextPeaks;
    }
}
于 2015-10-12T08:16:36.447 回答
-1
int solution(int A[], int N) {
    int i,j,k;
    int count=0;
    int countval=0;
    int count1=0;
    int flag;
    for(i=1;i<N-1;i++)
    {`enter code here`
        if((A[i-1]<A[i]) && (A[i]>A[i+1]))
        {



            printf("%d %d\n",A[i],i);
             A[count++]=i;
            i++;

        }
    }  

    j=A[0];
    k=0;
    if (count==1 || count==0)
    return count;
    if (count==2)
    {
        if((A[1]-A[0])>=count)
        return 2;
        else 
        return 1;
    }


    flag=0;
    // contval=count;
    count1=1;
    countval=count;
    while(1)
    {
    for(i=1;i<count;i++)
    {
           printf("%d %d\n",A[i],j);
           if((A[i]-j)>=countval)
            {
                printf("Added %d %d\n",A[i],j);
                count1++;
                j=A[i];

            }
           /* if(i==count-1 && count1<count)
            {
                j=A[0];
                i=0;
                count1=1;
            }*/

    }
printf("count %d count1 %d \n",countval,count1);
if (count1<countval)
            {
               count1=1;
               countval--;
               j=A[0];
              }
            else
            {
              break;            }


}
    return countval;
   }
于 2013-10-24T12:30:08.037 回答