如果狀態依賴關係只在相鄰的幾層之間,則可以使用滾動陣列進行優化數字三角形的狀態轉移方程為滾動陣列可以讓空間複雜度降維
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個點,將他們...