動態規劃課堂3-----簡單多狀態問題(買賣股票最佳時機)

目錄

引入:

例題1:按摩師(打家劫舍I)

例題2:打家劫舍II

例題3:刪除并獲得點數

例題4:粉刷房子

例題5:買賣股票的最佳時機含冷凍

結語:


引入:

相信看到這里的友友們對動態規劃已經有了一定的了解,下面我將介紹動態規劃的簡單多狀態dp問題。所謂多狀態就是在一步下有不同的情況要區分(例如買股票,今天可以分為買還是不買的多兩種情況)。由于算法只講知識點是遠遠不夠的故下面我會在例題中穿插知識點幫助理解。動態規劃一般的解題步驟還是1. 狀態表示,2.狀態轉移方程,3.初始化,4.填表順序,5.返回值。在寫代碼時一定要把這5步考慮清楚再寫代碼。

例題1:按摩師(打家劫舍I)

鏈接:按摩師

題目簡介:

一個有名的按摩師會收到源源不斷的預約請求,每個預約都可以選擇接或不接。在每次預約服務之間要有休息時間,因此她不能接受相鄰的預約。給定一個預約請求序列,替按摩師找到最優的預約集合(總預約時間最長),返回總的分鐘數。

解法(動態規劃):

1. 狀態表示:

對于簡單的線性dp ,我們可以用「經驗+題?要求」來定義狀態表示例如:

(1)以某個位置為結尾的最小花費。

(2)以某個位置為起點到終點的最小花費。

故我們這題采用常用的方式:dp[i] 表?:選擇到i 位置時,此時的最?預約時?。由于我們這個題在i 位置的時候,會?臨選擇或者不選擇兩種抉擇,所依賴的狀態需要細分。

下面之所以用f和g是因為高中我們所學的f(x)和g(x),可以換成其他的(但最好用f和g就當作是不成文的規定,這樣代碼的可讀性會更高)。

(1)f[i] 表示:選擇到i 位置時, nums[i] 必選,此時的最?預約時?。

(2)g[i]表示:選擇到i 位置時, nums[i] 不選,此時的最?預約時?。

2.狀態轉移方程

因為狀態表示定義了兩個,因此我們的狀態轉移?程也要分析兩個:

對于f[i] :

如果nums[i] 必選,那么我們僅需知道i - 1 位置在不選的情況下的最?預約時?, 然后加上nums[i] 即可,因此f[i] = g[i - 1] + nums[i] 。

對于g[i] :

如果nums[i] 不選,那么i - 1 位置上選或者不選都可以。因此,我們需要知道i - 1 位置上選或者不選兩種情況下的最?時?,因此g[i] = max(f[i - 1], g[i - 1]) 。

在狀態轉移方程這里可以畫圖來幫助我們理解

3.初始化

這道題的初始化?較簡單,因此?需加輔助節點(前兩篇文章已解釋),僅需初始化f[0] = nums[0], g[0] = 0 即可。

4.填表順序

根據「狀態轉移?程」得「從左往右,兩個表?起填」。

5.返回值

根據「狀態表示」,應該返回max(f[n - 1], g[n - 1]) 。

代碼實現如下:

