1. 程式人生 > >CS3K.com 九章演算法強化班

CS3K.com 九章演算法強化班

Advanced Data Structure -- Union Find

Number of Islands

題目

 思路I:BFS 避免相同位置的元素重複入列,訪問過的元素都要標記為已訪問。BFS為了得到下一個點的座標,所以需要建立一個表示位置的座標類。

View Code

思路II:並查集 等價於求集合中連通塊的個數。

View Code

 

Number of Islands II

題目

思路:並查集,把二維陣列轉化為一維father陣列。

View Code

 

LeetCode 547. Friend Circles

題目

思路:並查集的典型應用。題目是求朋友圈的個數,求將這n個人看成n個節點,等價於求連通塊的個數。

View Code

 

Graph Valid Tree

題目

思路I:BFS  最後判斷連通的節點個數是否為n。

View Code

思路II:並查集  判斷n - 1條邊是否構成環,即判斷是否有兩個點的father一樣。

View Code

 

Surrounded Reigions

題目

思路I:BFS  BFS二位矩陣的四周,講從外向內的字元O都標記為字元V代表已訪問過的字元O,然後依次便利整個二位矩陣,字元為O的都是除了四周的裡面的O,將它置為字元X,為V的字元還原成原來的字元O。

View Code

 思路II:並查集 建立一個n * m的dummy node,遍歷二維陣列,邊上的為字元O的直接合併到dummy node, 在裡面的字元為O的根據情況合併,如果該字元與相鄰字元O的parent一樣就不合並,如果不一樣分兩種情況,如果該字元的parent為dummy node就將相鄰字元O合併到該字元的parent,否則將該字元的parent合併到相鄰字元O的parent。最後再遍歷一次二維陣列,字元為O並且該字元的parent不是dummy node就將該字元置為字元X。也就是說,不能被包圍的字元O的parent都是dummy node,能被包圍的字元O的parent都不是dummy node。

View Code

 

Advanced Data Structure -- Trie 

Implement Trie

View Code

思路:trie樹的插入,查詢,前最匹配。需要注意一點的就是儲存子節點的HashMap不能再構造方法裡初始化,而是要在定義的時候直接初始化,這是為了覆蓋dummy root的HashMap子節點情況。

View Code

 

Add and Search Word

題目

思路:類似上題,trie樹的新增可以更加簡化。查詢單詞要遞迴。

View Code

 

Word Search

題目

思路:DFS 記得dfs的過程中把訪問過的字元標記稱某一特殊字元來表示訪問過這一字元,避免重複訪問。

time:O(n*m*4^len)  space:O(len) + O(n*m)

View Code

 

Word Search II

題目

思路:1. 把字典建成Trie樹。2. 用dfs的方法遍歷矩陣,同時在Trie上搜索字首是否存在。 3. 查詢所有Trie裡面有可能出現的字元。 注意找到string之後還要繼續往下低軌而不是return,因為下面也可能有要找的string。同時TrieNode中多了一個字串s來代表從根走到當前位置的字串,也就是插入的字串。

View Code

 

Word Squares

題目

 思路:Trie + DFS。先構建trie,新增一個List<String> startWith屬性表示包含以當前字元結尾的字首的所有單詞的集合。然後DFS遍歷,注意下一個可能構成word squares的單詞的字首是由前面的單詞嚴格限制的,也就是說下一個單子的字首是固定的,在trie中找到包含這個字首的所有可能的單詞(startWith),對這些單詞進行下一輪DFS。

View Code

  

Boggle Game

題目

思路:trie + DFS 不得不說這道題真的難,搞了半天。

View Code

 

 

139. Word Break

題目

思路:DP 兩種DP方法,第一種是j從0遍歷到i- 1,時間複雜度O(len^2),len為字串s的長度。適用於字典大,s短的情況。

View Code

     第二種是遍歷字典中的每個單詞的長度,如果canSegment[i - word.length()] == true && s.substring(i - word.length(), i).equals(當前遍歷的單詞),那麼canSegment[i]為true。時間複雜度O(len * size),len為字串s的長度,size為字典的大小。適用於字典小,s大的情況。而且本題中字典為list而不是set,判斷list是否含有某個元素的contains方法時間複雜度是O(size)的不是O(1),所以建議使用第二種方法。

View Code

 

