動態規劃 空間優化技巧以及接龍型動態規劃

2021-10-22 17:20:21 字數 4520 閱讀 6202

如果狀態依賴關係只在相鄰的幾層之間,則可以使用滾動陣列進行優化

滾動陣列可以讓空間複雜度降維

數字三角形的狀態轉移方程為

dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1]) + a[i][j]

滾動陣列優化之後為

dp[i % 2][j] = min(dp[(i - 1) % 2][j], dp[(i - 1) % 2][j - 1]) + a[i][j]

因為每一步只與他的前一步有關,所以前面的陣列我們可以重複使用,而不需要開闢新的空間。

隨著滾動陣列優化,我們需要改變的地方:

//原來的版本,詳情請看動態規劃入門:

public

intminimumtotal

(int

********)

if(********[0]

== null || ********[0]

.length ==0)

int n = ********.length;

int[

] f =

newint

[n][n]

;// initialize: 三角形的左邊和右邊要初始化

// 因為他們分別沒有左上角和右上角的點

f[0]

[0]= ********[0]

[0];

for(

int i =

1; i < n; i++

)// function: f[i][j] = math.min(f[i - 1][j], f[i - 1][j - 1]) + ********[i][j];

for(

int i =

1; i < n; i++)}

// answer: 最後一層的任意位置都可以是路徑的終點

int best = f[n -1]

[0];

for(

int i =

1; i < n; i++

)return best;

}//滾動陣列版本:

public

intminimumtotal

(int

********)

if(********[0]

== null || ********[0]

.length ==0)

int n = ********.length;

//空間負責度進行了降緯 n => 2

int[

] f =

newint[2

][n]

;

f[0]

[0]= ********[0]

[0];

// 因為陣列空間不能夠直接初始化,我們需要在動態的過程中初始化

for(

int i =

1; i < n; i++)}

// answer: 最後一層的任意位置都可以是路徑的終點

int best = f[

(i -1)

%2][

0];for

(int i =

1; i < n; i++

)return best;

}

從上面的不同的兩個版本我們可以知道最大的區別在於初始化,因為陣列空間不能夠直接初始化,所以我們需要在動態的過程中初始化。

那麼能否兩個維度一起滾動呢?

dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - 1]) + a[i][j] =>

dp[i % 2][j % 2] = min(dp[(i - 1) % 2][j % 2], dp[(i - 1) % 2][(j - 1) % 2]) + a[i][j]

不可以,因為j不是全域性單調遞增的,所以他的資料需要被儲存,而 i 是全域性單調遞增的。

所以我們可以得出,滾動陣列只可以滾動乙個維度,不能滾動兩個維度。

例項:斐波那契數列

class

solution

return dp[n%3];}}

總結:

屬於「座標型」動態規劃的一種 題型一般是告訴你乙個接龍規則,讓你找最長的龍

經典例題:

leetcode 300. 最長遞增子串行

給你乙個整數陣列 nums ,找到其中最長嚴格遞增子串行的長度。

子串行是由陣列派生而來的序列,刪除(或不刪除)陣列中的元素而不改變其餘元素的順序。例如,[3,6,2,7] 是陣列 [0,3,1,6,2,2,7] 的子串行。

例子1

:輸入:nums =[10

,9,2

,5,3

,7,101,18

]輸出:4

解釋:最長遞增子串行是 [2,

3,7,

101],因此長度為 4 。

利用動規四要素分析:

state: 

dp[i] 表示以第 i 個數為龍尾的最長的龍有多長

function:

dp[i]

= max

, j < i && nums[j]

< nums[i]

initialization:

//每個位置都可以是龍頭

dp[0.

.n-1]=

1answer:

max

follow up:求具體的方法

倒推法記錄每個狀態的最優值是從哪個前繼狀態來的 通常需要乙個和狀態陣列同樣維度的陣列 prev[i] 記錄 使得 dp[i] 獲得最優值的那個 j 是誰 j 是方程 dp[i] = max 裡的j

最長上公升連續子串行 ii

描述:給定乙個整數矩陣. 找出矩陣中的最長連續上公升子串行, 返回它的長度. 最長連續上公升子串行可以從任意位置開始, 向上/下/左/右移動.

輸入:[[

1,2,

3,4,

5],[

16,17,

24,23,

6],[

15,18,

25,22,

7],[

14,19,

20,21,

8],[

13,12,

11,10,

9]]輸出:

25解釋:1-

>2-

>3-

>4-

>5-

>..

.->

25(由外向內螺旋)

leetcode 368.最大整除子集

描述:給出乙個由無重複的正整數組成的集合,找出其中最大的整除子集,子集中任意一對 (si,sj) 都要滿足:si % sj = 0 或 sj % si = 0。

如果有多個目標子集,返回其中任何乙個均可。

示例 1

:輸入:[1

,2,3

]輸出:[1

,2](當然,[1

,3] 也正確)

class

solution

arrays.

sort

(nums)

;int n = nums.length;

hashmap

dp =

newhashmap()

; hashmap

prev =

newhashmap()

;for

(int i =

0; i < n; i++

)int lastnum = nums[0]

;for

(int i =

0; i < n; i++)if

(dp.

get(num)

< dp.

get(factor)+1

)}if(dp.

get(num)

> dp.

get(lastnum))}

return

getpath

(prev, lastnum);}

private list

getpath

(hashmap

prev,

int lastnum)

collections.

reverse

(path)

;return path;

}private list

getfactors

(int num)

int factor =1;

while

(factor * factor <= num)

} factor++;}

return factors;

}}

動態規劃空間優化之滾動陣列

使用範圍 使用在遞推或動態規劃中 作用 節約空間 注意 時間上沒什麼優勢 舉例1 作用在一維陣列 普通方法 int d new int 100 d 0 1 d 1 1 for int i 2 i 100 i system.out.printf d d 99 上述方法使用100個空間 近似認為 注意,...

動態規劃 斜率優化

一 引用 一般dp 方程可以轉化成 dp i f j x i 的形式,其中 f j 中儲存了只與 j相關的量。這樣的 dp方程可以用單調佇列進行優化,從而使得 o n 2 的複雜度降到 o n 可是並不是所有的方程都可以轉化成上面的形式,舉個例子 dp i dp j x i x j x i x j ...

動態規劃優化方法

之前我們學習過動態規劃方法,但是並沒有對dp進行系統細緻的優化。今天來看一下dp的優化方法。做變換 等式就可以看作一條直線,每個j都確定出乙個點 x,y 對於當前要求解的i,其斜率已確定 且隨i單增 要使dp i 最大即要使這條直線過某乙個j形成的點並使得的截距最小。假設之前已處理完前9個點,將他們...