class Solution {public int massage(int[] nums) {//1.創建dp表//2.初始化//3.填表//4.返回值int n = nums.length;if(n == 0){return 0;}int[] f = new int[n];//選擇int[] g = new int[n];//不選擇f[0] = nums[0];for(int i = 1;i < n;i++){f[i] = g[i - 1] + nums[i];g[i] = Math.max(g[i - 1],f[i - 1]);}return Math.max(g[n -1],f[n - 1]);}
}

時間復雜度:O(n)

空間復雜度:O(n)

例題2:打家劫舍II

鏈接:打家劫舍II

題目簡介:

你是一個專業的小偷,計劃偷竊沿街的房屋,每間房內都藏有一定的現金。這個地方所有的房屋都?圍成一圈?,這意味著第一個房屋和最后一個房屋是緊挨著的。同時,相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警?。

給定一個代表每個房屋存放金額的非負整數數組,計算你?在不觸動警報裝置的情況下?,今晚能夠偷竊到的最高金額。

?解法(動態規劃):

通過閱讀題目友友可以發現這題和例題一是差不多的,唯一不同就是例題二加了一個末尾和開頭的限制。上?個問題是?個「單排」的模式,這?個問題是?個「環形」的模式,也就是?尾是相連的。但是我們可以將「環形」問題轉化為「兩個單排」問題:

(1)偷第?個房屋時的最大?額x ,此時不能偷最后?個房?,因此就是偷[0, n - 2] 區間的房?。

(2)不偷第?個房屋時的最大?額y ,此時可以偷最后?個房?,因此就是偷[1, n - 1] 區 間的房?。

兩種情況下的「最大值」,就是最終的結果。

代碼如下:

下面的rob1方法就是例題一。

class Solution {public int rob(int[] nums) {int n = nums.length;return Math.max(nums[0] + rob1(nums,2,n - 2), rob1(nums,1,n - 1));}public int rob1(int[] nums,int left,int right){if(left > right){return 0;}//1.創建dp表//2.初始化//3.填表//4.返回值int n = nums.length;int[] f = new int[n];int[] g = new int[n];f[left] = nums[left];for(int i = left + 1;i <= right;i++){f[i] = g[i - 1] + nums[i];g[i] = Math.max(g[i - 1],f[i - 1]);}return Math.max(f[right],g[right]);}
}

時間復雜度:O(n)?

空間復雜度:O(n)

例題3:刪除并獲得點數

鏈接:刪除并獲得點數

題目簡介:

給你一個整數數組?nums?,你可以對它進行一些操作。

每次操作中,選擇任意一個?nums[i]?,刪除它并獲得?nums[i]?的點數。之后,你必須刪除?所有?等于?nums[i] - 1?和?nums[i] + 1?的元素。

開始你擁有?0?個點數。返回你能通過這些操作獲得的最大點數。

解法(動態規劃):

其實這道題依舊是「打家劫舍I」問題的變型。?我們注意到題?描述,選擇x 數字的時候, x - 1 與x + 1 是不能被選擇的。像不像「打家劫舍」問題中,選擇i 位置的?額之后,就不能選擇i - 1 位置(數組中)以及i + 1 位置的?額呢~?因此,我們可以創建?個??為10001 (根據題?的數據范圍)的hash 數組,將nums 數 組中每?個元素x ,累加到hash 數組下標為x 的位置處,然后在hash數組上來?次「打家劫舍」即可。

過程如下圖:

弧線表示0到i - 1之間能獲得的最大點數。

代碼如下:

class Solution {public int deleteAndEarn(int[] nums) {//1.創建dp表//2.初始化//3.填表//4.返回值int n = 10001;int[] arr = new int[n];for(int x:nums){arr[x] += x;}int[] f = new int[n];int[] g = new int[n];f[0] = arr[0];for(int i = 1;i < n;i++){f[i] = g[i - 1] + arr[i];g[i] = Math.max(f[i - 1],g[i - 1]);}return Math.max(f[n - 1],g[n - 1]);}
}

時間復雜度:O(n)?

空間復雜度:O(n)

例題4:粉刷房子

鏈接:粉刷房?

題目簡介:

?解法(動態規劃):

?1. 狀態表示:

對于線性dp ,我們可以?「經驗+題?要求」來定義狀態表?:但是我們這個題在i 位置的時候,會?臨「紅」「藍」「綠」三種抉擇,所依賴的狀態需要細分:

(1)dp[i][0] 表?:粉刷到i 位置的時候,最后?個位置粉刷上「紅?」,此時的最?花費。?

(2)dp[i][1] 表?:粉刷到i 位置的時候,最后?個位置粉刷上「藍?」,此時的最?花費。

(3)dp[i][2] 表?:粉刷到i 位置的時候,最后?個位置粉刷上「綠?」,此時的最?花費。

?2.狀態轉移方程

因為狀態表?定義了三個,因此我們的狀態轉移?程也要分析三個:

對于dp[i][0] :

如果第i個位置粉刷上「紅?」,那么i-1位置上可以是「藍?」或者「綠?」。因此我們 需要知道粉刷到i-1位置上的時候,粉刷上「藍?」或者「綠?」的最?花費,然后加上i?位置的花費即可。于是狀態轉移?程為: dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + costs[i - 1][0] ;

同理,我們可以推導出另外兩個狀態轉移?程為:

dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1] ;

dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i - 1][2] 。

?3.初始化

采用最前?加上?個「輔助結點」。

注意點:(1)輔助結點??的值要「保證后續填表是正確的」(2)「下標的映射關系」。

?4.填表順序

?5.返回值

根據「狀態表?」,應該返回最后?個位置粉刷上三種顏?情況下的最?值,因此需要返回: min(dp[n][0], min(dp[n][1], dp[n][2])) 。

代碼如下:

class Solution {public int minCost(int[][] costs) {//1.創建dp表//2.初始化//3.填表//4.返回值int n = costs.length;int[][] dp = new int[n + 1][3];for(int i = 1;i <= n;i++){dp[i][0] = Math.min(dp[i - 1][1],dp[i - 1][2]) + costs[i - 1][0];dp[i][1] = Math.min(dp[i - 1][0],dp[i - 1][2]) + costs[i - 1][1];dp[i][2] = Math.min(dp[i - 1][1],dp[i - 1][0]) + costs[i - 1][2];}return Math.min(dp[n][0],Math.min(dp[n][1],dp[n][2]));}
}

時間復雜度:O(n)?

空間復雜度:O(n)

例題5:買賣股票的最佳時機含冷凍

鏈接:買賣股票的最佳時機含冷凍期

題目簡介:

??解法(動態規劃):

?1. 狀態表示:

這?我們選擇?較常?的?式,以某個位置為結尾,結合題?要求,定義?個狀態表?:由于有「買?」「可交易」「冷凍期」三個狀態,因此我們可以選擇?三個數組,其中:

(1)dp[i][0] 表?:第i 天結束后,處于「買?」狀態,此時的最?利潤。

(2)dp[i][1] 表?:第i 天結束后,處于「可交易」狀態,此時的最?利潤。

(3)dp[i][2] 表?:第i 天結束后,處于「冷凍期」狀態,此時的最?利潤。

我們要謹記規則:

(1)處于「買?」狀態的時候,我們現在有股票,此時不能買股票,只能繼續持有股票,或者賣 出股票;

(2)處于「買?」狀態的時候,我們現在有股票,此時不能買股票,只能繼續持有股票,或者賣 出股票;

?2.狀態轉移方程

確定狀態表示后,我們可以畫圖來幫助我們理解根據題目要求我們可以畫圖下圖,并推出狀態轉移方程。

?3.初始化

三種狀態都會?到前?個位置的值,因此需要初始化每??的第?個位置:

dp[0][0] :此時要想處于「買?」狀態,必須把第?天的股票買了,因此dp[0][0] = - prices[0] ; dp[0][1] :啥也不??即可,因此dp[0][1] = 0 ;

dp[0][2] :手上沒有股票,買?下賣?下就處于冷凍期,此時收益為0 ,因此 dp[0][2] = 0 。

4.填表順序

根據「狀態表?」,我們要三個表?起填,每?個表「從左往右」。

5.返回值

應該返回「賣出狀態」下的最?值,因此應該返回max(dp[n - 1][1], dp[n - 1] [2]) 。

代碼如下:

class Solution {public int maxProfit(int[] prices) {//1.創建dp表//2.初始化//3.填表//4.返回值int n = prices.length;int[][] dp = new int[n][3];dp[0][0] = -prices[0];for(int i = 1;i < n;i++){dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]);dp[i][1] = Math.max(dp[i - 1][1],dp[i - 1][2]);dp[i][2] = dp[i - 1][0] + prices[i];}return Math.max(dp[n - 1][1],dp[n - 1][2]);}
}

時間復雜度:O(n)?

空間復雜度:O(n)

結語:

其實寫博客不僅僅是為了教大家,同時這也有利于我鞏固自己的知識點,和一個學習的總結,由于作者水平有限,對文章有任何問題的還請指出,接受大家的批評,讓我改進,如果大家有所收獲的話還請不要吝嗇你們的點贊收藏和關注,這可以激勵我寫出更加優秀的文章。

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

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

相關文章

深度學習 精選筆記(8)梯度消失和梯度爆炸

學習參考&#xff1a; 動手學深度學習2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、請聯系侵刪。 ②已寫完的筆記文章會不定時一直修訂修改(刪、改、增)&#xff0c;以達到集多方教程的精華于一文的目的。 ③非常推薦上面&#xff08;學習參考&#x…

帶你快速初步了解Python列表

1.列表 列表主要是用來存儲多個數據&#xff0c;是有序的集合 2.創建列表 """ 語法&#xff1a;變量名 [數據1,數據2,數據3......] 注意&#xff1a;列表中的數據類型可以是各種不同的數據類型 """ 創建空列表 list1 [] print(list1) …

Gitlab: 私有化部署

目錄 1. 說明 2. 資源要求 3. 安裝 4. 配置實踐 4.1 服務器 4.2 人員與項目 4.2 部署準備 4.2.1 訪問變量及用戶賬號設置 4.2.2 Runner設置 4.2.3 要點 5. 應用項目 CI/CD 6. 參考 1. 說明 gitlab是一個強大且免費的代碼管理/部署工具&#xff0c;能統一集成代碼倉…

AngularJS入門

1. AngularJS簡介 AngularJS是一個JavaScript框架,用js編寫的庫 <script src="https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js"></script> <!-- 放在<body> 元素的底部。提高網頁加載速度 -->1.1. AngularJS 擴展了 HTML …

Freesia項目目錄結構

目錄結構 前端目錄&#xff1a; &#xff08;目錄結構來自layui-vue-admin&#xff09; src文件下 api&#xff08;前端請求后端服務的路由&#xff09;assert&#xff08;一些內置或必要的資源文件&#xff09;layouts&#xff08;全局框架樣式組件&#xff09;router&…

Unity(第十九部)射線

在Unity中&#xff0c;射線檢測通常用于碰撞檢測&#xff0c;比如&#xff1a;在游戲中&#xff0c;開槍射擊時&#xff0c;需要判斷擊中的物體、子彈擊中的位置&#xff1b;用鼠標來控制物體的移動&#xff1b;用鼠標拾取某個物體。 射線&#xff0c;顧名思義&#xff0c;在數…

【轉載】深度學習筆記——詳解損失函數

原文鏈接: https://blog.csdn.net/weixin_53765658/article/details/136360033 CSDN賬號: Purepisces github賬號: purepisces 希望大家可以Star Machine Learning Blog https://github.com/purepisces/Wenqing-Machine_Learning_Blog 損失函數 根據您使用的神經網絡類型和數…

第四十七回 一丈青單捉王矮虎 宋公明二打祝家莊-強大而靈活的python裝飾器

四面全是埋伏&#xff0c;宋江和眾人一直繞圈跑不出去。正在慌亂之時&#xff0c;石秀及時趕到&#xff0c;教大家碰到白楊樹就轉彎走。走了一段時間&#xff0c;發現圍的人越來越多&#xff0c;原來祝家莊以燈籠指揮號令。花榮一箭射下來紅燈龍&#xff0c;伏兵自己就亂起來了…

Northwestern University-844計算機科學與技術/軟件工程-復試注意事項【考研復習】

本文提到的西北大學是位于密歇根湖泊畔的西北大學。西北大學&#xff08;英語&#xff1a;Northwestern University&#xff0c;簡稱&#xff1a;NU&#xff09;是美國的一所著名私立研究型大學。它由九人于1851年創立&#xff0c;目標是建立一所為西北領地地區的人服務的大學。…

【力扣白嫖日記】550.游戲玩法分析IV

前言 練習sql語句&#xff0c;所有題目來自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免費數據庫練習題。 今日題目&#xff1a; 550.游戲玩法分析IV 表&#xff1a;Activity 列名類型player_idintdevice_idintevent_datedategames_played…

從 iOS 設備恢復數據的 20 個iOS 數據恢復工具

作為 iPhone、iPad 或 iPod 用戶&#xff0c;您可能普遍擔心自己可能會丟失存儲在珍貴 iOS 設備中的所有寶貴數據。數據丟失的原因多種多樣&#xff0c;這里列出了一些常見原因&#xff1a; 1. iOS 軟件更新 2. 恢復出廠設置 3. 越獄 4. 誤操作刪除數據 5. iOS 設備崩潰 …

C++筆記(五)--- 虛函數(virtual)

目錄 虛函數介紹 虛函數、覆蓋和重載區別 虛函數介紹 C的虛函數是多態性的表現 1.構造函數不能為虛函數2.子類繼承時虛函數仍為虛函數3.虛函數類外實現時&#xff0c;不需要加virtual4.有虛函數的類&#xff0c;析構函數一定要寫成虛函數&#xff08;否則可能會造成內存泄漏&…

【代碼隨想錄python筆記整理】第十六課 · 出現頻率最高的字母

前言:本筆記僅僅只是對內容的整理和自行消化,并不是完整內容,如有侵權,聯系立刪。 一、哈希表初步 在之前的學習中,我們使用數組、字符串、鏈表等等,假如需要找到某個節點,則都要從頭開始,逐一比較,直到找到為止。為了能夠直接通過要查找的記錄找到其存儲位置,我們選…

設備像素、css像素、設備獨立像素、dpr、ppi 之間的區別

設備像素、CSS 像素、設備獨立像素 (DIP)、設備像素比 (DPR) 和每英寸像素密度 (PPI) 是與屏幕分辨率和顯示質量相關的概念。它們之間的區別如下&#xff1a; 設備像素&#xff1a;設備像素是物理屏幕上的最小可見單元&#xff0c;用于實際渲染圖像或文本。它表示硬件像素點的數…

、JMETER與它的組件們

os進程取樣器 這個取樣器可以讓jmeter直接調用python寫的測試數據 這樣就可以調用python寫的測試數據給到jmeter進行調用 注意&#xff1a;1建議python返回轉json格式dumps一下&#xff1b;2py文件中需要把結果打印出來&#xff0c;可以不用函數直接編寫 傳到jmeter之后可以用…

你真的了解C語言中的【柔性數組】嗎~

柔性數組 1. 什么是柔性數組2. 柔性數組的特點3. 柔性數組的使用4. 柔性數組的優勢 1. 什么是柔性數組 也許你從來沒有聽說過柔性數組這個概念&#xff0c;但是它確實是存在的。 C99中&#xff0c;結構體中的最后?個元素允許是未知大小的數組&#xff0c;這就叫做柔性數組成員…

MyBatis 學習(五)之 高級映射

目錄 1 association 和 collection 介紹 2 案例分析 3 一對一關聯和一對多關聯 4 參考文檔 1 association 和 collection 介紹 在之前的 SQL 映射文件中提及了 resultMap 元素的 association 和 collection 標簽&#xff0c;這兩個標簽是用來關聯查詢的&#xff0c;它們的屬…

算法--時空復雜度分析以及各個數據量對應的可使用的算法(C++;1s內)

這里寫目錄標題 由數據范圍反推算法時間復雜度以及算法內容分析時間復雜度看循環實例1實例2 固定時間復雜度快排和歸并排序二分高精度算法雙指針算法單鏈表插入刪除操作棧和隊列的操作單調棧和單調隊列KMPTire并查集堆哈希表BFS、DFS圖的深度優先、寬度優先遍歷dijkstra算法樸素…

題目 1037: [編程入門]宏定義的練習

問題描述&#xff1a; 輸入兩個整數&#xff0c;求他們相除的余數。用帶參的宏來實現&#xff0c;編程序。 樣例輸入&#xff1a; 3 2 樣例輸出&#xff1a; 1 代碼分析&#xff1a; 這段代碼實現了輸入兩個整數&#xff0c;然后使用帶參數的宏計算它們相除的余數&…

「MySQL」深入理解MySQL中常用的SQL函數

「MySQL」深入理解MySQL中常用的SQL函數 窗口函數參考文章1. COALESCE 函數2. USING 函數3. LEAD 函數4. interval 函數5. INSTR 函數6. substring_index 函數7. LENGTH 函數和 CHAR_LENGTH 函數 窗口函數參考文章 SQL窗口函數 1. COALESCE 函數 COALESCE 函數的作用是從一…