數據結構與算法——從遞歸入手一維動態規劃【1】

前言:

簡單記錄對左程云系列算法課程--算法講解066【必備】的學習,這是第一篇。主要提供C++代碼和一些簡單的個人理解,如需要細致講解請移步原視頻。

涉及內容:

斐波那契數列、動態規劃

參考視頻:

左程云--算法講解066【必備】從遞歸入手一維動態規劃

題目列表:

1.Leetcode--509. 斐波那契數
2.Leetcode--983. 最低票價
3.Leetcode--91. 解碼方法
4.Leetcode--639. 解碼方法 II

題目解答:

?1.Leetcode--509. 斐波那契數
題目:

解題思考:

如果使用簡單的遞歸,則會發現會有很多重復的遞歸的計算,所以為了優化,可以使用數組存放每一個 f (n) 對應的值,這樣就可以避免重復計算,這就是記憶化搜索。而遞歸一般可以使用迭代完成,即從頂向下到從底向上,再由于我們計算 f (n) 時我們只需要 f (n - 1)f (n - 2) ,所以我們只需要兩個變量。

小結:看似是斐波那契數列,其實是整個一維動態規劃的思考過程,學會思路比做題更重要。

遞歸 -> 記憶化搜索 -> 迭代 -> 空間優化

三個階段(省去迭代版本)代碼如下。

示例代碼:
①純遞歸
class Solution {
public:int fib(int n) {return func(n);}int func(int n) {if(n == 0) {return 0;}if(n == 1) {return 1;}return func(n - 1) + func(n - 2);}
};
②記憶化
class Solution {
private:vector<int> dp;
public:int fib(int n) {dp.resize(n + 1, -1);return func(n);}int func(int n) {if(n == 0) {return 0;}if(n == 1) {return 1;}if(dp[n] != -1) {return dp[n];}dp[n] = func(n - 1) + func(n - 2);return dp[n]; }
};
③最終優化
class Solution {
public:int fib(int n) {int f0 = 0;int f1 = 1;if (n == 0) { return 0; }if (n == 1) { return 1; }for(int i = 0; i < n - 1; i++){int f = f1 + f0;f0 = f1;f1 = f;}return f1;}
};
?2.Leetcode--983.最低票價
題目:

解題思考:

起初自己寫時想到了從左向右迭代求解,但是始終沒有碼出來,直到后來參考別人代碼才完成從左向右的迭代。狀態方程思路是對的,錯誤在于沒有把非旅游日期的對應最小花費更新,總想著去判斷其是否為旅游日期。示例代碼如下。

而左老師的代碼是從后向左迭代求解的,我個人認為是不如從左向右更加容易理解。示例代碼也如下。都已通過測試。

示例代碼:
①從左向右
class Solution {
private:int lastDay;int dp[366] = {0};
public:int mincostTickets(vector<int>& days, vector<int>& costs) {lastDay = days[days.size() - 1];int index = 0;for(int i = 1; i <= lastDay; i++){if(i == days[index]){int f1 = dp[i - 1] + costs[0];int f2 = (i >= 7 ? dp[i - 7] : 0) + costs[1];int f3 = (i >= 30 ? dp[i - 30] : 0) + costs[2];dp[i] = min(f1, f2);dp[i] = min(dp[i], f3);index++;}else{dp[i] = dp[i - 1];}}return dp[lastDay];}
};
②從右向左
class Solution {
private:int durations[3] = { 1, 7, 30 };
public:int mincostTickets(vector<int>& days, vector<int>& costs) {int n = days.size();vector<int> dp(n + 1, INT_MAX);dp[n] = 0;for(int i = n - 1; i >= 0; i--){for(int k = 0, j = i + 1; k <= 2; k++){while(j < n && days[i] + durations[k] > days[j]){j++;}dp[i] = min(dp[i], costs[k] + dp[j]);}}return dp[0];}
};
?3.Leetcode--91. 解碼方法
題目:

解題思考:

本題其實沒有特別的點,注意一下編碼'0'的判斷即可,按遞歸->記憶化->動態規劃寫就行了。