140. Word Break II

題目

思路:和上一題不同的是,這道題要返回所有可能的組合。所以現在dp[i]裡面應該存可以使長度為i所有可能的String裡的最後一個word。dp有兩種寫法,一個就是直接寫成陣列:List[]的形式,不能形成的dp[i] = null。還有一個是用個hashmap:Map<Integer, List>,用hashmap的好處是如果s很長而且用dict能組合成的長度不是很多的話,map用的空間相對少。dp結束之後,第二步就是通過dp裡面儲存的word,一步一步回溯找到所有結果。

View Code

 

472. Concatenated Words

題目

思路I:DP 常規思路是遍歷陣列中的每一個單詞,然後對該單詞,檢視該單詞是否能右陣列中剩餘的元素組成,這樣做時間複雜度過高。需要進行優化,一個單詞要想被其他片語成,其他詞的長度必然小於這個詞的長度,於是先對陣列按各單詞長度進行從小到大排序,然後每次遍歷過程中,用一個set來儲存比當前單詞長度小的單詞,也就是說set儲存的是能組成當前單詞的候選單詞,在遍歷過程中如果當前單詞能由set裡的單片語成(這個過程借用Word Break這道題的DP思路),就把當前單詞加入到結果中。最後迴圈結束就可以返回結果了。

View Code

 思路II:trie Trie 先將各個單詞插入到Trie樹,然後對每個單詞,判斷它是否能由其他單片語成。

View Code

 

Find the Weak Connected Component in the Directed Graph

題目

思路:並查集 由於節點的值不確定,所以用HashMap來儲存一個節點和它的父節點的對映關係而不是用陣列儲存,注意用HashMap來儲存的時候並查集中的find函式的寫法!

View Code

 

Sweep Line

Building Outline

題目

思路I:使用PriorityQueue

我的解法:用一個帶最大堆的掃描線遍歷陣列,每出現一個拐點則記錄一次區間。新加入一個元素後若堆頂元素和之前不同,則表明出現拐點。

  1. 首先處理陣列中元素。將每一個點用一個point來儲存,儲存time(開始寫錯了,應該是位置,但是要改的太多了),flag(起點為1,終點為0),height。用一個HashMap來記錄每一對終點和起點(終點為key,起點為value)。

  2. 將所有point儲存在一個list中並排序,首先根據時間從小到大排序,若時間相等則根據flag排序(先起點後終點),若flag也相等則根據height排序(若同為起點則從大到小排序,若同為終點則從小到大排序)。這樣可以避免重複解。

  3. 再構建一個最大堆,用於記錄加入的元素的最大值。

  4. 開始遍歷list中每個point,起點元素加入堆,終點元素刪去堆中對應的起點元素。

  5. 當遇到一個起點元素時,先記錄加入前堆頂元素,然後將該起點元素加入,再看加入後堆頂元素,1)若沒有變化,則繼續下一個point;2)若有變化,則說明出現拐點,將之前堆頂元素時間作為起點,當前堆頂元素時間作為終點,之前堆頂元素高度作為高度。注意:就算堆頂元素變化,但是如果之前堆頂元素和當前堆頂元素時間相同,說明是在這個時間連續有幾個起點被加入,寬度為0,不能算一個區間。

  6. 當遇到一個終點元素時,將其對應的起點元素從堆中刪除。若此時堆為空,則和5中一樣記錄一個區間,並繼續下一個point。若堆不為空,則需要看此時堆頂元素是否改變。若不變則繼續,否則說明出現“拐點”。此處“拐點”要分兩種情況討論: 1)若新的堆頂元素高度和之前堆頂元素高度相同,則說明相同高度的兩段區間有重疊,題目要求若發生這種情況要合併這兩段區間,所以我們要保留之前的堆頂元素(兩段同高度相同重疊區間的最左邊),刪去新的堆頂元素(即代替原堆頂元素被刪除,因為每遇到一個終點必須刪去一個起點),具體做法可以是先刪去新堆頂元素,再加入原堆頂元素,或者直接將新堆頂元素時間改為原堆頂元素時間。 2)若新堆頂和原堆頂元素高度不同,則像5中那樣記錄一個區間,但是要將現在的堆頂元素時間改為遇到的終點元素的時間。

  7. 遍歷完整個list結束

View Code

