如果整数序列的每个元素严格小于或严格大于其邻居,则称为Z字形序列。
示例:序列4 2 3 1 5 3形成一个之字形,但不是7 3 5 5 2和3 8 6 4 5。
对于给定的整数数组,我们需要找到形成Z字形序列的最大(连续)子阵列的长度。
这可以在O(N)中完成吗?
目前我的解决方案是O(N ^ 2),它只是简单地取每两个点并检查每个可能的子阵列是否满足条件。
答案 0 :(得分:1)
我声称任何2个Z字形子序列的重叠序列的长度是最多1
矛盾证明:
假设a_i .. a_j
是最长的锯齿形子序列,并且还有另一个锯齿形子序列b_m...b_n
重叠。
不失一般性,让我们说重叠的部分是
a_i ... a_k ... a_j
-------- B_M ... b_k” ... B_N
a_k = b_m,a_k + 1 = b_m + 1 ... a_j = b_k'其中k'-m = j-k> 0(至少2个元素重叠)
然后他们可以合并形成一个更长的锯齿形序列,矛盾。
这意味着他们可以相互重叠的唯一情况就像
3 5 3 2 3 2 3
3 5 3
和3 2 3 2 3
在1个元素重叠
这仍然可以在O(N)中解决,我相信,就像贪婪地增加之字形长度一样。如果失败,将迭代器1元素移回并将其视为新的曲折起点
记录您找到的最新和最长的锯齿形长度
答案 1 :(得分:0)
对于每个索引i
,您可以找到最小的j
,使得索引为j,j + 1,...,i-1,i的子阵列为锯齿形。这可以分两个阶段完成:
找到最长的"增加"之字形(以a[1]>a[0]
开头):
start = 0
increasing[0] = 0
sign = true
for (int i = 1; i < n; i ++)
if ((arr[i] > arr[i-1] && sign) || )arr[i] < arr[i-1] && !sign)) {
increasing[i] = start
sign = !sign
} else if (arr[i-1] < arr[i]) { //increasing and started last element
start = i-1
sign = false
increasing[i] = i-1
} else { //started this element
start = i
sign = true
increasing[i] = i
}
}
同样做&#34;减少&#34; zig-zag,你可以找到每个索引最早的&#34;一个之字形子阵的可能开始。
从那里,找到最大可能的锯齿形很容易。
由于所有的操作都是在O(n)
完成的,而你基本上是一个接一个地完成,这就是你的复杂性。
你可以结合两者&#34;增加&#34;并且&#34;减少&#34;一气呵成:
start = 0
maxZigZagStart[0] = 0
sign = true
for (int i = 1; i < n; i ++)
if ((arr[i] > arr[i-1] && sign) || )arr[i] < arr[i-1] && !sign)) {
maxZigZagStart[i] = start
sign = !sign
} else if (arr[i-1] > arr[i]) { //decreasing:
start = i-1
sign = false
maxZigZagStart[i] = i-1
} else if (arr[i-1] < arr[i]) { //increasing:
start = i-1
sign = true
maxZigZagStart[i] = i-1
} else { //equality
start = i
//guess it is increasing, if it is not - will be taken care of next iteration
sign = true
maxZigZagStart[i] = i
}
}
你可以看到你甚至可以放弃maxZigZagStart
辅助数组并存储本地最大长度。
答案 2 :(得分:0)
沿着数组走,看看当前项目是否属于(符合定义)之字形。记住las zigzag start,它是数组的开始或最近的非Z字形元素之后的第一个zigzag元素。这和当前项目定义一些之字形子阵列。当它看起来比之前发现的长时,存储新的最长锯齿形长度。继续直到数组结束,您应该在O(N)中完成任务。
答案 3 :(得分:0)
简单的一次通过算法草图。 Cmp比较相邻元素,为较少,相等和较大的情况返回-1,0,1。 对于Cmp过渡的情况,Zigzag结束:
0 0
-1 0
1 0
Zigzag结束,新系列开始:
0 -1
0 1
-1 -1
1 1
Zigzag系列继续进行过渡
-1 1
1 -1
ALGO:
Start = 0
LastCmp = - Compare(A[i], A[i - 1]) //prepare to use the first element individually
MaxLen = 0
for i = 1 to N - 1 do
Cmp = Compare(A[i], A[i - 1]) //returns -1, 0, 1 for less, equal and greater cases
if Abs(Cmp - LastCmp) <> 2 then
//zigzag condition is violated, series ends, new series starts
MaxLen = Max(MaxLen, i - 1 - Start)
Start = i
//else series continues, nothing to do
LastCmp = Cmp
//check for ending zigzag
if LastCmp <> 0 then
MaxLen = Max(MaxLen, N - Start)
输出示例:
2 6 7 1 7 0 7 3 1 1 7 4
5 (7 1 7 0 7)
8 0 0 3 5 8
1
0 0 7 0
2
1 2 0 7 9
3
8 3 5 2
4
1 3 7 1 6 6
2
1 4 0 6 6 3 4 3 8 0 9 9
5
答案 4 :(得分:0)
抱歉,我使用perl来写这个。
#!/usr/bin/perl
@a = ( 5, 4, 2, 3, 1, 5, 3, 7, 3, 5, 5, 2, 3, 8, 6, 4, 5 );
$n = scalar @a;
$best_start = 0;
$best_end = 1;
$best_length = 2;
$start = 0;
$end = 1;
$direction = ($a[0] > $a[1]) ? 1 : ($a[0] < $a[1]) ? -1 : 0;
for($i=2; $i<$n; $i++) {
// a trick here, same value make $new_direction = $direction
$new_direction = ($a[$i-1] > $a[$i]) ? 1 : ($a[$i-1] < $a[$i]) ? -1 : $direction;
print "$a[$i-1] > $a[$i] : direction $new_direction Vs $direction\n";
if ($direction != $new_direction) {
$end = $i;
} else {
$this_length = $end - $start + 1;
if ($this_length > $best_length) {
$best_start = $start;
$best_end = $end;
$best_length = $this_length;
}
$start = $i-1;
$end = $i;
}
$direction = $new_direction;
}
$this_length = $end - $start + 1;
if ($this_length > $best_length) {
$best_start = $start;
$best_end = $end;
$best_length = $this_length;
}
print "BEST $best_start to $best_end length $best_length\n";
for ($i=$best_start; $i <= $best_end; $i++) {
print $a[$i], " ";
}
print "\n";
答案 5 :(得分:0)
让我们以序列5 9 3 4 5 4 2 3 6 5 2 1 3
为例。你有一个条件,子序列的每个内部元素都应该满足(元素严格地小于或严格地大于它的邻居)。让我们为整个序列的每个元素计算这个条件:
5 9 3 6 5 7 2 3 6 5 2 1 3
0 1 1 1 1 1 1 0 1 0 0 1 0
最外层元素的条件未定义,因为它们每个只有一个邻居。但为方便起见,我将其定义为0
。
1
的最长子序列(9 3 6 5 7 2
)是最长的之字形子序列(5 9 3 6 5 7 2 3
)的内部部分。所以算法是:
第一步可以通过以下算法在O(n)
中完成:
max_length = 0
current_length = 0
for i from 2 to len(a) - 1:
if a[i - 1] < a[i] > a[i + 1] or a[i - 1] > a[i] < a[i + 1]:
current_length += 1
else:
max_length = max(max_length, current_length)
current_length = 0
max_length = max(max_length, current_length)
唯一特殊情况是序列总长度为0
或1
。然后整个序列将是最长的之字形子序列。
答案 6 :(得分:0)
#include "iostream"
using namespace std ;
int main(){
int t ; scanf("%d",&t) ;
while(t--){
int n ; scanf("%d",&n) ;
int size1 = 1 , size2 = 1 , seq1 , seq2 , x ;
bool flag1 = true , flag2 = true ;
for(int i=1 ; i<=n ; i++){
scanf("%d",&x) ;
if( i== 1 )seq1 = seq2 = x ;
else {
if( flag1 ){
if( x>seq1){
size1++ ;
seq1 = x ;
flag1 = !flag1 ;
}
else if( x < seq1 )
seq1 = x ;
}
else{
if( x<seq1){
size1++ ;
seq1=x ;
flag1 = !flag1 ;
}
else if( x > seq1 )
seq1 = x ;
}
if( flag2 ){
if( x < seq2 ){
size2++ ;
seq2=x ;
flag2 = !flag2 ;
}
else if( x > seq2 )
seq2 = x ;
}
else {
if( x > seq2 ){
size2++ ;
seq2 = x ;
flag2 = !flag2 ;
}
else if( x < seq2 )
seq2 = x ;
}
}
}
printf("%d\n",max(size1,size2)) ;
}
return 0 ;
}