示例代碼:
①純遞歸(超時)
class Solution {
private:string _s;
public:int numDecodings(string s) {_s = s;return getCount(0);}int getCount(int i) {if(i == _s.size()){return 1;}int ans;if(_s[i] == '0') {ans = 0;}else{ans = getCount(i + 1);if(i + 1 < _s.size() && (_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26){ans += getCount(i + 2);}}return ans;}};
②記憶化(通過)
class Solution {
private:string _s;vector<int> dp;
public:int numDecodings(string s) {_s = s;int len = s.size();dp.resize(len, -1);return getCount(0);}int getCount(int i) {if(i == _s.size()){return 1;}if(dp[i] != -1){return dp[i];}int ans;if(_s[i] == '0') {ans = 0;}else{ans = getCount(i + 1);if(i + 1 < _s.size() && (_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26){ans += getCount(i + 2);}}dp[i] = ans;return ans;}};
③動態規劃
class Solution {
public:int numDecodings(string s) {int n = s.size();vector<int> dp(n + 1, -1);dp[n] = 1;for(int i = n - 1; i >= 0; i--){if(s[i] == '0'){dp[i] = 0;}else{dp[i] = dp[i + 1];if(i + 1 < n && (s[i] - '0') * 10 + (s[i + 1] - '0') <= 26){dp[i] += dp[i + 2];}}}return dp[0];}
};
④空間優化
class Solution {
public:int numDecodings(string s) {int n = s.size();int next = 1;int nextnext = 0;int cur;for(int i = n - 1; i >= 0; i--){if(s[i] == '0'){cur = 0;}else{cur = next;if(i + 1 < n && (s[i] - '0') * 10 + (s[i + 1] - '0') <= 26){cur += nextnext;}}nextnext = next;next = cur;}return next;}
};
?4.Leetcode--639. 解碼方法 II
題目:

解題思考:

本題與上一題類似,無非是討論的情況比較多,這里推薦觀看原視頻,左老師講的非常清晰,我在這里僅提供對應代碼。

示例代碼:
①純遞歸(超時)
class Solution {
private:string _s;int len;long mod = 1e9 + 7;
public:int numDecodings(string s) {_s = s;len = s.size();return (int)getCount(0);}int getCount(int i){if(i == len){return 1;}if(_s[i] == '0'){return 0;}unsigned long long ans = 0;if(_s[i] == '*'){ans = (unsigned long long)9 * getCount(i + 1);}else{ans = getCount(i + 1);}if(i + 1 < len){// num, num// num, *// * , num// * , *if(_s[i] != '*'){//num, num//num, *if(_s[i + 1] != '*'){//num, numif((_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26){ans += getCount(i + 2);}}else{//num, *if(_s[i] == '1'){ans += (unsigned long long)9 * getCount(i + 2);}if(_s[i] == '2'){ans += (unsigned long long)6 * getCount(i + 2);}}}else{//*, num//*, *if(_s[i + 1] != '*'){//*, numif(_s[i + 1] <= '6'){ans += (unsigned long long)2 * getCount(i + 2);}else{ans += getCount(i + 2);}}else{//*, *ans += (unsigned long long)15 * getCount(i + 2);}}}ans = ans % mod;return ans;}
};
②記憶化
class Solution {
private:string _s;int n;long mod = 1e9 + 7;vector<unsigned long long> dp;
public:int numDecodings(string s) {_s = s;n = s.size();dp.resize(n, -1);return (int)getCount(0);}int getCount(int i){if(i == n){return 1;}if(_s[i] == '0'){return 0;}if(dp[i] != -1){return dp[i];}unsigned long long ans = 0;if(_s[i] == '*'){ans = (unsigned long long)9 * getCount(i + 1);}else{ans = getCount(i + 1);}if(i + 1 < n){// num, num// num, *// * , num// * , *if(_s[i] != '*'){//num, num//num, *if(_s[i + 1] != '*'){//num, numif((_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26){ans += getCount(i + 2);}}else{//num, *if(_s[i] == '1'){ans += (unsigned long long)9 * getCount(i + 2);}if(_s[i] == '2'){ans += (unsigned long long)6 * getCount(i + 2);}}}else{//*, num//*, *if(_s[i + 1] != '*'){//*, numif(_s[i + 1] <= '6'){ans += (unsigned long long)2 * getCount(i + 2);}else{ans += getCount(i + 2);}}else{//*, *ans += (unsigned long long)15 * getCount(i + 2);}}}ans = ans % mod;dp[i] = ans;return ans;}
};
③動態規劃
class Solution {
private:string _s;int n;long mod = 1e9 + 7;vector<unsigned long long> dp;public:int numDecodings(string s) {_s = s;n = s.size();dp.resize(n + 1, -1);dp[n] = 1;for (int i = n - 1; i >= 0; i--) {if(_s[i] == '0'){dp[i] = 0;continue;}if (_s[i] == '*') {// ans = (unsigned long long)9 * getCount(i + 1);dp[i] = (unsigned long long)9 * dp[i + 1];} else {// ans = getCount(i + 1);dp[i] = dp[i + 1];}if (i + 1 < n) {// num, num// num, *// * , num// * , *if (_s[i] != '*') {// num, num// num, *if (_s[i + 1] != '*') {// num, numif ((_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26) {// ans += getCount(i + 2);dp[i] += dp[i + 2];}} else {// num, *if (_s[i] == '1') {// ans += (unsigned long long)9 * getCount(i + 2);dp[i] += (unsigned long long)9 * dp[i + 2];}if (_s[i] == '2') {// ans += (unsigned long long)6 * getCount(i + 2);dp[i] += (unsigned long long)6 * dp[i + 2];}}} else {//*, num//*, *if (_s[i + 1] != '*') {//*, numif (_s[i + 1] <= '6') {// ans += (unsigned long long)2 * getCount(i + 2);dp[i] += (unsigned long long)2 * dp[i + 2];} else {// ans += getCount(i + 2);dp[i] += dp[i + 2];}} else {//*, *// ans += (unsigned long long)15 * getCount(i + 2);dp[i] += (unsigned long long)15 * dp[i + 2];}}}dp[i] = dp[i] % mod;}return (int)dp[0];}
};
④空間壓縮
class Solution {
private:string _s;int n;long mod = 1e9 + 7;// vector<unsigned long long> dp;
public:int numDecodings(string s) {_s = s;n = s.size();// dp.resize(n + 1, -1);// dp[n] = 1;unsigned long long next = 1;unsigned long long nextnext = 0;unsigned long long cur;for (int i = n - 1; i >= 0; i--) {if (_s[i] != '0') {if (_s[i] == '*') {// dp[i] = (unsigned long long)9 * dp[i + 1];cur = (unsigned long long)9 * next;} else {// dp[i] = dp[i + 1];cur = next;}if (i + 1 < n) {if (_s[i] != '*') {if (_s[i + 1] != '*') {if ((_s[i] - '0') * 10 + (_s[i + 1] - '0') <= 26) {// dp[i] += dp[i + 2];cur += nextnext;}} else {if (_s[i] == '1') {// dp[i] += (unsigned long long)9 * dp[i + 2];cur += (unsigned long long)9 * nextnext;}if (_s[i] == '2') {// dp[i] += (unsigned long long)6 * dp[i + 2];cur += (unsigned long long)6 * nextnext;}}} else {if (_s[i + 1] != '*') {if (_s[i + 1] <= '6') {// dp[i] += (unsigned long long)2 * dp[i + 2];cur += (unsigned long long)2 * nextnext;} else {// dp[i] += dp[i + 2];cur += nextnext;}} else {// dp[i] += (unsigned long long)15 * dp[i + 2];cur += (unsigned long long)15 * nextnext;}}}cur = cur % mod;}nextnext = next;next = cur;cur = 0;}return (int)next;}
};

最后:

這幾道題基本就是套的左老師提供的思路模板,在此之前寫動態規劃只是思考動態方程以及如何遞歸和邊界處理,這很顯然會有很大的修改成本,而遞歸的修改成本就很小。當然,如果題目簡單,則可以直接寫,如遇到像第四題這種比較復雜的,優先寫遞歸,之后按模板步驟來。第66節剩下的習題將在第二篇給出。

純遞歸 -> 記憶化搜索 -> 動態規劃 -> 空間壓縮

最后,本文主要用于個人記錄,如有錯誤還望指出,感謝你的閱讀^_^。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/88118.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/88118.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/88118.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

搭建個人博客系列--Nacos 注冊中心

基礎項目已完成&#xff0c;接下來就是SpringCloud的各種組件了。 那你又要問&#xff1a;既然有Nacos為什么之前還裝了Apollo&#xff1f; 那你別管&#xff0c;那不得什么都會點&#xff0c;不然怎么找工作。干就完了。 一、安裝Nacos 管他三七二十一&#xff0c;先在doc…

前端實習總結——案例與大綱

以下是一個結合真實場景的前端面試案例&#xff0c;包含面試流程、核心問題、候選人回答思路及面試官考察點&#xff0c;可直觀感受如何在面試中展現實習/項目經歷&#xff1a; 案例背景 候選人&#xff1a;應屆生&#xff0c;有6個月前端實習經歷&#xff0c;參與過“企業內部…

Web前端開發: :where(偽類函數選擇器)

:where(偽類函數選擇器)&#xff1a;:where() 是 CSS Selectors Level 4 規范中引入的一個強大的偽類函數選擇器&#xff0c;它允許開發者以簡潔的方式編寫復雜的選擇器&#xff0c;同時具有獨特的優先級特性。核心概念&#xff1a;:where() 偽類函數選擇器與 :is() 非常相似&a…

EfficientVMamba: Atrous Selective Scan for Light Weight Visual Mamba論文精讀(逐段解析)

EfficientVMamba: Atrous Selective Scan for Light Weight Visual Mamba論文精讀&#xff08;逐段解析&#xff09; 論文地址&#xff1a;https://arxiv.org/abs/2403.09977 CVPR 2024 Abstract. Prior efforts in light-weight model development mainly centered on CNN an…

Integer緩沖區

文章目錄常見面試題&#xff1a;總結Integer緩沖區是Java預先創建的一個固定范圍的Integer對象緩存池&#xff08;默認-128到127&#xff09;&#xff0c;用于自動復用頻繁使用的整數值&#xff0c;減少內存開銷和對象創建。當通過自動裝箱或Integer.valueOf()生成該范圍內的整…

[國家電網備考]計算機網絡

計算機網絡的概述 概念: 用通信設備與線路將地理位置不同,功能獨立的計算機系統互連起來,以功能完善的網絡軟件實現網絡中資源共享和信息傳遞的系統 自治計算機: 能夠自我管理,配置,維護的計算機(目前我們使用的電腦) 以前的終端只有顯示器,不能叫做自治計算機 計算機網絡向用戶…

在 Linux(openEuler 24.03 LTS-SP1)上安裝 Kubernetes + KubeSphere 的防火墻放行全攻略

目錄 在 Linux&#xff08;openEuler 24.03 LTS-SP1&#xff09;上安裝 Kubernetes KubeSphere 的防火墻放行全攻略 一、為什么要先搞定防火墻&#xff1f; 二、目標環境 三、需放行的端口和協議列表 四、核心工具說明 1. 修正后的 exec.sh 腳本&#xff08;支持管道/重…

HTTP 響應頭信息詳解

HTTP 響應頭信息詳解 引言 HTTP(超文本傳輸協議)是互聯網上應用最為廣泛的網絡協議之一。在HTTP協議中,響應頭信息是服務器向客戶端發送的重要信息之一。響應頭信息包含了關于響應的元數據,如狀態碼、內容類型、緩存策略等。本文將詳細介紹HTTP響應頭信息的概念、類型、作…

去掉長按遙控器power鍵后提示關機、飛行模式的彈窗

首先找到對應長短按power鍵的位置&#xff1a;frameworks\base\policy\src\com\android\internal\policy\impl\PhoneWindowManager.javaprivate final Runnable mPowerLongPress new Runnable() {Overridepublic void run() {// The context isnt readif (mLongPressOnPowerBe…

Redis-哨兵機制Sentinel

redis的主從復制模式下,一旦主節點出現了故障無法提供服務了,需要人工進行主從切換,同時大量的客戶端需要被通知切換到新的主節點上,對于有了一定規模的應用來說,這種方案的延遲是無法接受的,于是redis2.8提供了Redis-Sentinel(哨兵)來解決這個問題. 目錄 1.啥是哨兵節點: 2.r…

SQL 視圖

SQL 視圖 引言 SQL 視圖是數據庫管理系統中的一種重要概念,它允許用戶以不同的方式查看數據庫中的數據。本文將詳細介紹 SQL 視圖的概念、作用、創建方法以及在實際應用中的注意事項。 一、SQL 視圖的概念 SQL 視圖是數據庫中的一種虛擬表,它并不存儲實際的數據,而是基于…

ESP32-使用VSCODE 各種問題總結匯總

1 問題 1 1.1 具體問題描述-config:idf.customExtraPath 無法正確描述launch.json 中使用了一個變量&#xff1a; ${config:idf.customExtraPaths}但在 VSCode 的設置中&#xff0c;并沒有找到對應的設置項 idf.customExtraPaths&#xff0c;所以無法解析。 1.2 問題解決 1.2.1…

【剪裁Patch】已標注的WSI剪裁Patch的處理流程(以QuPath軟件得到的標注信息為例)

1. 整體處理思路 整體處理流程如圖所示,概括來說就是:根據標注信息將WSI區分為腫瘤區域和正常區域,對這個區域進行采樣裁剪得到具有Patch級別標簽的Patch。 當然,這里的Patch標簽是根據標注信息決定的,如果標注的是癌癥亞型信息,那么也可以將不同亞型的Patch區分出來。 …

Qt 與Halcon聯合開發九:算法類設計與實現講解(附源碼)

一、設計背景 在機器視覺系統中&#xff0c;算法是系統的核心。不同產品、不同項目對圖像處理的要求不盡相同&#xff0c;因此算法需要具備&#xff1a; 靈活拓展&#xff1a;方便添加新算法統一調用&#xff1a;界面或上層邏輯不關心算法細節結構清晰&#xff1a;便于維護與…

npu-driver 23.0.3驅動安裝

宿主機器上安裝npu-driver/ npu-firmware這兩個東西 wget -O Ascend-hdk-910b-npu-driver_23.0.3_linux-aarch64.run https://bj.bcebos.com/v1/aipe-easyedge-public/cann/eb_speed/Ascend-hdk-910b-npu-driver_23.0.3_linux-aarch64.run?authorizationbce-auth-v1%2F50c8bb…

LeetCode題解---<三數之和>

文章目錄題目<三數之和>--Python解法題解題目<三數之和>–Python解法 給你一個整數數組 nums &#xff0c;判斷是否存在三元組 [nums[i], nums[j], nums[k]] 滿足 i ! j、i ! k 且 j ! k &#xff0c;同時還滿足 nums[i] nums[j] nums[k] 0 。請你返回所有和為…

探索Insplorion氫氣傳感器:高靈敏度與快速響應的創新解決方案

在追求更清潔、更安全能源的過程中&#xff0c;氫氣作為一種理想的清潔能源載體&#xff0c;正日益受到全球的重視。然而&#xff0c;氫氣的廣泛應用也帶來了新的挑戰——如何確保其儲存、運輸和使用的安全性&#xff1f;Insplorion通過其獨特的納米等離子體傳感&#xff08;NP…

【QT】事件(鼠標、按鍵、定時器、窗口)

文章目錄1. 事件1.1 事件的介紹1.2 事件的處理2. 按鍵事件3. 鼠標事件4. 定時器5. 窗口事件1. 事件 1.1 事件的介紹 事件是應用程序內部或者外部產生的事情或者動作的統稱。 在 Qt 中使用?個對象來表示?個事件。所有的 Qt 事件均繼承于抽象類 QEvent。事件是由系統或者 Qt …

STM32固件升級設計——串口IAP升級(基于YMODEM協議)

目錄 一、功能描述 1、BootLoader部分&#xff1a; 2、APP部分&#xff1a; 二、BootLoader程序制作 1、分區定義 2、 主函數 3、YMODEM協議的實現 4、程序跳轉 三、APP程序制作 四、工程配置&#xff08;默認KEIL5&#xff09; 五、運行測試 結束語 概述 IAP&…

Cookie(搭配domain)/Session(搭配HttpServletRequest+HttpSession)

各位看官&#xff0c;大家早安午安晚安呀~~~如果您覺得這篇文章對您有幫助的話歡迎您一鍵三連&#xff0c;小編盡全力做到更好 歡迎您分享給更多人哦今天我們來學習&#xff1a;Cookie/Session1.Cookie/Session的簡述我們在講解HTTP協議的時候已經講解過Cookie了HTTP 協議自身是…