求陣列中最長遞增子串行

2021-07-05 03:12:48 字數 3253 閱讀 1890

程式設計之美有一道關於陣列中最長遞增子串行,題目如下:

寫乙個時間複雜度盡可能低的程式,求乙個一維陣列(n個元素)中最長遞增子串行的長度。

例如在序列1,-1,2,-3,4,-5,6,-7中,其最長的遞增子串行的長度為4(如1,2,4,6),從該書給的例子我們可以知道的是其最長的遞增子串行可以不連續的。

作者利用動態規劃方法給了三種解法。

解法一:

根據無後效性的定義,各階段按照一定的次序排列好之後,對於某個給定階段的狀態來說,它以前各階段的狀態無法直接影響它未來的決策,而只能間接地通過當前狀態來影響,如以下目標串:

1,-1,2,-3,4,-5,6,-7

當i=1時,顯然,最長的遞增序列為(1),序列長度為1.

當i=2時,由於-1<1,因此,必須丟棄第乙個值然後重新建立串,當前的遞增序列為(-1),長度為1.

當i=3時,由於2>1,2>-1,因此,最長的遞增序列為(1,2),(-1,2),長度為2,在這裡,2前面是1還是-1對求出後面的遞增序列沒有直接影響。

假設在目標陣列array的前i個元素中,最長遞增子串行的長度為lis[i],那麼用動態規劃可以推出以下公式:

lis[i+1]=max,array[i+1]>array[k],for any k<=i

即如果array[i+1]大於array[k],那麼第k+1個元素可以接在lis[k]長的子串行後面構成乙個更長的子串行,同時array[i+1]本身至少可以構成乙個長度為1的子串行。

從作者的分析角度,我們可以用樹的結構來分析,如圖:

**實現:

#include 

#include

#include

using

namespace

std;

int max(int *a,int len)

int lis(int *a,int len)

return max(lisary,len);

}int main()

; int len=sizeof(a)/sizeof(int);

cout

/隨機測試

for(int i=0;ifor(int j=0;j100+1;

cout

}cout

0;}

整個演算法的時間複雜度為o(n2

+n)=o(n2

).解法二:第二種解法:對於前面i個元素的任何乙個遞增子串行,如果這個子串行的最大元素比array[i+1]小,那麼就可以將array[i+1]載入這個子串行後面構成乙個新的遞增子串行,假設在陣列的前i個元素中,以array[i]為最大元素的最長遞增子串行的長度為lis[i],同時假設:長度為1的遞增子串行最大元素的最小值為maxv[1].

長度為2的遞增子串行最大元素的最小值為maxv[2].

………

長度為lis[i]的遞增子串行最大元素的最小值為maxv[lis[i]].

根據作者分析可以得到如下的公式:

lis[i+1]=max,array[i+1]>maxv[k],k<=maxlislen,其中maxlislen表示當前狀態最長遞增序列的長度

maxv[len]=min,其中ik

<=n,並且滿足lis[i1

]=lis[i2

]=……..=lis[ik

]=len.

**實現:

#include 

#include

#include

using

namespace

std;

int min(int *a,int len)

//如果當前遞增序列大於最長的遞增序列,則更新最長序列

if(lisary[i]>nmaxils)

//改變該遞增序長度的最大元素的值,使其在滿足

//同樣的遞增序列長度情況下,挑選最小元素為最大元素

else

if(maxv[j]1])

}return nmaxils;

}int main()

; int len=sizeof(a)/sizeof(int);

cout

cout

}cout

0;}

整個演算法過程中也是o(n2

).第三種解法:根據上面的第二種解法思路,可以得到以下推論:在遞增序列,如果i

#include 

#include

#include

using

namespace

std;

int min(int *a,int len)

else

else

}

lisary[i]=low;

//更新遞增序列長度為low其最大元素改為更小的a[i]

maxv[low]=a[i];}}

return nmaxils;

}int main()

; int len=sizeof(a)/sizeof(int);

cout

cout

}cout

0;}

整個演算法過程時間複雜度是o(n*lo

g2n).

求陣列中最長遞增子串行

原文見 分析過程很清楚。這裡主要是 部分有改動。完全用c寫的,從檔案中讀入。另外,解法二的程式加了去重,求的是最長單調遞增子串行。求陣列中最長遞增子串行 寫乙個時間複雜度盡可能低的程式,求乙個一維陣列 n個元素 中的最長遞增子串行的長度。例如 在序列1,1,2,3,4,5,6,7中,其最長的遞增子串...

求陣列中最長遞增子串行

最長遞增子串行,longest increasing subsequence 下面我們簡記為 lis。排序 lcs演算法 以及 dp演算法就忽略了,這兩個太容易理解了。假設存在乙個序列d 1.9 2 1 5 3 6 4 8 9 7,可以看出來它的lis長度為5。下面一步一步試著找出它。我們定義乙個序...

求陣列中最長遞增子串行

根據 程式設計之美 中解法二的思路,發現記錄lis陣列是不必要的,只要直接不斷更新maxv即可。在遍歷整個陣列arr的過程中,maxv陣列的長度也在不斷增加。當遍歷到arr i 時,maxv j 中已經記錄了由arr 0 arr i 的序列可以得到的所有長度為j的子串行中最大元素的最小值。例如 ar...