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

前言:

記錄一下對左程云系列算法課程--算法講解066【必備】的剩余習題的學習。本文主要簡單記錄個人學習心得和提供C++版本代碼。如需要題目的細致講解,請前往原視頻。

涉及內容:

動態規劃、三指針、

參考視頻:

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


題目列表:

1.Leetcode--264. 丑數 II
2.Leetcode--32. 最長有效括號
3.Leetcode--467. 環繞字符串中唯一的子字符串
4.Leetcode--940. 不同的子序列 II

題目解答:

?1.Leetcode--264. 丑數 II
題目:

解題思考:

首先可以很好的考慮到暴力求解,我們只需要從1開始,從大到小每個數字遍歷判斷其是否是丑數然后計數即可,但很顯然這會超時。

那么我們從質因子入手,因為一個丑數(除1)外,都是由其他丑數×2 | 3 | 5 得到的,那么我們可以從1出發,會得到三個丑數:2、3、5,所以1后面的丑數就是2。接著從2出發,得到三個丑數:4、6、10,算上之前得到但是沒有使用的丑數一共是:3、4、5、6、10,所以2后面的數字應該是3,之后循環即可。從上述思路知道我們需要一個優先隊列(最小堆),關于C++中priority_queue的比較器我在這里由所記錄,按需觀看。

可以優先隊列會隨著時間的推移而變大,而且在得到最終結果時,有很多用不到的數據也會被一直存儲。例如剛才我們求第三個丑數(3)時已經計算了5個數。

通過觀察,我們可以只保存三個變量,分別指代*2、*3、*5,當對應變量被使用時,我們只需要改變這一個變量即可,即優化了優先隊列的空間,還對比較的數據范圍進行縮小化。

三版的示例代碼如下。

示例代碼:

①暴力(超時)