思路II:自定義HashHeap堆可以將PriorityQueue中O(n)的remove操作優化到O(lgn)的remove操作。注意點已經在程式碼中標出。

View Code

 

Advanced Data Structure -- Segment Tree

Segment Tree Build

題目

思路:很簡單,類似寫建立二叉樹的程式。

View Code

 

Segment Tree Build II

題目

思路:多了求每個區間的最大值,navie做法是每次建立某一區間節點,就呼叫findMax()函式在陣列中的該區間內找最大值,這個沒必要,我們可以從左右區間子樹的max屬性來更新當前區間節點的max。

View Code

 

Segment Tree Query

題目

思路:查詢給定區間中的最大值,根據給定區間與當前區間節點的三種位置關係來執行相應的操作,注意要包含給定區間超過原有區間範圍的情況。

View Code

 

Segment Tree Query II

題目

思路:查詢給定區間中的元素個數,根據給定區間與當前區間節點的三種位置關係來執行相應的操作,注意要包含給定區間超過原有區間範圍的情況。

View Code

 

Segment Tree Modify

題目

思路:改變某一元素的值從而更新線段樹。根據要改變值的索引index與當前區間的中點mid的大小關係來選擇相應的操作,記得從小到大更新遍歷過的區間的max屬性。

View Code

 

Interval Sum

題目

思路:線段樹build + query的結合,注意query函式中是start ~ end與當前線段樹節點的root.start ~ root.end相比,所以query中mid = root.start + (root.end - root.start) / 2,是當前線段樹節點的區間中點,不要誤寫成start + (end - start) / 2,錯弄成待查詢的區間中點,這個錯誤非常容易犯。

View Code

 

Interval Sum II

題目

思路:線段樹build + modify + query的結合。

View Code

 

Interval Minimum Number

題目

思路:線段樹build + query結合,只要熟悉線段樹的模版,寫起來很容易。

View Code

 

Count of Smaller Number

題目

思路I:陣列中最小值min,最大值max,map儲存每個元素出現的次數,以這三個來構建線段樹。注意這一題的邊界情況,queries陣列len >= 1時,對每一個詢問必須有返回值(0或者非0),當A陣列為空或者len == 0時不能直接返回空的list,而是返回長度為queries.length,元素都為0的list。

View Code

 思路II:考慮可擴充套件性,同Count of Smaller Number before itself。

View Code

 

Count of Smaller Number before Itself

題目

思路:將陣列A中的元素作為索引,對應的值為該元素個數,建立線段樹。每次遍歷A中的元素時,先線上段樹中query,再modify,更新線段樹中節點的count值。

View Code

 

Min Stack

題目

思路I:兩個棧,一個棧stack儲存元素,另一個棧minStack儲存當前stack中的最小值,minStack元素個數等於stack中的元素個數。

View Code

優化:minStack只儲存小於等於當前minStack棧頂元素的值。但是空間複雜度不會改變。

View Code

 

Largest Rectangle in Histogram

題目

思路:單調棧  注意迴圈次數為length + 1次!!!棧中儲存的是索引。

View Code

 

Maximal Rectangle

題目

思路:單調棧  二維陣列從上到下累計直方圖的高度,每一行看作是直方圖的寬度。然後轉化為求每一行的直方圖能構成的最大面積即轉化成Largest Rectangle in Histogram問題。

View Code

 

Max Tree

題目

思路I:分治法  但是時間複雜度最壞可達到O(n^2),棧深過大會溢位,如升序序列。

View Code

思路II:單調遞減棧,找出每個數往左數第一個比他大的數和往右數第一個比他大的數,兩者中較小的數即為該數的父親節點。每個數往左數第一個比他大的數用單調遞減棧來維護,當遇到往右數第一個比他大的數就把棧頂元素pop出來,補充該節點與父親節點的關係。迴圈次數為length(陣列長度) + 1。為了完善所有節點的關係,虛擬出一個節點,值為Integer.MAX_VALUE,確保所有節點的關係。

View Code

 

Expression Tree Build

題目

 思路:首先定義一個Node,對於每一個符號或者數字,附上一個val,以便於之後evaluate它,來建立樹

    如果expression[i]等於"("或者")"調整base然後continue跳過後面的步驟

    維護一個單調遞增stack,建立最小樹,類似題[Max Tree]

