日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

动态规划之四键键盘

發(fā)布時(shí)間:2024/4/11 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态规划之四键键盘 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

動(dòng)態(tài)規(guī)劃之四鍵鍵盤

如何在 N 次敲擊按鈕后得到最多的 A? 我們窮舉唄, 每次有對(duì)于每次按鍵, 我們可以窮舉四種可能, 很明顯就是?個(gè)動(dòng)態(tài)規(guī)劃問題。

第?種思路(超時(shí))

這種思路會(huì)很容易理解, 但是效率并不?, 我們直接?流程: 對(duì)于動(dòng)態(tài)規(guī)劃問題, ?先要明?有哪些「狀態(tài)」 , 有哪些「選擇」 。

具體到這個(gè)問題, 對(duì)于每次敲擊按鍵, 有哪些「選擇」 是很明顯的: 4 種,就是題?中提到的四個(gè)按鍵, 分別是 A 、 C-A 、 C-C 、 C-V ( Ctrl 簡寫為 C ) 。

接下來, 思考?下對(duì)于這個(gè)問題有哪些「狀態(tài)」 ? 或者換句話說, 我們需要
知道什么信息, 才能將原問題分解為規(guī)模更?的?問題?

你看我這樣定義三個(gè)狀態(tài)?不?: 第?個(gè)狀態(tài)是剩余的按鍵次數(shù), ? n 表?; 第?個(gè)狀態(tài)是當(dāng)前屏幕上字符 A 的數(shù)量, ? a_num 表?; 第三個(gè)狀態(tài)是剪切板中字符 A 的數(shù)量, ? copy 表?

如此定義「狀態(tài)」 , 就可以知道 base case: 當(dāng)剩余次數(shù) n 為 0 時(shí), a_num
就是我們想要的答案

結(jié)合剛才說的 4 種「選擇」 , 我們可以把這?種選擇通過狀態(tài)轉(zhuǎn)移表?出來:

dp(n - 1, a_num + 1, copy), # A 解釋: 按下 A 鍵, 屏幕上加?個(gè)字符 同時(shí)消耗 1 個(gè)操作數(shù)dp(n - 1, a_num + copy, copy), # C-V 解釋: 按下 C-V 粘貼, 剪切板中的字符加?屏幕 同時(shí)消耗 1 個(gè)操作數(shù)dp(n - 2, a_num, a_num) # C-A C-C 解釋: 全選和復(fù)制必然是聯(lián)合使?的, 剪切板中 A 的數(shù)量變?yōu)槠聊簧?A 的數(shù)量 同時(shí)消耗 2 個(gè)操作數(shù)

這樣可以看到問題的規(guī)模 n 在不斷減?, 肯定可以到達(dá) n = 0 的 base case, 所以這個(gè)思路是正確的:

def maxA(N: int) -> int:# 對(duì)于 (n, a_num, copy) 這個(gè)狀態(tài),# 屏幕上能最終最多能有 dp(n, a_num, copy) 個(gè) Adef dp(n, a_num, copy):# base caseif n <= 0: return a_num;# ?種選擇全試?遍, 選擇最?的結(jié)果return max(dp(n - 1, a_num + 1, copy), # Adp(n - 1, a_num + copy, copy), # C-Vdp(n - 2, a_num, a_num) # C-A C-C)# 可以按 N 次按鍵, 屏幕和剪切板?都還沒有 Areturn dp(N, 0, 0)

這個(gè)解法應(yīng)該很好理解, 因?yàn)檎Z義明確。 下?就繼續(xù)?流程, ?備忘錄消除?下重疊?問題:

def maxA(N: int) -> int:# 備忘錄memo = dict()def dp(n, a_num, copy):if n <= 0: return a_num;# 避免計(jì)算重疊?問題if (n, a_num, copy) in memo:return memo[(n, a_num, copy)]memo[(n, a_num, copy)] = max(# ?種選擇還是?樣的)return memo[(n, a_num, copy)]return dp(N, 0, 0)

這個(gè)算法的時(shí)間復(fù)雜度不容易分析。 我們可以把這個(gè) dp 函數(shù)寫成 dp 數(shù)組:

dp[n][a_num][copy] # 狀態(tài)的總數(shù)(時(shí)空復(fù)雜度) 就是這個(gè)三維數(shù)組的體積

我們知道變量 n 最多為 N , 但是 a_num 和 copy 最多為多少我們很難計(jì)算, 復(fù)雜度起碼也有 O(N^3) 把。 所以這個(gè)算法并不好, 復(fù)雜度太?, 且已經(jīng)?法優(yōu)化了。
這也就說明, 我們這樣定義「狀態(tài)」 是不太優(yōu)秀的, 下?我們換?種定義dp 的思路。