class Solution {
public:int nthUglyNumber(int n) {int count = 0;int num = 0;while(count < n){num++;if(isUglyNumber(num)){count++;} }//count == nreturn num;}bool isUglyNumber(int n){if(n <= 0){return false;}while(n % 2 == 0){n /= 2;}while(n % 3 == 0){n /= 3;}while(n % 5 == 0){n /= 5;}if(n == 1){return true;}return false;}
};

②優先隊列(最小堆)

class Solution {
private:struct compare{bool operator()(unsigned long long a, unsigned long long b){return a > b;}};
public:int nthUglyNumber(int n) {priority_queue<unsigned long long, vector<unsigned long long>, compare> pq;unsigned long long num = 1;int count = 1;while(count != n){count++;pq.push((unsigned long long)num * 2);pq.push((unsigned long long)num * 3);pq.push((unsigned long long)num * 5);num = pq.top();while(num == pq.top()){pq.pop();}}return num;}
};

③三指針動態規劃

class Solution {
public:int nthUglyNumber(int n) {vector<int> dp(n + 1, 0);dp[1] = 1;int i2 = 1, i3 = 1, i5 = 1;for(int i = 2; i <= n; i++){int a = dp[i2] * 2;int b = dp[i3] * 3;int c = dp[i5] * 5;dp[i] = min(min(a, b), c);if(dp[i] == a) { i2++; }if(dp[i] == b) { i3++; }if(dp[i] == c) { i5++; }}return dp[n];}
};
輔助題目與示例代碼:

這里再推薦一些相關習題,只是和本題相關,與動態規劃無關。

①Leetcode--231. 2 的冪
class Solution {
public:bool isPowerOfTwo(int n) {return n > 0 && (n & (n - 1)) == 0;}
};
②Leetcode--263. 丑數
class Solution {
public:bool isUgly(int n) {if(n <= 0){return false;}while(n % 3 == 0){n /= 3;}while(n % 5 == 0){n /= 5;}return n > 0 && (n & (n - 1)) == 0;}
};
?2.Leetcode--32. 最長有效括號
題目:

解題思考:

本題的動態規劃做法中存在著KMP算法的影子。首先對于暴力求解,我們只需要枚舉以每一位為結尾的子括號串的有效括號串長度,最后求最大值即可。但很顯然這存在重復計算,那么如何利用之前已經計算過的數據,這就是該題動態規劃做法的來歷。、

如果當前位置為左括號"(",很顯然依此結尾的字串不可能有效,對應dp數組我們記作0。

如果當前位置為右括號")",我們可以看dp[i - 1]位置對應的有效字串長度是多少,這個時候我們只需要關注p = i - dp[i - 1] - 1這個位置是否為"("。如果是,則可以在dp[i - 1]的基礎上再加上兩個字符長度。最后判斷dp[p - 1]位置有多長的有效字符串長度,再次加上即可。

此時只需要加到dp[p - 1]即可,再左邊就不用看了,因為我們按照順序求解,dp[p - 1]的值已經是最長的有效字符串長度了。

?這里還是推薦一下原視頻的,左老師模擬了一個很長的例子幫助有效理解,最后代碼如下。

示例代碼:
class Solution {
public:int longestValidParentheses(string s) {if (s == "") { return 0; }int n = s.size();vector<int> dp(n, 0);dp[0] = 0;int ans = 0;for(int i = 1; i < n; i++){if(s[i] == ')'){int p = i - dp[i - 1] - 1;if(p >= 0 && s[p] == '('){dp[i] = dp[i - 1] + 2 + (p > 0 ? dp[p - 1] : 0);}}ans = max(ans, dp[i]);}return ans;}
};
?3.Leetcode--467. 環繞字符串中唯一的子字符串
題目:

解題思考:

最容易想到的暴力解法當然是逐個位置進行枚舉,顯然,重復計算非常多。而觀察可發現長字符串是包含短字符串的,所以很自然可以聯系到狀態方程。但這里重點不在如何建立狀態方程,狀態方程只是"果"。我們要找的是字串之間的關系,即"因"。

如果我們以每個位置作為字串的開頭去判斷是否為有效字串,則從0位置開始顯然是最復雜的,那么這時可以考慮從末位置,即從右向左,但這可能寫不順手。所以我們可以使每個位置作為字串的結尾,從左向右即可。

那么從0位置入手,很顯然其對應的字串為1。在下一個位置時,我們查看上一個位置是否能連在一起構成有效字串,如果是有效字串,則以此位置結尾的有效字串最大長度為len+ 1,len用于記錄當前有效字串最大長度,而我們對26個字母都存放對應字母結尾時,可以構成的有效子串個數,最后循環完畢累加即可。可能表述不是很清楚,這里還是推薦一下左老師的原視頻。

示例代碼:
class Solution {
public:int findSubstringInWraproundString(string s) {int n = s.size();vector<int> ss(n);for(int i = 0; i < n; i++){ss[i] = s[i] - 'a';}vector<int> dp(26, 0);int len = 1;dp[ss[0]] = 1;for(int i = 1, cur, pre; i < n; i++){cur = ss[i];pre = ss[i - 1];if((pre == 25 && cur == 0) || pre + 1 == cur){len++;}else{len = 1;}dp[cur] = max(dp[cur], len);}int ans = 0;for(int x : dp){ans += x;}return ans;}
};
?4.Leetcode--940. 不同的子序列 II
題目:

解題思考:

?本題還是看原視頻吧。主要特點在于計數和去重,cnt[idx]設計的很好。

示例代碼:
class Solution {
private:int mod = 1e9 + 7;
public:int distinctSubseqII(string s) {vector<int> cnt(26, 0);int all = 1;int newAdd;for(char c : s){int idx = c - 'a';newAdd = (all - cnt[idx] + mod) % mod;cnt[idx] = (cnt[idx] + newAdd) % mod;all = (all + newAdd) % mod;}return (all - 1 + mod) % mod;}
};

最后:

關于動態規劃的總結其實左老師也講了很多。這節課最重要的學習了動態規劃是怎樣來的,即設計純遞歸、記憶化搜索、設計遞推、空間優化。其實整個過程也就是把遞歸寫成迭代的做法。另外還有對序列的操作,作為初學者的我也很容易將每個位置所為所求序列的開頭,但是這樣會陷入0位置就是最復雜位置的困難。當我們反向思考,讓每個位置最為所求序列的結尾,這樣就可以從0位置起依次迭代了。

學習算法是漫長且痛苦的過程,且可能長期伴隨著焦慮。但這是始終要面對的,畢竟是自己選擇的路。算法難嗎?難。需要天賦嗎?需要一點。自己有天賦沒?不知道。在我看來,天賦只有在經歷過無數努力且踩在巨人的肩膀上才能體現的東西。更何況天賦的高山永無頂點,只要實現自我超越,就是有價值的。愿自己能在學習技術和算法的路上一直走下去。

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

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

相關文章

【理念●體系】Windows AI 開發環境搭建實錄:六層架構的逐步實現與路徑治理指南

【理念●體系】從零打造 Windows WSL Docker Anaconda PyCharm 的 AI 全鏈路開發體系-CSDN博客 Windows AI 開發環境搭建實錄&#xff1a;六層架構的逐步實現與路徑治理指南 ——理念落地篇&#xff0c;從路徑規劃到系統治理&#xff0c;打造結構化可復現的 AI 開發環境 AI…

5G標準學習筆記15 --CSI-RS測量

5G標準學習筆記15 --CSI-RS測量 前言 前面講了&#xff0c;在5GNR中&#xff0c;CSI-RS 是支持信道狀態評估、波束管理和無線資源管理&#xff08;RRM&#xff09;的關鍵參考信號。下面孬孬基于3GPP TS 38.331中的內容&#xff0c;詳細定義了基于 CSI-RS 的測量程序&#xff0c…

第P28:阿爾茨海默病診斷(優化特征選擇版)

&#x1f368; 本文為&#x1f517;365天深度學習訓練營 中的學習記錄博客&#x1f356; 原作者&#xff1a;K同學啊 一、進階說明 針對于特征對模型結果的影響我們做了特征分析 特征選擇 1. SelectFromModel 工作原理&#xff1a;基于模型的特征選擇方法&#xff0c;使用…

AI的歐幾里得要素時刻:從語言模型到可計算思維

引言 人工智能正在經歷一個關鍵的轉折點。就像歐幾里得的《幾何原本》為數學奠定了公理化基礎一樣&#xff0c;AI也正在尋找自己的"要素時刻"——一個能夠將當前的語言模型能力轉化為真正可計算、可驗證思考的轉變。 最近發表的論文《AI’s Euclid’s Elements Momen…

番外-linux系統運行.net framework 4.0的項目

基礎環境&#xff1a;linux系統&#xff0c;.net framework 4.0&#xff0c;npgsql 2.2.5.0 &#xff08;版本不同&#xff0c;構建可能失敗&#xff09; 方法背景&#xff1a;linux不支持運行.net framework 4.0&#xff0c;高版本mono不支持npgsql 2.x 主要使用&#xff1a…

國內AI訓練都有哪些企業?:技術深耕與場景實踐

國內AI訓練都有哪些企業&#xff1f;當人工智能從實驗室走向產業一線&#xff0c;AI 訓練就像為智能系統 “施肥澆水” 的關鍵環節&#xff0c;讓技術根系在各行業土壤里扎得更深。國內一批 AI 訓練企業正各展所長&#xff0c;有的專攻技術優化&#xff0c;有的深耕場景應用。它…

微算法科技基于格密碼的量子加密技術,融入LSQb算法的信息隱藏與傳輸過程中,實現抗量子攻擊策略強化

隨著量子計算技術的發展&#xff0c;傳統加密算法面臨被量子計算機破解的風險&#xff0c;LSQb 算法也需考慮應對未來可能的量子攻擊。微算法科技基于格密碼的量子加密技術&#xff0c;融入LSQb算法的信息隱藏與傳輸過程中&#xff0c;實現抗量子攻擊策略強化。格密碼在面對量子…

xAI發布Grok4+代碼神器Grok4 Code,教你如何在國內升級訂閱SuperGrok并使用到Grok4教程

就在今天&#xff0c;馬斯克旗下xAI發布了其最新的旗艦AI模型Grok4&#xff0c;并同步推出專為開發者打造的編程利器 Grok 4 Code&#xff0c;還推出了一項全新的AI訂閱計劃——每月300美元的SuperGrokHeavy。 那最新發布的Grok4以及有哪些特性呢&#xff1f;以及如何才能使用…

Rust 變量遮蔽(Variable Shadowing)

在 Rust 中&#xff0c;變量遮蔽&#xff08;Variable Shadowing&#xff09; 是一種在同一作用域內重新聲明同名變量的特性。它允許你創建一個新變量覆蓋之前的同名變量&#xff0c;新變量與舊變量類型可以不同&#xff0c;且舊變量會被完全隱藏。核心特點允許同名變量重復聲明…

【VScode | 快捷鍵】全局搜索快捷鍵(ctrl+shift+f)失效原因及解決方法

&#x1f601;博客主頁&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客內容&#x1f911;&#xff1a;&#x1f36d;嵌入式開發、Linux、C語言、C、數據結構、音視頻&#x1f36d; &#x1f60e;金句分享&#x1f60e;&a…

Windows 與 Linux 內核安全及 Metasploit/LinEnum 在滲透測試中的綜合應用

目錄 &#x1f6e0;? 1. 內核安全如何助力滲透測試與黑客行業 1.1 內核安全的戰略價值 1.2 結合 Metasploit 與 LinEnum 的作用 &#x1f50d; 2. Metasploit 信息收集模塊及其在內核安全中的應用 2.1 Windows 信息收集模塊 2.2 Linux 信息收集模塊 2.3 使用步驟 Wind…

京東攜手HarmonyOS SDK首發家電AR高精擺放功能

在電商行業的演進中&#xff0c;商品的呈現方式不斷升級&#xff1a;從文字、圖片到視頻&#xff0c;再到如今逐漸興起的3D與AR技術。作為XR應用探索的先行者&#xff0c;京東正站在這場體驗革新的最前沿&#xff0c;不斷突破商品展示的邊界&#xff0c;致力于通過創新技術讓消…

瞄準Win10難民,蘋果正推出塑料外殼、手機CPU的MacBook

最近有消息稱&#xff0c;蘋果正在研發一款定位“低價”的MacBook&#xff0c;售價可能低于800美元&#xff08;約合人民幣5800元&#xff09;&#xff0c;采用的是A18 Pro芯片&#xff0c;也就是未來iPhone 16 Pro同款的“手機芯片”&#xff0c;而不是現有的M系列。這款產品預…

原子級 macOS 信息竊取程序升級:新增后門實現持久化控制

臭名昭著的 Atomic macOS Stealer&#xff08;AMOS&#xff0c;原子級 macOS 竊取程序&#xff09;惡意軟件近期完成危險升級&#xff0c;全球 Mac 用戶面臨更嚴峻威脅。這款與俄羅斯有關聯的竊密程序首次植入后門模塊&#xff0c;使攻擊者能維持對受感染系統的持久訪問、執行遠…

Shader面試題100道之(81-100)

Shader面試題&#xff08;第81-100題&#xff09; 以下是第81到第100道Shader相關的面試題及答案&#xff1a; 81. Unity中如何實現屏幕空間的熱扭曲效果&#xff08;Heat Distortion&#xff09;&#xff1f; 熱扭曲效果可以通過GrabPass抓取當前屏幕圖像&#xff0c;然后在片…

C#洗牌算法

洗牌算法是一種將序列&#xff08;如數組、列表&#xff09;元素隨機打亂的經典算法&#xff0c;核心目標是讓每個元素在打亂后出現在任意位置的概率均等。在 C# 中&#xff0c;常用的洗牌算法有Fisher-Yates 洗牌算法&#xff08;也稱 Knuth 洗牌算法&#xff09;&#xff0c;…

Python PDFplumber詳解:從入門到精通的PDF處理指南

一、PDFplumber核心優勢解析 在數字化辦公場景中&#xff0c;PDF文檔處理是數據分析師和開發者的必備技能。相較于PyPDF2、pdfminer等傳統庫&#xff0c;PDFplumber憑借其三大核心優勢脫穎而出&#xff1a; 精準表格提取&#xff1a;采用流式布局分析算法&#xff0c;支持復雜表…

Flutter 與 Android 的互通幾種方式

Flutter 與 Android 的互通主要通過以下幾種方式實現&#xff0c;每種方式適用于不同的場景&#xff1a;1. 平臺通道&#xff08;Platform Channels&#xff09; Flutter 與原生 Android 代碼通信的核心方式&#xff0c;支持雙向調用。 類型&#xff1a; MethodChannel&#xf…

全新開源AI知識庫系統!PandaWiki一鍵構建智能文檔,支持AI問答、創作與搜索!

傳統 Wiki 工具像一本厚重的“死書”&#xff0c;雖能存儲信息&#xff0c;卻無法主動「思考」。而在當今AI席卷各個行業的浪潮中&#xff0c;知識管理也迎來了智能化的巨大飛躍。最近開源圈悄然走紅的 PandaWiki&#xff0c;就用 AI 大模型為知識庫注入了 靈魂&#xff0c; 它…

Rust 結構體

Rust 結構體 引言 Rust 是一種系統編程語言,以其內存安全、并發支持和零成本抽象而聞名。結構體(struct)是 Rust 中用于創建自定義數據類型的工具。本文將深入探討 Rust 結構體的概念、用法以及其在實際編程中的應用。 結構體的定義 在 Rust 中,結構體是一種復合類型,…