View Code

 

Expression Evaluation

題目

思路:兩個棧,一個棧存數字,一個棧存操作符。

入棧操作:

   1. 遇到"(",放入操作符棧

   2. 遇到")",取出數字棧中兩個數與操作符棧中一個操作符運算,將結果存入數字棧,迴圈該過程直到遇到"(",然後從操作符棧中pop出"("。

   3. 遇到操作符,如果當前操作符棧中的優先順序等於或者高於(等於也要運算,防止類似"999/3/3/3"表示式執行錯誤的運算順序)該操作符,取出數字棧中兩       個數與操作符棧中一個操作符運算,將結果存入數字棧,迴圈該過程,直到當前操作符棧中的優先順序小於該操作符或者遇到"("。

   4. 遇到數字,直接存入數字棧。

出棧操作:  

   然後對數字棧和操作符棧中剩餘的元素進行:取出數字棧中兩個數與操作符棧中一個操作符運算,將結果存入數字棧,迴圈該過程。最後操作符棧應該為空,    數字棧只剩下一個數,返回這個數。注意這裡需要判斷數字棧是否為空,比如表示式"((()))"執行程式後數字棧為空,返回0;不為空才返回這個數。

View Code

 

Convert Expression to Reverse Polish Notation

題目

思路:先Expression Tree Build,然後後序遍歷該樹就能求出逆波蘭表示法。逆波蘭表示法實際上就是二叉樹的後序遍歷。

View Code

 

Convert Expression to Polish Notation

題目

思路:先Expression Tree Build,然後前序遍歷該樹就能求出波蘭表示法。波蘭表示法實際上就是二叉樹的前序遍歷。

View Code

 

Find Peak Element

題目

思路:根據A[mid]與A[mid - 1](單調性)來二分

View Code

 

Find Peak Element II

題目

思路I:根據列取最大值,根據上一行對應位置或者下一行對應位置是否比該位置的值大來進行二分。時間複雜度O(nlgn)

View Code

思路II:採用思路I,但是交替按照行和列進行二分。時間複雜度O(n)

View Code

 

Sqrt(x)

題目

思路:從0 ~ x二分答案。易錯點:mid * mid很容易超過整數表示範圍,所以check的時候記得轉為long比較。

View Code

 

Sqrt(x) II

題目

思路:從0 ~ x二分答案。易錯點:由於二分的是double數,當這個二分數<1時你永遠也不可能二分到想要的答案,最後的二分結果就是這個數本身,所以這種情況下end的取值應該置為1才行。還有注意浮點數二分的二分模版上與整數二分的不同,while是end - start是大於某個精度(比題目給定的精度還要小以保證結果的正確性)迴圈。

View Code

 

Find the Duplicate Number

題目

思路:從可能的答案範圍1 ~ n進行二分,當在陣列中小於等於mid的元素個數等於mid說明小於等於mid的元素都不是重複元素,反之小於等於mid的元素中含有重複元素。

View Code

 

Wood Cut

題目

思路:二分這些木頭所能切割成的相等木頭的長度,注意二分的區間,既然是長度,範圍是1 ~ max(這些木頭的長度),不能從0開始,因為所得到的長度不可能是0,0代表不存在這樣的長度。Last/Biggest length that can get >= k pieces。

View Code

 

Copy Books

題目

思路:Smallest time that k people can copy all books。二分抄書所需要的時間,範圍是max(抄每本書的時間)~sum(抄每本書的時間),而且答案一定在這個範圍內!對每一個二分的抄書時間,判斷在這個時間下k個人能不能抄完所有書,這個判斷可以轉化為在這個時間下所需要的最小抄書人數是不是小於等於k。

View Code

 

Maximum Average Subarray

題目

 思路:涉及子陣列問題用到prefix_sum,sum[i] = sum[i - 1] + num[i - 1]。最大平均和轉化為原陣列中每一個元素減去二分的mid所得到的陣列中是否有一段長度大於等於k的subArray的和大於等於0.

View Code

 

第5周 & 第6周 ----  Dynamic Programming

Maximal Square

題目

