這是乙個比較古老的演算法問題,在上學期的演算法課中也有所講解,不過當初並沒有理解到位,現在重新思考一下。
最長遞增子串行問題:給定乙個序列,找出其中最長的乙個序列,並且滿足對任意的 0 < n,m < j,都有bn < bm。
最樸素的一種解法是從a0開始,對給定序列進行遍歷,在遇到分叉時產生分支,最後將最長的序列更新出來。遍歷到an時便得到最大的遞增序列。這種做法較為簡單,但是不可取,因為對每乙個ai而言求以它為開頭的遞增序列可能會產生大量分支,嚴重影響了求解速度。
對上面的解法我們可以增加乙個剪枝,如果當前要進行遍歷的元素是前面某乙個最長序列的一部分,那麼他的序列長度肯定較小,便可以跳過此元素,直接判斷下乙個即可。
但是這樣還是很慢,乙個只有1000個數的序列,要找出最長子序列大概需要2s,這是不可容忍的,所以我搬出了動態規劃。在這個問題裡面,前n的數與前n-1個數的最長鏈有一定的聯絡。如果第n個數大於前面n-1個數中最長鏈的末端,那麼更新,否則尋找鏈中合適的元素重新構成子串行(自身有可能是頭元素)。
對這個演算法,我想出了以下解法:
對每個元素為末尾進行遍歷,對第i個元素,需要遍歷前i-1個元素的最長子序列進行判斷。然後按照演算法更新相關資料,這樣可以保證到第n個元素的時候一定是最長子序列。最後我按逆序輸出,如果順序輸出的話單獨開個陣列儲存一下就好。
//關於最長子序列問題的思索
#include
int data[1000];//儲存資料
int answer[1000];//最長鏈長度
intlist[1000];//前導元素
int max;//最長鏈
int index;//最長鏈末尾索引
int main()
}if(answer[i] > max)
}n = list[index];
while(n != index)
printf("%d\n",data[n]);
}return
0;}
這個相比之前速度快了很多,乙個1000的序列,大概100ms左右可以解決。那麼還能優化嗎?關鍵點應該在於在求前n個數的時候要對前n-1個數進行遍歷,如果我們能夠使用二分的思想優化,那麼這個問題的時間就從乙個n^2減小到nlog(n)。
int search(int );
int count;
int answer[1000];
int main()
}printf("%d\n",count+1);
}}int search(int number)
return mid + 1;}
這種方法占用記憶體較少 如果只是計數的話並不用儲存之前的結果。
如果要輸出最長鏈 只需要單獨申請乙個陣列用來儲存最長鏈 通過對比鏈中元素在最長鏈長度改變時進行相關的更新
最長遞增子串行
這是微軟實習生筆試遇到的,題意 求乙個陣列中最長遞增子串行的長度。要求選擇該題最好演算法的時間複雜度和空間複雜度。答案 時間複雜度o nlgn 空間複雜度o n 這題明顯用動態規劃來解。假設在目標陣列array 的前i個元素中,以array i 元素為最大元素的遞增子串行的長度是lis i 那麼 遞...
最長遞增子串行
最長遞增子串行又叫做最長上公升子串行 子串行,正如lcs一樣,元素不一定要求連續。本節討論實現三種常見方法,主要是練手。題 求乙個一維陣列arr i 中的最長遞增子串行的長度,如在序列1,1,2,3,4,5,6,7中,最長遞增子串行長度為4,可以是1,2,4,6,也可以是 1,2,4,6。方法一 d...
最長遞增子串行
最長遞增子串行 求乙個字串的最長遞增子串行 如 dabdbf最長遞增子串行就是abdf,長度為4 這是一道基本的動態規劃求解的題目,與此類似的還有 最長公共子串行 分析 用一維陣列dp i 來儲存以a i 為末元素的最長遞增子串行的長度,那麼dp i 至少為1 即包含它本身 往前尋找,如果存在a j...