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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

朝花夕拾——动态规划

發布時間:2024/1/8 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 朝花夕拾——动态规划 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Overview

最長連續子序列和

-2 6 -1 5 4 -7 2 3

求連續的子數列最大和。

根據遞歸的思路想:f(n) = max{ f(n-1) + num[n], num[n] }


LeetCode 300. 最長遞增子序列 LIS

題目鏈接:https://leetcode-cn.com/problems/longest-increasing-subsequence/

給你一個整數數組 nums ,找到其中最長嚴格遞增子序列的長度。(子序列可以不連續)

輸入:nums = [10,9,2,5,3,7,101,18] 輸出:4 解釋:最長遞增子序列是 [2,3,7,101],因此長度為 4 。輸入:nums = [7,7,7,7,7,7,7] 輸出:1

終于碰到這個題了,之前一直分不清LCS和LIS。

方法1:樸素動態規劃

用一個二重循環來實現,時間復雜度n方。

定義dp[i]的含義,以nums[i]結尾的子序列的最大長度。

for (int i = 0; i < n; ++i) {for (int j = 0; j < i; ++j) {if (nums[j] < nums[i]) {dp[i] = max(dp[i], dp[j] + 1);}}}

方法2:二分+動態規劃

考慮方法一中的內層循環,是否可以優化。

重新定義dp[i],長度為i的子序列中最后一位數字的最小值。

做法:維護一個單調數組dp[],在遍歷nums[]的時候,如果當前元素a比dp的棧頂元素大,則直接推入棧,如果比棧頂元素小,則二分這個數組,找到最小的比a大的數dp[k],替換它,以保證在長度k下,dp[k]中的值始終最小。

dp的長度就是最終結果。

int lengthOfLIS(vector<int>& nums) {if (nums.size() == 0) return 0;vector<int> dp(1, nums[0]);for (int i=1; i<nums.size(); ++i) {if (nums[i] > dp[dp.size() - 1]) {dp.push_back(nums[i]);continue;}int lo = 0;int hi = dp.size() - 1;while (lo < hi) {int mid = (lo + hi) / 2;if (nums[i] > dp[mid]) {lo = mid + 1;} else {hi = mid;}}dp[lo] = nums[i];}return dp.size();}

非連續最大子集

給你一個序列arr = {}

請你求出它的一個子集,要求,子集和最大,且子集的元素在原序列終不能相鄰

入門DP

對于每一個數,dp[i] = max{ dp[i-1], dp[i] + arr[i-1] }

那么就和斐波那契有點像了


LeetCode 1143. 最長公共子序列 LCS

給定兩個字符串 text1 和 text2,返回這兩個字符串的最長 公共子序列 的長度。如果不存在 公共子序列 ,返回 0 。

輸入:text1 = "abcde", text2 = "ace" 輸出:3 解釋:最長公共子序列是 "ace" ,它的長度為 3 。

創建二維數組dp,其中dp[i][j] 表示text[0:i]和text2[0:j]的最長公共子序列的長度。

int longestCommonSubsequence(string text1, string text2) {int dp[1003][1003], n = text1.size(), m = text2.size();memset(dp, 0, sizeof(dp));dp[0][0] = text1[0] == text2[0] ? 1 : 0;for (int i=1; i<m; ++i) {dp[0][i] = text1[0] == text2[i] ? 1 : max(dp[0][i-1], 0);}for (int i=1; i<n; ++i) {dp[i][0] = text1[i] == text2[0] ? 1 : max(dp[i-1][0], 0);}for (int i=1; i<n; ++i) {for (int j=1; j<m; ++j) {dp[i][j] = text1[i] == text2[j] ? dp[i-1][j-1] + 1 : max(dp[i-1][j], dp[i][j-1]);}}return dp[n-1][m-1];}

hdu1506 Largest Rectangle in a Histogram

對于每一個高度h[i],搜索它能到達的最左,和最右,最大面積Smax = Max{ i | 面積Si = (最右 - 最左 + 1) *h[i] }

這樣的時間復雜度為O(n^2),必超時

舉例 2,3,4,5

要判斷2能到達最右的位置,不需要循環比較,只需要知道3能到達的最右是哪里,因為若3能到達的位置,2必然也能到達

1 #include<cstdio>2 #include<iostream>3 using namespace std;4 5 int main()6 {7 int n;8 while(scanf("%d", &n) && n)9 { 10 long long h[100007]; 11 long long l[100007]; 12 long long r[100007]; 13 for(int i=1;i<=n;i++) 14 { 15 scanf("%lld", &h[i]); 16 l[i] = r[i] = i; 17 } 18 h[0] = h[n+1] = -1; 19 for(int i=1;i<=n;i++) 20 { 21 while(h[i] <= h[l[i]-1]) { 22 l[i] = l[l[i]-1]; 23 } 24 } 25 for(int i=n;i>=1;i--) 26 { 27 while(h[i] <= h[r[i]+1]) { 28 r[i] = r[r[i]+1]; 29 } 30 } 31 long long ans = 0; 32 for(int i=1;i<=n;i++) 33 { 34 ans = ans > (r[i]-l[i]+1)*h[i] ? ans : (r[i]-l[i]+1)*h[i]; 35 } 36 printf("%lld\n",ans); 37 } 38 }