思路:1.狀態  dp[i][j] 表示以i和j作為正方形右下角可以拓展的最大邊長 

   2.方程  if matrix[i][j] == 1  dp[i][j] = min(left[i][j-1], up[i-1][j], dp[i-1][j-1]) + 1  

        (upper[i][j] 表示以i, j 作為全為1的向上長條有多長,left[i][j] 表示以i, j 作為全為1的向左長條有多長,)

        if matrix[i][j] == 0  dp[i][j] = 0 

        然而我們可以將上面這個狀態轉移方程簡化如下面這個:

        if matrix[i][j] == 1  dp[i][j] = min(dp[i - 1][j], dp[i][j-1], dp[i-1][j-1]) + 1;

        if matrix[i][j] == 0  dp[i][j] = 0 

   3.初始化 f[i][0] = matrix[i][0];

        f[0][j] = matrix[0][j] 

   4.答案  max{dp[i][j]} * max{dp[i][j]} 

View Code

 

Maximal Square II

題目

思路:1.狀態  dp[i][j] 表示以i和j作為正方形右下角可以拓展的最大邊長

        upper[i][j] 表示以i, j 作為全為0的向上長條有多長

        left[i][j] 表示以i, j 作為全為0的向左長條有多長

   2.方程  if matrix[i][j] == 1  dp[i][j] = 1 + Math.min(dp[i - 1][j - 1], Math.min(up[i - 1][j], left[i][j - 1]))

                     up[i][j] = 0

                     left[i][j] = 0

        if matrix[i][j] == 0  dp[i][j] = 0

                     up[i][j] = 1 + up[i - 1][j]

                     left[i][j] = 1 + left[i][j - 1]

   3.初始化  不需要

   4.答案  max{dp[i][j]} * max{dp[i][j]} 

View Code

 

區間類DP

特點:1. 求一段區間的解max/min/count

   2. 轉移方程通過區間更新

   3. 從大到小的更新

 

Stone Game

題目

思路:1.狀態  dp[i][j] 表示把第i到第j個石子合併到一起的最小花費 

   2.方程  dp[i][j] = min(dp[i][k]+dp[k+1][j]+sum[i,j]) (記得提前初始化sum[i][j])  for k: i ~ j - 1

   3.初始化 dp[i][i] = 0 

   4.答案  dp[0][n-1] 

View Code

 

Stone Game II

題目

思路:陣列變成迴圈陣列。解決迴圈方式有三種:1.拆環  2.複製  3.取反

   這裡採用複製陣列的方式解決迴圈問題。複製前len - 1個元素到原陣列末尾,對得到的新陣列用Stone Game中一樣的方法DP,最後在得到的dp陣列中找到長度為len並且score最小子陣列。

   1.狀態  dp[i][j] 表示把第i到第j個石子合併到一起的最小花費 (dp[2 * n - 1][2 * n - 1])

   2.方程  dp[i][j] = min(dp[i][k]+dp[k+1][j]+sum[i,j]) (記得提前初始化sum[i][j])  for k: i ~ j - 1

   3.初始化 dp[i][i] = 0 

   4.答案  dp[i][i + n - 1]  for i : 0 ~ n - 1 

View Code

 

Copy Books

題目

思路I:二分法。二分答案,即二分抄完書所花費的最短時間。初始範圍max ~ sum。如果這些人在二分的時間mid內抄完書所用的最少人數(貪心來求該人數)<=k,說明能完成任務,時間end=mid;否則start = mid。最後Double Check。

View Code

思路II:動態規劃。思路同Copy Books II。需要預先求得一個人抄完前i本書所花費的時間sum[i]陣列,為狀態方程做準備。

   1.狀態  dp[i][j] 表示前i+1個人,抄前j本書的最小完成時間。

   2.方程  dp[i][j] = min{max{dp[i - 1][j - k], sum[j] - sum[j - k]}}  for k:0 ~ j

   3.初始化 dp[0][j] = sum[j] for j:0 ~ n;  dp[i][0] = 0 for i:0 ~ len - 1

   4.答案  dp[len - 1][n]

View Code

 

Copy Books II

題目

思路:1.狀態  dp[i][j] 表示前i+1個人,抄前j本書的最小完成時間。

   2.方程  dp[i][j] = min{max{dp[i - 1][j - k], k * times[i]}} for k:0 ~ j

   3.初始化 dp[0][j] = j * times[0] for j:0 ~ n;dp[i][0] = 0 for i:0 ~ len - 1

   4.答案  dp[len-1][n]

