【问题标题】:Explain the Peak and Flag Algorithm解释峰值和标志算法
【发布时间】:2013-10-27 18:45:45
【问题描述】:

编辑

刚刚指出需求状态的峰值不能是数组的结尾。

于是我跑到了这个网站

http://codility.com/

如果你能在 2 小时内解决它们,这会给你带来编程问题并给你证书。第一个问题是我以前见过的,通常称为峰与旗问题。如果你不熟悉

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

0 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个flag,那么任何两个flag之间的距离应该大于或等于K。索引P和Q之间的距离是绝对值|P-Q|。

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

两个flag,可以分别设置在峰1和5上;

三个标志,您可以将它们设置在峰 1、5 和 10;

四个标志,您只能在峰 1、5 和 10 上设置三个标志。

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

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

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

假设:

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

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

复杂性:

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

输入数组的元素可以修改。

所以这是有道理的,但我使用这段代码失败了

public int GetFlags(int[] A)
{
        List<int> peakList = new List<int>();
        for (int i = 0; i <= A.Length - 1; i++)
        {               
                if ((A[i] > A[i + 1] && A[i] > A[i - 1]))
                {
                    peakList.Add(i);
                }
        }

        List<int> flagList = new List<int>();
        int distance = peakList.Count;
        flagList.Add(peakList[0]);
        for (int i = 1, j = 0, max = peakList.Count; i < max; i++)
        {
            if (Math.Abs(Convert.ToDecimal(peakList[j]) - Convert.ToDecimal(peakList[i])) >= distance)
            {
                flagList.Add(peakList[i]);
                j = i;
            }
        }
        return flagList.Count;
}

编辑

int[] A = new int[] { 7, 10, 4, 5, 7, 4, 6, 1, 4, 3, 3, 7 };

正确答案是 3,但我的应用程序显示的是 2

这我不明白,因为有 4 个峰值(索引 1、4、6、8),因此,您应该能够在其中 2 个峰值(1 和 6)处放置一个标志

我在这里遗漏了什么吗?显然我的假设是一个Array的开头或结尾可以是一个峰值,不是这样吗?

如果这需要进入 Stack Exchange Programmers,我会移动它,但认为此处的对话框会有所帮助。

编辑

【问题讨论】:

  • 您可以在 1、4、8 上设置 3 个标志
  • 所以你有能力“跳过”一个高峰?我不确定您将如何在数组中向前看 N 长度数组,而不会非常低效。有什么想法吗?
  • 我没有看到任何您不能跳过高峰的信息 - 即使您的答案 1 和 6 也跳过了高峰。您能否发布一些指向此代码挑战的链接?
  • 我认为最好的策略是:当你可以设置一个标志时——就设置它。因此,如果距离允许您设置标志 - 设置它。
  • 你可能是对的,我只是很难把我的大脑包裹在这个问题上。当标志不等于或大于您可以拥有的最大标志时,您如何在 1 和 4 处设置标志?最大标志为 4,1 和 4 之间的差值小于此值。

标签: c# arrays algorithm


【解决方案1】:

显然我的假设是数组的开头或结尾可以 做个巅峰,不是这样吗?

您的假设是错误的,因为峰值定义为:

0

当涉及到您的第二个示例时,您可以在 1、4、8 上设置 3 个标志。

【讨论】:

  • 所以你有能力“跳过”一个高峰?我不确定您将如何在 N 长度数组的数组中向前看,而不会非常低效。有什么想法吗?
【解决方案2】:

这里有个提示:如果可以设置m个标志,那么必须至少有m * (m - 1) + 1个数组元素。鉴于 N

【讨论】:

    【解决方案3】:

    这里有个提示:如果可以设置m个标志,那么一定有 至少 m * (m - 1) + 1 个数组元素。鉴于 N

    不,这是错误的。 Codility 对自定义解决方案进行了一系列测试,暴力破解很容易按时失败。

    【讨论】:

      【解决方案4】:

      我在这里给出了我的任务解决方案,该任务在 C++ 中实现了 100% 的代码(正确性和性能)。要理解解决方案,您必须针对给定的索引距离实现(例如,当第一个峰值从索引 2 开始,最后一个峰值从索引 58 开始时,距离为 56),其中包含 n 个峰值,最大数量有一个上限根据任务中描述的条件,可以持有标志的峰数。

      #include <vector>
      #include <math.h>
      
      typedef unsigned int uint;
      
      void flagPeaks(const std::vector<uint> & peaks,
          std::vector<uint> & flaggedPeaks,
          const uint & minDist)
      {
          flaggedPeaks.clear();
          uint dist = peaks[peaks.size() - 1] - peaks[0];
          if (minDist > dist / 2)
              return;
      
          flaggedPeaks.push_back(peaks[0]);
          for (uint i = 0; i < peaks.size(); ) {
              uint j = i + 1;
              while (j < (peaks.size()) && ((peaks[j] - peaks[i]) < minDist))
                  ++j;
      
              if (j < (peaks.size()) && ((peaks[j] - peaks[i]) >= minDist))
                  flaggedPeaks.push_back(peaks[j]);
              i = j;
          }
      }
      
      
      int solution(std::vector<int> & A)
      {
          std::vector<uint> peaks;
          uint min = A.size();
          for (uint i = 1; i < A.size() - 1; i++) {
              if ((A[i] > A[i - 1]) && (A[i] > A[i + 1])) {
                  peaks.push_back(i);
                  if (peaks.size() > 1) {
                      if (peaks[peaks.size() - 1] - peaks[peaks.size() - 2] < min)
                          min = peaks[peaks.size() - 1] - peaks[peaks.size() - 2];
                  }
              }
          }
          // minimal distance between 2 peaks is 2
          // so when we have less than 3 peaks we are done
          if (peaks.size() < 3 || min >= peaks.size())
              return peaks.size();
      
          const uint distance = peaks[peaks.size() - 1] - peaks[0];
          // parts are the number of pieces between peaks
          // given n + 1 peaks we always have n parts
          uint parts = peaks.size() - 1;
          // calculate maximal possible number of parts
          // for the given distance and number of peaks
          double avgOptimal = static_cast<double>(distance) / static_cast<double> (parts);
          while (parts > 1 && avgOptimal < static_cast<double>(parts + 1)) {
              parts--;
              avgOptimal = static_cast<double>(distance) / static_cast<double>(parts);
          }
      
          std::vector<uint> flaggedPeaks;
          // check how many peaks we can flag for the 
          // minimal possible distance between two flags
          flagPeaks(peaks, flaggedPeaks, parts + 1);
          uint flags = flaggedPeaks.size();
          if (flags >= parts + 1)
              return parts + 1;
      
          // reduce the minimal distance between flags
          // until the condition fulfilled
          while ((parts > 0) && (flags < parts + 1)) {
              --parts;
              flagPeaks(peaks, flaggedPeaks, parts + 1);
              flags = flaggedPeaks.size();
          }
          // return the maximal possible number of flags 
          return parts + 1;
      }
      

      【讨论】:

        猜你喜欢
        • 2017-08-12
        • 1970-01-01
        • 1970-01-01
        • 2013-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多