LeetCode 338. Counting Bits

第一道自己做出來的DP!!!紀念合影,你沒聽錯我就是這么菜

給你一個非負整數num,求從0到num的num+1個數中,每個數二進制表示的1的個數,返回一個數組

就是dp嘛,暴力的辦法就是for from 0 to num,每個數的每一個二進制位比較,設二進制位最壞長度為31位,那么復雜度就是O(31*n)

其中大量重復計算,所以用動態規劃解決,自底向上

1 class Solution {2 public:3 vector<int> countBits(int num) {4 vector<int>dp(num+1);5 dp.resize(num+1);6 dp[0] = 0;7 for(int i=1;i<=num;i++)8 {9 if((i & 1) == 0) 10 dp[i] = dp[i>>1]; 11 else 12 dp[i] = dp[i>>1] + 1; 13 } 14 return dp; 15 } 16 };

能不能組成S?

給你一個序列arr = {},和一個數S,問你序列里的數能不能組成S,又是簡單的選和不選問題


web數據挖掘中的編輯距離

這個有點難想


稍微變了一小下的01背包

uim拉著基友小A到了一家……餐館,很低端的那種。uim指著墻上的價目表說:“隨便點”。

題目描述
不過uim由于買了一些書,口袋里只剩M元(M≤10000)。

餐館雖低端,但是菜品種類不少,有N種(N≤100),第i種賣a?元(ai?≤1000)。由于是很低端的餐館,所以每種菜只有一份。

小A奉行“不把錢吃光不罷休”,所以他點單一定剛好吧uim身上所有錢花完。他想知道有多少種點菜方法。

思路:和裸的價值+容量的01背包不同,原來是求可放入背包且價值最大化,這個是必須裝滿背包,求有多少種方案。

根據題意設數組dp[i][j]為前i種菜品恰好花費j元的點菜方法數。那么,考慮第i種菜點或不點,若不點,則說明前i-1種菜,已經恰好花費j元;若點,則說明前i-1種菜,花費j-ai元,這樣,在點完第i種菜后,恰好花費j元。

因此容易得出公式

dp[i][j] = dp[i-1][j] + dp[i-1][j-ai]

然而很多人想到這里以后就不知道接下來怎么做了。(比如說我)

但是在看到"j - ai"后,應該能想到,對j - ai的情況進行枚舉。

  • 若j > ai,則和上式一樣。
  • 若j < ai,則說明第i道菜,壓根就買不起,因此dp[i][j] = dp[i-1][j]。
  • 若j == ai,那么說明可以只點這一道菜作為一種新的方案,dp[i][j] = dp[i-1][j] + 1。

96. 不同的二叉搜索樹

給定一個整數 n,求以 1 … n 為節點組成的二叉搜索樹有多少種?

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/unique-binary-search-trees/
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。

這個題我一開始沒有想到能拿dp做。

class Solution { public:int numTrees(int n) {int g[20] = {1, 1};for (int i = 2; i <= n; ++ i) {for (int j = 1; j <= i; ++ j) {g[i] += g[j-1] * g[i-j];}}return g[n];} };

354. 俄羅斯套娃信封問題

題目鏈接:https://leetcode-cn.com/problems/russian-doll-envelopes/

給定一些標記了寬度和高度的信封,寬度和高度以整數對形式(w, h)出現。當另一個信封的寬度和高度都比這個信封大的時候,這個信封就可以放進另一個信封里,如同俄羅斯套娃一樣。

請計算最多能有多少個信封能組成一組“俄羅斯套娃”信封(即可以把一個信封放到另一個信封里面)。

說明:
不允許旋轉信封。

是不是很像LIS的變型?但是這里要注意對原數組進行一個從小到大的排序。對于w從小到大排序,對于h從大到小排序,我這里還沒有想明白,為什么h降序排序就是對的,升序排序就是錯的。

int maxEnvelopes(vector<vector<int>>& envelopes) {sort(envelopes.begin(), envelopes.end(), [](const vector<int> &u, const vector<int> &v){return u[0] < v[0] || (u[0] == v[0] && u[1] > v[1]);});vector<pair<int, int>> dp(1, {envelopes[0][0], envelopes[0][1]});for (const auto &envelope : envelopes) {if (envelope[0] > dp[dp.size() - 1].first && envelope[1] > dp[dp.size() - 1].second) {dp.push_back({envelope[0], envelope[1]});continue;}int lo = 0;int hi = dp.size() - 1;while (lo < hi) {int mid = (lo + hi) / 2;if (envelope[0] > dp[mid].first && envelope[1] > dp[mid].second) {lo = mid + 1;} else {hi = mid;}}dp[lo] = {envelope[0], envelope[1]};}return dp.size(); }

我的代碼還是比較復雜了,看了題解以后發現,只需要對h做LIS即可,因為h是降序排列的,當你對h做LIS時,別忘了,LIS是最長遞增子序列,只要被你選入的h一定是遞增的,但是你又是降序排列的,這說明你選取的兩個信封一定有w2 > w1,這里是嚴格大于,仔細想一想。

總結

以上是生活随笔為你收集整理的朝花夕拾——动态规划的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。