注意:這道題卡時間複雜度和空間複雜度,程式碼中要注意的地方已經標記。

View Code

 

Post Office Problem

題目

思路:

dp[i][j]表示在前i個村莊中建j個post的最短距離,l為分隔點,可以將問題轉化為在前l個村莊建j-1個post的最短距離+在第l+1到第i個村莊建1個post的最短距離。其中有個性質,如元素是單調排列的,則在中間位置到各個元素的距離和最小。

  1. 初始化dis矩陣,列舉不同開頭和結尾的村莊之間建1個post的最小距離,即求出開頭和結尾村莊的中間點,然後計算開頭到結尾的所有點到中間點的距離。記得要對原矩陣排序,這樣才能用中間點距離最小性質。

  2. 初始化dp矩陣,即初始化dp[i][1],求前i個村莊建1個post的最小距離(可根據dis求出)。

  3. post數l從2列舉到k,開始村莊i從j列舉到結尾(因為要建j個post至少需要j個村莊,否則沒有意義,其實可以從j + 1開始列舉),然後根據狀態函式求dp[i][j],分割點l從j-1列舉到i-1(前l個村莊建j-1個post則至少需要j-1個村莊),在這些分隔點的情況下求dp[i][j]的最小值。

4.返回dp[n][k]即可。

   1.狀態  dp[i][j] 表示前i個村莊中建j個郵局的最短距離

   2.方程  dp[i][j] = min{dp[l][j - 1] + dis[l + 1][i]  for j - 1 <= l < i}

   3.初始化 dp[i][1] = dis[1][i]  for 1 <= i <= n

   4.答案  dp[n][k]

View Code

 

 雙序列DP

1. state: f[i][j]代表了第一個sequence的前i個數字/字元,配上第二個sequence的前j個...

2. function: f[i][j] = 研究第i個和第j個的匹配關係
3. initialize: f[i][0] 和 f[0][i]
4. answer: f[n][m] min/max/數目/存在關係

5. n = s1.length()  m = s2.length() 

解題技巧畫矩陣,填寫矩陣 

 

Edit Distance

題目

思路:1.狀態  dp[i][j]表示A的前i個字元最少要用幾次編輯可以變成B的前j個字元

   2.方程  A[i - 1] == B[j - 1],dp[i][i] = dp[i - 1][j - 1];A[i - 1] != B[j - 1],dp[i][j] = 1 + Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]),         dp[i - 1][j - 1])。

   3.初始化 dp[i][0] = i  dp[0][j] = j

   4.答案  dp[n][m]

   5. 可以用滾動陣列優化空間複雜度

View Code

 

K Edit Distance

題目

思路:暴力法,按Edit Distance思路對每個word計算最短編輯距離然後判斷該距離是否小於等於k,不可取。考慮到這些word有很多重複,因此這些word可以用trie樹來儲存,從而減少重複字母的最小編輯距離的計算。也就是在trie樹上跑動態規劃。

View Code

 

動態規劃 & 貪心

121. Best Time to Buy and Sell Stock

題目

思路I:動態規劃  動態規劃的一般方式是利用一個數組dp[]用來儲存如果以今天結尾, 能得到的結果。 對於我們這個問題來說, 就是用來儲存到第i天的為止, 如果只能買賣一次股票, 所能獲得的最大收益。 這個收益和截止到前一天為止的最大收益有關 — 或者說是昨天的收益有關, 我們將這個收益稱為A。 它還和今天的股價有關, 確切的說, 是和今天的股價和截止到今天為止的最小股價的差有關, 這個差即為如果今天賣出, 可以得到 的最大收益, 我們將這個收益稱為B。 今天的最終最大收益則為A和B中大的那個。

View Code

思路II:貪心  如果用貪心的思想, 我們不需要儲存每天的狀態, 而只需要儲存截至到目前為止最大的收益即可, 則最後一天的最大的收益即為最後的收益。

View Code

 

122. Best Time to Buy and Sell Stock II

題目

這道題與前一道題的區別在於, 我們可以買賣股票很多次(as many as you want), 求最大收益。

這道題相對簡單,不要把自己繞進去,其實只要比較是不是今天比昨天貴, 不用管之前的情況。舉個簡單的栗子,比如考慮第三天的情況的時候, 因為day3 - day1 = day3 - day2 + day2 - day1, 而day2 - day1 又已經包含在dp[day2]中,所以,只要day3比day2大,則,dp[day3] = dp[day2] + day3 - day2

