序列是单调的,如果它单调增加然后单调减去 折痕,或者如果它可以循环转移到单调增加然后 单调减少。例如序列(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)])
这是对的吗?
答案 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]之间的转换。