1. 程式人生 > >] 找工作知識儲備(2)---陣列字串那些經典演算法:最大子序列和,最長遞增子序列,最長公共子串,最長公共子序列,字串編輯距離,最長不重複子串,最長迴文子串

] 找工作知識儲備(2)---陣列字串那些經典演算法:最大子序列和,最長遞增子序列,最長公共子串,最長公共子序列,字串編輯距離,最長不重複子串,最長迴文子串

作者:寒小陽

時間:2013年9月。

0、前言

        這一部分的內容原本是打算在之後的字串或者陣列專題裡面寫的,但看著目前火熱進行的各家網際網路公司筆試面試中,出現了其中的一兩個內容,就隨即將這些經典問題整理整理,單寫一篇發上來了。這裡爭取覆蓋面廣一些,列舉了7個最經典的問題,也會是之後大家筆試面試常見到的問題,而每個問題下都列舉了幾種思路,掌握這些經典問題的解題思路和演算法相信對同類型問題的解答都能有幫助。

       這裡總結的幾個問題分別是最大子序列和,最長遞增子序列,最長公共子串,最長公共子序列,字串編輯距離,最長不重複子串,最長迴文子串。其中前兩個問題是針對陣列求解的,後五個問題是針對字串求解的。多數問題都有動態規劃的解法(博主不堪地表示,自己動態規劃也較弱,只能想到一些基本的思路),這些解法需要細細琢磨,可發散式地使用在很多其他的題目上。

一、最大子序列和

這裡把最大子序列和放在第一個位置,它並不是字串相關的問題,事實上它的目的是要找出由陣列成的一維陣列中和最大的連續子序列。比如[0-235-12]應返回9[-9-2-3-5-3]應返回-2

1、動態規劃法

你也許從這兩個例子中已經可以看出,使用動態規劃的方法很容易完成這個任務,只要前i項的和還沒有小於0那麼子序列就一直向後擴充套件,否則丟棄之前的子序列開始新的子序列,同時我們要記下各個子序列的和,最後找到和最大的子序列。但是你可能需要謹慎一些,在整個陣列都為負的情況下,所以初始的和最大值賦值不當的話可能會出問題。

    根據以上的思路我們可以有以下的程式碼:

  1. /********************************************************************** 
  2. 動態規劃求最大子序列和 
  3. **********************************************************************/
  4. int Maxsum(int * arr, int size)  
  5. {  
  6.     int maxSum = -INF; //很重要,初始值賦值為負無窮大
  7.     int sum = 0;  
  8.     for(int i = 0; i < size; ++i)  
  9. {  
  10. //小於0則捨棄
  11.         if(sum < 0)  
  12.         {  
  13.             sum = arr[i];  
  14.         }else
  15.         {  
  16.             sum += arr[i];  
  17.         }  
  18. //比現有最大值大,則替換
  19.         if(sum > maxSum)  
  20.         {  
  21.             maxSum = sum;  
  22.         }  
  23.     }  
  24.     return maxSum;  
  25. }  


  1. /************************************************************************* 
  2. 如果想獲得最大子序列和的初始和結束位置怎麼辦呢?我們知道,每當當前子陣列和的小於0時,便是新一輪子陣列的開始,每當更新最大和時,便對應可能的結束下標,這個時候,只要順便用本輪的起始和結束位置更新始末位置就可以,程式結束,最大子陣列和以及其始末位置便一起被記錄下來了 
  3. *****************************************************************************/
  4. void Maxsum_location(int * arr, int size, int & start, int & end)  
  5. {  
  6.     int maxSum = -INF;  
  7.     int sum = 0;  
  8.     int curstart = start = 0;  /* curstart記錄每次當前起始位置 */
  9.     for(int i = 0; i < size; ++i)  
  10.     {  
  11.         if(sum < 0)  
  12.         {  
  13.             sum = arr[i];  
  14.             curstart = i;     /* 記錄當前的起始位置 */
  15.         }else
  16.         {  
  17.             sum += arr[i];  
  18.         }  
  19.         if(sum > maxSum)  
  20.         {  
  21.             maxSum = sum;  
  22.             start = curstart; /* 記錄並更新最大子陣列起始位置 */
  23.             end = i;  
  24.         }  
  25.     }  
  26. }  


2、分治法