思路I:動態規劃

View Code

思路II:貪心

View Code

 

309. Best Time to Buy and Sell Stock with Cooldown

題目

思路:動態規劃

很好的一道題, 很容易把自己繞乎進去。

每天都有兩種可能性,要麼賣,要麼啥都不幹。 當然這天的最大收益則是這兩個方案中大的那個。 按照DP的思想,不如開兩個陣列,一個表示今天要賣,另一個表示今天啥也不幹。

profitDoNothing[i]比較容易想,因為今天啥也不幹,所以今天就繼承昨天的結果,昨天的結果又有兩種可能 --- 賣、啥也不幹,當然要繼承它倆中大的那個,所以profitDoNothing[i] = Math.max(profitSell[i-1], profitDoNothing[i-1])。

重點來了,profitSell[i]怎麼算。其實也有兩種情況,如果day[i-1]我買入了(或者賣了,因為賣完了可以再買回來),則day[i]可以直接賣,收益是:profitSell[i] = profitSell[i-1] + prices[i] - prices[i-1]。但是還有一種情況,就是day[i-1]是啥也沒幹的,所以day[i]需要把自己先買回來,再賣,收益是:profitSell[i] = profitDoNothing[i-1] + prices[i] - prices[i] = profitDoNothing[i-1]。最終取這兩個大的就行了。

View Code

思路II:貪心

仔細看你的動態規劃的狀態轉移方程,你會發現其實你不需要一個數組,你只需要兩個數: profitSell & profitDoNothing  然後每次比較的時候建立一箇中間變數即可。

相關推薦

CS3K.com 演算法強化班

Advanced Data Structure -- Union Find Number of Islands 題目  思路I:BFS 避免相同位置的元素重複入列,訪問過的元素都要標記為已訪問。BFS為了得到下一個點的座標,所以需要建立一個表示位置的座標類。 View Co

CS3K.com 演算法基礎班

