如何确定一个序列是否是比特的?

时间:2010-06-12 14:46:05

标签: algorithm

  

序列是单调的,如果它单调增加然后单调减去       折痕,或者如果它可以循环转移到单调增加然后       单调减少。例如序列(1,4,6,8,3,-2),        (9,2,-4,-10,-5)和(1,2,3,4)是比特的,但(1,3,12,4,2,10)不是       双调。

如何判断给定序列是否具有比特效应?

我有以下意见。我们可以走到 n / 2 ,其中 n 是数组的长度,并检查是否

(a[i] < a[i + 1]) and (a[n - i - 1] < a[n-1 - (i + 1)])

这是对的吗?

5 个答案:

答案 0 :(得分:32)

一个比特序列:

 /\
/  \
    \/

不是一个比特序列:

 /\    
/  \  / (higher than start)
    \/

显然,如果方向变化超过两次,我们就不能有一个比特序列 如果方向改变不到两次,我们必须有一个比特序列。

如果方向有两个变化,我们可能会有一个比特序列。考虑上面的两个ascii图像。显然,方向上有两个变化的序列将匹配其中一个模式(允许反射)。因此,我们通过比较第一个和最后一个元素来设置初始方向。由于它们可以相同,我们使用的第一个元素不等于最后一个元素。

这是Java中的一个实现:

public static Boolean bitonic(int[] array) {
    if (array == null) return false;
    if (array.length < 4) return true;
    Boolean dir;// false is decreasing, true is increasing
    int pos = 0, switches = 0;
    while (pos < array.length) {
        if (array[pos] != array[array.length - 1])
            break;
        pos++;
    }
    if (pos == array.length) return true;
    //pos here is the first element that differs from the last
    dir = array[pos] > array[array.length - 1];
    while (pos < array.length - 1 && switches <= 2) {
        if ((array[pos + 1] != array[pos]) &&
           ((array[pos + 1] <= array[pos]) == dir)) {
            dir ^= true;
            switches++;
        }
        pos++;
    }
    return switches <= 2;
}

答案 1 :(得分:8)

  • 向前遍历阵列,当你到达终点时缠绕(下面的代码)
  • 计算您找到的拐点总数,如果num_inflection_points==2,那么您的阵列是比特的。
  • 此运行时应为O(n)

-

以下是c ++中的一个工作示例:

bool is_bitonic(const vector<int>& v) {
  bool was_decreasing = v.back() > v.front();
  int num_inflections = 0;
  for (int i = 0; i < v.size() && num_inflections <= 2; i++) {
    bool is_decreasing = v[i] > v[(i+1)%v.size()];
    // Check if this element and next one are an inflection.
    if (was_decreasing != is_decreasing) {
      num_inflections++;
      was_decreasing = is_decreasing;
    }
  }
  return 2 == num_inflections;
}
  • 注意,取决于您的实施:

注1:这是循环遍历数组的基本思路:

for (int i = ip_index; i < array_length; i++) {
   int index = (i + 1) % array_length;  // wraps around to beginning
   // Retrieve the value with
   DoSomethingWithValue(array[index];)
}

注2:它可以简化循环length + 1元素的代码,这将保证你找到两个拐点。

注3:或者,如果您总是寻找增加到减少的第一个拐点(在搜索其他拐点之前),它可能会简化代码。这样,你的扫描只需要担心找到另一个相反翻转的另一个拐点。

注4:至于你的例子,你不能使用N/2,因为拐点不一定发生在数组的中点。

答案 2 :(得分:2)

这是Java中一种高效而简单的实现。它只遍历数组一次以确定阵列是否是bitonic。它使用变量reversal来计算数组中单调性的方向反转次数(包括圆形环绕)。

变量trend可以有三个值:

  • 0,如果值相同;
  • 1,如果数组单调增加;
  • -1,如果数组单调减少。
public static boolean bitonic(int[] arr) {
  int reversal = 0;
  int len = arr.length;
  int trend = 0; // 0 means any, 1 means increasing, -1 means decreasing 
  for (int i= 0; i < len ; i++) {
    if(arr[i%len] < arr[(i+1)%len]){
      if (trend == 0) trend = 1;
      else if ( trend == -1) {
        reversal ++;
        trend = 1;
      }
    }
    else if(arr[i%len] > arr[(i+1)%len]){
      if (trend == 0) trend = -1;
      else if ( trend == 1) {
        reversal ++;
        trend = -1;
      }
    }
    if(reversal > 2) return false;
  }
  return true;
}

答案 3 :(得分:0)

你可以寻找峰值,即当[i-1] < a [i]&amp;&amp; a [i]&gt; a [i + 1],然后a [i]是局部峰值(用模数运算符进行环绕)。

在比特序列中,只能有一个这样的峰值。一旦找到了峰值,那么你可以向下走到左边(必要时再缠绕,再次使用模数)直到找到一个上坡。然后你回到山顶,向下走到右边,直到你发现另一个上坡。现在,如果一个序列是比特的,那么你将通过在两侧下坡来覆盖整个序列。

顺便说一句,我是否误解了这个问题,或者你的第一个例子是不是有点神秘的?

答案 4 :(得分:0)

需要正好两个(或者,取决于你的定义如何处理退化,正好为0)在上升和下降之间的转换。不要忘记检查[n]和[0]之间的转换。