1. 程式人生 > >【POJ1887 || 2355 || 1631】Testing the CATCHER(最長遞增(遞減)子序列)NYOJ224

【POJ1887 || 2355 || 1631】Testing the CATCHER(最長遞增(遞減)子序列)NYOJ224

幾個題目說的都挺很長,但是最後求的都是最長遞減(遞增)子序列。。。好吧 刷水題。。。

O(n^2)的演算法中:建立一個一維陣列array[j]opt[],array[j]表示序列的元素,opt[i]表示以第i個元素結尾的序列中的最長下降子序列,初始化為1,對於一個opt[i],遍歷前面的每個元素j,如果array[j]>array[i]opt[j]>=opt[i],那麼opt[j]就要加1,在這裡,遍歷前面的每個元素j,尋找此前最大的子序列時間複雜度為O(n),如果我們在一個有序的序列中查詢此前最大的序列長度,我們就可以用二分查詢,時間複雜度就會降為O(logn),總的時間複雜度就會為O(nlogn)

。為此,我們增加一個一維陣列BB[i]表示當前序列為i的末尾元素的最小值。 例如對於序列:4 2 6 3 1 5

i

1

2

3

4

5

6

array

4

2

6

3

1

5

opt

1

1

2

2

1

3

B

1

3

5

構建過程如下:

i=1時,opt[i]=1 B[i]=4(當前為1的序列的末尾元素的最小值)

opt

1

1

1

1

1

1

B

4

i=2時,2不大於4,所以opt[i]=1,B[1]更新為2

opt

1

1

1

1

1

1

B

2

i=3時,6大於2,所以opt[i]=1+1,B[2]更新為6

opt

1

1

2

1

1

1

B

2

6

i=4時,32 6之間,所以opt[i]=1+1,B[2]更新為3

opt

1

1

2

2

1

1

B

2

3

i=5時,1小於2,所以opt[i]=1,B[1]更新為1

opt

1

1

2

2

1

1

B

1

3

i=6時,5大於3,所以opt[i]=2+1,B[3]

更新為5

opt

1

1

2

2

1

3

B

1

3

5

opt[6]就是最後的結果。從構建的過程可以容易的證明一下兩點:B是遞增的。B是當前序列為i的末尾元素的最小值。以上“2不大於4”,“32 6之間”等等的判斷採用二分查詢,所以總的時間複雜度為:O(nlogn),核心的c程式碼如下:

for(i=1;i<=n;i++)
{
num = array[i];
left = 1;
right = Blen;
while(left<=right)
{
mid = (left+right)/2;
if(B[mid]<num)
left = mid+1;
else
right = mid-1;
}
opt[i] = left;
B[left] = num;
if(Blen<left)
Blen = left;
if(max<opt[i])
max = opt[i];
}
printf("%d/n",max);

 

這個是最長遞增子序列