第?種思路

繼續(xù)?流程, 「選擇」 還是那 4 個(gè),

但是這次我們只定義?個(gè)「狀態(tài)」 , 也就是剩余的敲擊次數(shù) n。

這個(gè)算法基于這樣?個(gè)事實(shí), 最優(yōu)按鍵序列?定只有兩種情況:

要么?直按 A : A,A,…A(當(dāng) N ?較?時(shí))
要么是這么?個(gè)形式: A,A,…C-A,C-C,C-V,C-V,…C-V(當(dāng) N ?較?時(shí))

因?yàn)樽址麛?shù)量少(N ?較?) 時(shí), C-A C-C C-V 這?套操作的代價(jià)相對(duì)?較?, 可能不如?個(gè)個(gè)按 A ; ?當(dāng) N ?較?時(shí), 后期 C-V 的收獲肯定很?。

這種情況下整個(gè)操作序列?致是: 開頭連按?個(gè) A , 然后 C-A C-C組合再接若? C-V , 然后再 C-A C-C 接著若? C-V , 循環(huán)下去。

換句話說, 最后?次按鍵要么是 A 要么是 C-V 。 明確了這?點(diǎn), 可以通過這兩種情況來設(shè)計(jì)算法:

int[] dp = new int[N + 1]; // 定義: dp[i] 表? i 次操作后最多能顯?多少個(gè) A for (int i = 0; i <= N; i++)dp[i] = max(這次按 A 鍵,這次按 C-V)

對(duì)于「按 A 鍵」 這種情況, 就是狀態(tài) i - 1 的屏幕上新增了?個(gè) A ?已, 很容易得到結(jié)果:

// 按 A 鍵, 就?上次多?個(gè) A ?已 dp[i] = dp[i - 1] + 1;

但是, 如果要按 C-V , 還要考慮之前是在哪? C-A C-C 的。

剛才說了, 最優(yōu)的操作序列?定是 C-A C-C 接著若? C-V , 所以我們??
個(gè)變量 j 作為若? C-V 的起點(diǎn)。 那么 j 之前的 2 個(gè)操作就應(yīng)該是 C-AC-C
了:

public int maxA(int N) {int[] dp = new int[N + 1];dp[0] = 0;for (int i = 1; i <= N; i++) {// 按 A 鍵dp[i] = dp[i - 1] + 1;for (int j = 2; j < i; j++) {// 全選 & 復(fù)制 dp[j-2], 連續(xù)粘貼 i - j 次// 屏幕上共 dp[j - 2] * (i - j + 1) 個(gè) Adp[i] = Math.max(dp[i], dp[j - 2] * (i - j + 1));}} // N 次按鍵之后最多有?個(gè) A?return dp[N]; }

其中 j 變量減 2 是給 C-A C-C 留下操作數(shù), 看個(gè)圖就明?了:

此算法就完成了, 時(shí)間復(fù)雜度 O(N2)O(N^2)O(N2), 空間復(fù)雜度 O(N)O(N)O(N), 這種解法應(yīng)該是?較?效的了

最后總結(jié)

動(dòng)態(tài)規(guī)劃難就難在尋找狀態(tài)轉(zhuǎn)移, 不同的定義可以產(chǎn)?不同的狀態(tài)轉(zhuǎn)移邏輯, 雖然最后都能得到正確的結(jié)果, 但是效率可能有巨?的差異。

回顧第?種解法, 重疊?問題已經(jīng)消除了, 但是效率還是低, 到底低在哪?呢? 抽象出遞歸框架:

def dp(n, a_num, copy):dp(n - 1, a_num + 1, copy), # Adp(n - 1, a_num + copy, copy), # C-Vdp(n - 2, a_num, a_num) # C-A C-C

看這個(gè)窮舉邏輯, 是有可能出現(xiàn)這樣的操作序列 C-A C-C, C-A C-C... 或者C-V,C-V,... 。 然這種操作序列的結(jié)果不是最優(yōu)的, 但是我們并沒有想辦法規(guī)避這些情況的發(fā)?, 從?增加了很多沒必要的?問題計(jì)算

回顧第?種解法, 我們稍加思考就能想到, 最優(yōu)的序列應(yīng)該是這種形式: A,A…C-A,C-C,C-V,C-V…C-A,C-C,C-V… 。

根據(jù)這個(gè)事實(shí), 我們重新定義了狀態(tài), 重新尋找了狀態(tài)轉(zhuǎn)移, 從邏輯上減少了?效的?問題個(gè)數(shù), 從?提?了算法的效率

超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生

總結(jié)

以上是生活随笔為你收集整理的动态规划之四键键盘的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。