其實陣列的問題,最好留點心,有一大部分題目是可以用分治的辦法完成的,比如說這道題裡面:最大子序列和可能出現在三個地方,1整個出現在輸入資料的左半部分,2整個出現在輸入資料的右半部分,3或者跨越輸入資料的中部從而佔據左右兩個半部分。可以有以下程式碼:

  1. /************************************************************** 
  2. 分治法求解最大子序列和 
  3. ***************************************************************/
  4. int MaxSumRec( const vector<int> & a, int left, int right )  
  5. {  
  6.     if( left == right )  // Base case
  7.         if( a[ left ] > 0 )  
  8.             return a[ left ];  
  9.         else
  10.             return 0;  
  11.     int center = ( left + right ) / 2;  
  12.     int maxLeftSum  = maxSumRec( a, left, center );  
  13.     int maxRightSum = maxSumRec( a, center + 1, right );  
  14.     int maxLeftBorderSum = 0, leftBorderSum = 0;  
  15.     forint i = center; i >= left; i-- )  
  16.     {  
  17.         leftBorderSum += a[ i ];  
  18.         if( leftBorderSum > maxLeftBorderSum )  
  19.             maxLeftBorderSum = leftBorderSum;  
  20.     }  
  21.     int maxRightBorderSum = 0, rightBorderSum = 0;  
  22.     forint j = center + 1; j <= right; j++ )  
  23.     {  
  24.         rightBorderSum += a[ j ];  
  25.         if( rightBorderSum > maxRightBorderSum )  
  26.             maxRightBorderSum = rightBorderSum;  
  27.     }  
  28.     return max3( maxLeftSum, maxRightSum, maxLeftBorderSum + maxRightBorderSum );  
  29. }  


二、最長遞增子序列

和上一問題一樣,這是陣列序列中的問題,比如arr={1,5,8,2,3,4}的最長遞增子序列是1,2,3,4

1、動態規劃法

    結合上一題的思路,在陣列的這類問題裡面使用動態規劃還是很常見的,從後向前分析,很容易想到,i個元素之前的最長遞增子序列的長度要麼是1比如說遞減的數列),要麼就是第i-1個元素之前的最長遞增子序列加1我們可以得到以下關係:

LIS[i] = max{1,LIS[k]+1},其中,對於任意的k<=i-1arr[i] > arr[k],這樣arr[i]才能在arr[k]的基礎上構成一個新的遞增子序列。這種方法程式碼如下:

  1. #include <iostream>
  2. usingnamespace std;  
  3. //動態規劃法求最長遞增子序列 LIS
  4. int dp[101]; /* 設陣列長度不超過100,dp[i]記錄到[0,i]陣列的LIS */
  5. int lis;    /* LIS 長度 */
  6. int LIS(int * arr, int size)  
  7. {  
  8.     for(int i = 0; i < size; ++i)  
  9.     {  
  10.         dp[i] = 1;  
  11.         for(int j = 0; j < i; ++j)  
  12.         {  
  13.             if(arr[i] > arr[j] && dp[i] < dp[j] + 1)  
  14.             {  
  15.                 dp[i] = dp[j] + 1;  
  16.                 if(dp[i] > lis)  
  17.                 {  
  18.                     lis = dp[i];  
  19.                 }  
  20. 相關推薦

    ] 工作知識儲備(2)---陣列字串那些經典演算法大子序列遞增序列公共公共序列字串編輯距離重複

    作者:寒小陽 時間:2013年9月。 0、前言         這一部分的內容原本是打算在之後的字串或者陣列專題裡面寫的,但看著目前火熱進行的各家網際網路公司筆試面試中,出現了其中的一兩個內容,就隨即將這些經典問題整理整理,單寫一

    [置頂] 工作知識儲備(3)---從頭說12種排序演算法原理、圖解、動畫視訊演示、程式碼以及筆試面試題目中的應用

    分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

    工作知識儲備(3)---從頭說12種排序演算法原理、圖解、動畫視訊演示、程式碼以及筆試面試題目中的應用

    作者:寒小陽 0、前言      從這一部分開始直接切入我們計算機網際網路筆試面試中的重頭戲演算法了,初始的想法是找一條主線,比如資料結構或者解題思路方法,將博主見過做過整理過的演算法題逐個分析一遍(博主當年自己學演算法就是用這種比較笨的刷題學的,

    如何字串中第一個重複的字元JavaPython的分別實現

    遇到一個問題,網上有很多教程,在沒看的情況下,自己先寫了幾種方法,僅供參考: Python實現方式:(三種方法,執行效率有差異) # _*_ coding:utf-8 _*_ import time # 傳參方式 str = "=WUKVJPLKKPYBUI=JAOCFCJJIYKGN

    第13屆景馳-埃森哲杯廣東工業大學ACM程式設計大賽 D psd面試(序列區間dp)

    題目描述 掌握未來命運的女神 psd 師兄在拿了朝田詩乃的 buff 後決定去實習。 埃森哲公司註冊成立於愛爾蘭,是一家全球領先的專業服務公司,為客戶提供戰略、諮詢、數字、技術和運營服務及

    leetcode-java.T005_LongestPalindromicSubstringTotal 給定一個字串S出它的大的

    敬請關注部落格,後期不斷更新優質博文,謝謝 每天j堅持刷leetcode----找出最大的迴文字串 package leetcode.T005_LongestPalindromicSubstringTotal; /** * @author 周志祥 E-mai

    對於一個字串請設計一個高效演算法計算其中的長度。

    給定字串A以及它的長度n,請返回最長迴文子串的長度。  測試樣例: "abc1234321ab",12  返回:7 分析與解法 最容易想到的辦法是列舉所有的子串,分別判斷其是否為迴文。這個思路初看起來是正確的,但卻做了很多無用功,如果一個長的子串包含另一個短一些的子

    【HDU - 3068】(Manacher演算法馬拉車演算法

    題幹: 給出一個只由小寫英文字元a,b,c...y,z組成的字串S,求S中最長迴文串的長度.  迴文就是正反讀都是一樣的字串,如aba, abba等 Input 輸入有多組case,不超過120組,每組輸入為一行小寫英文字元a,b,c...y,z組成的字串S  兩

    Leetcode題解中級篇之陣列字串(5)

    題目:https://leetcode-cn.com/explore/interview/card/top-interview-questions-medium/29/array-and-strings/79/ 題目描述: 給定一個字串 s,找到 s 中最長的迴

    給定一個字串s,

    思路1:  1 從每一個迴文對稱點開始向左右遍歷,直到左右字元不相等。求出最長子串。 2 考慮迴文子串可能是奇數長度,對稱點只有一個。也可能是偶數長度。對稱點有倆個 程式碼: string longestPalindrome(string s) { int

    Longest Palindromic Substring 字串

    所謂迴文字串,就是一個字串,從左到右讀和從右到左讀是完全一樣的。比如"level" 、 “aaabbaaa” Given a string s, find the longest palindro

    【動態規劃】求公共

    題目 : 給定兩個字串,求出它們之間連續的最長的相同子字串的長度。 eg : fbaabe,ebaabf,連續最長子串長度為4。 注意:求最長迴文子串也可以用求最長公共子串來求,只需將字串反轉作為另外一個字串,迴文部分反轉之後不變,然後求LCS(Longes

    演算法導論-第15章-動態規劃-15-2 序列(LPS)

    問題描述 迴文序列(Palindromic sequence, Palindrome)是指正向遍歷和反向遍歷完全相同的序列,例如字串“AAAAA”顯然是一個迴文序列,又如字串“[email 

    [C++] 動態規劃之矩陣連乘、公共序列大子單調遞增序列

    每次 種子 () return 避免 amp 可能 text com 一、動態規劃的基本思想   動態規劃算法通常用於求解具有某種最優性質的問題。在這類問題中,可能會有許多可行解。每一個解都對應於一個值,我們希望找到具有最優值的解。   將待求解問題分解成若幹個子問題,先求

    SP1043 GSS1 - Can you answer these queries I(線段樹區間大子(靜態))

    有一種 nbsp 不用 端點 合並 表示 格式 space iostream 題目描述 給出了序列A[1],A[2],…,A[N]。 (a[i]≤15007,1≤N≤50000)。查詢定義如下: 查詢(x,y)=max{a[i]+a[i+1

    大子(在線處理復雜度O(n))

    spa 最大子列和 pts 最大 int nts ups script 程序 #include<stdio.h> int main(){ int k,num,sum=0,Max=0; scanf("%d",&k); while(k--){ s

    [SHOI2015]腦洞治療儀(惡心的線段樹區間大子

    由於 得到 \n define 範圍 ret scan 定義 add 題目描述: 曾經發明了自動刷題機的發明家 SHTSC 又公開了他的新發明:腦洞治療儀——一種可以治療他因為發明而日益增大的腦洞的神秘裝置。 為了簡單起見,我們將大腦視作一個 01 序列。11代表這個位置的

    【SHOI2015】腦洞治療儀(惡心的線段樹區間大子

    -i string 修改 def 由於 返回 系列 lazy long 題目描述: 曾經發明了自動刷題機的發明家 SHTSC 又公開了他的新發明:腦洞治療儀——一種可以治療他因為發明而日益增大的腦洞的神秘裝置。為了簡單起見,我們將大腦視作一個 01

    陣列-BAT面試經典試題絕對眾數陣列大子陣列

    1.絕對眾數問題 定義:給定N個數,稱出現次數最多的數為眾數:若某眾數出現的次數大於N/2,稱該眾數為絕對眾數。 如:A={1,2,1,3,2}中,1和2都是眾數,但都不是絕對眾數;A={1,2,1,3,1}中,1是絕對眾數。 已知給定的N個整數存在絕對眾數,以最低的時空負責度計算該

    【LeetCode】516. 序列

    題目連結:https://leetcode-cn.com/problems/longest-palindromic-subsequence/description/ 題目描述 給定一個字串s,找到其中最長的迴文子序列。可以假設s的最大長度為1000。 示例 輸入: “