Remove Substrings 題目 思路:很容易想到貪心,能儘量削減原串就削減原串,但是貪心是錯誤的,反例:"abcabd", ["ab","abcd"]    用DFS,對於dict中的每一個子串,在原串中找到匹配的該串的索引,並擷取原字串,更新結果,將擷取後的字串加入到佇列中(增加一

[CS3K.com]演算法 課程 視訊 錄製 免費下載

九章演算法 課程 視訊 錄製 免費下載 [ 九章演算法班 ] 課程 完整 視訊 錄製 免費下載 最新一期 << 九章演算法班 >> 課程完整視訊錄製, 課件打包下載, 百度雲盤 地址 ! 本站長期提供九章演算法免費課程視訊 與 課件打包下

CS3K.com 演算法 課程 視訊 錄製 免費下載

CS3K.com 九章演算法 課程 視訊 錄製 免費下載 [ 九章演算法班 ] 課程 完整 視訊 錄製 免費下載 最新一期 << 九章演算法班 >> 課程完整視訊錄製, 課件打包下載, 百度雲盤 地址 ! 本站長期提供九章演算法免費課程視

CS3K.com 演算法 課程 視訊 錄製 免費下載

CS3K.com 九章演算法 課程 視訊 錄製 免費下載 [ 九章演算法班 ] 課程 完整 視訊 錄製 免費下載 最新一期 << 九章演算法班 >> 課程完整視訊錄製, 課件打包下載, 百度雲盤 地址 ! 本站長期提供九章演算法免費課程視

CS3K.com 算法 課程 視頻 錄制 免費下載

修改 百度雲盤 message sql linked bigdata 分析 red 規劃 [ 九章算法班 ] 課程 完整 視頻 錄制 免費下載最新一期 << 九章算法班 >> 課程完整視頻錄制, 課件打包下載, 百度雲盤 地址 ! 本站長期提供九章算

CS3K.com 算法基礎班

子串匹配 pre 一位 mov gif set 並且 原來 位數 Remove Substrings 題目 思路:很容易想到貪心,能盡量削減原串就削減原串,但是貪心是錯誤的,反例:"abcabd", ["ab","abcd"]    用DFS,對於dict中的每一個子串,在

[www.cs150.com]演算法 課程 視訊 錄製 免費下載

九章演算法視訊教程傳送門:www.cs150.com [ 九章演算法強化班 ] 課程 完整 視訊 錄製 免費下載 最新一期 << 九章演算法強化班 >> 課程完整視訊錄製, 課件打包下載, 百度雲盤 地址 ! 本站長期提供九章演算法免費課

演算法 課程 視訊 錄製 免費下載 [cs150.com]

九章演算法視訊教程傳送門:www.cs150.com [ 九章演算法強化班 ] 課程 完整 視訊 錄製 免費下載 最新一期 << 九章演算法強化班 >> 課程完整視訊錄製, 課件打包下載, 百度雲盤 地址 ! 本站長期提供九章演算法免費課

演算法 課程 視訊 錄製 免費下載 cs150.com

[ 九章演算法強化班 ] 課程 完整 視訊 錄製 免費下載 最新一期 << 九章演算法強化班 >> 課程完整視訊錄製, 課件打包下載, 百度雲盤 地址 ! 本站長期提供九章演算法免費課程視訊 與 課件打包下載 Big Table 教學To

演算法筆記 5.深度優先搜尋 Depth First Search

DFS cs3k.com 什麼時候用dfs? 短, 小, 最問題 而90%DFS的題, 要麼是排列, 要麼是組合 組合搜尋問題 Combination 問題模型:求出所有滿足條件的“組合” 判斷條件:組合中的元素是順序無關的 時間複雜度:與 2^n 相關 遞迴三要素 一般來說,如果面試官不特

演算法筆記 4.寬度優先搜尋 Breadth First Search

演算法與題型 cs3k.com DFS: 用於搜尋, 題目中有ALL字樣 二分法: 用於時間複雜度小於O(n)的情況 分治法: 二叉樹問題, 子問題和父問題有關係 BFS:- 二叉樹上的寬搜- 圖上的寬搜: 拓撲排序- 棋盤上的寬搜   什麼時候應該用BFS? 圖

演算法筆記 3.二叉樹與分治演算法Binary Tree & Divide Conquer

大綱 cs3k.com • 時間複雜度訓練 II • 二叉樹的遍歷演算法 Traverse in Binary Tree Preorder / Inorder / Postorder • 二叉樹的深度優先搜尋 DFS in Binary Tree 1.遍歷問題 Preorder

演算法筆記 2.Binary Search

大綱 cs3k.com 第一境界 二分法模板 • 時間複雜度小練習• 遞迴與非遞迴的權衡• 二分的三大痛點• 通用的二分法模板 第二境界 • 二分位置 之 圈圈叉叉 Binary Search on Index – OOXX• 找到滿足某個條件的第一個位置或者最後一個位置 第三境界 •二分位置 之

演算法筆記 1.Introducing Algorithm Interview & Coding Style

Implement strStr cs3k.com http://www.lintcode.com/problem/strstr/ Returns the position of the first occurrence of string target in string source, or -1

演算法筆記 8.雜湊表與堆 Hash & Heap

大綱 cs3k.com 資料結構概述 雜湊表 Hash: a.原理  b.應用 堆 Heap: a.原理    b.應用-優先佇列 Priority Queue  c.替代品-TreeMap   資料結構的兩類問題 cs3k

演算法筆記 6.連結串列與陣列 Linked List & Array

刷題注意事項 cs3k.com 每道題需要總結的 思路 演算法 核心程式碼 這個題得到的啟示!!!重點是bug free的能力   linked list理解 結果兩個都是 1 2 3 node是存在main函式裡的區域性變數, 還是全域性變數? 區

演算法筆記 7.兩根指標 Two Pointers

大綱 cs3k.com 同向雙指標 相向雙指標 Two Sum :3.1 大小• = target• <= target • > target     3.2 去重• unique pairs    3.3 離得近• closest to t

演算法高階班筆記7.Follow Up Question

Overview: cs3k.com  Subarray sum 3 follow up Continuous Subarray Sum 2 follow up Wiggle Sort 2 follow up Partition 3 follow up Iterator 3

演算法高階班筆記6.動態規劃(下)

區間類DP Stone Game Burst Ballons Scramble String 匹配類動規 Longest Common Subsequence Edit Distance K Edit Distance Distinct Subqu