动态规划,复习
- 软件开发
- 2025-08-28 17:51:01

一.动态规划 1.
思路:每次递增序列结束都取最优解
class Solution { public: int findLengthOfLCIS(vector<int>& nums) { int ans = -1,temp = 1; for(int i = 0;i<nums.size()-1;i++){ if(nums[i]<nums[i+1]) temp++; else{ ans = max(ans,temp); temp = 1; } } ans = max(ans,temp); return ans; } }; 2.思路:动态规划五部曲
/* dp[i]表示以i为结尾的最长子序列的长度 递推公式为前i项的哪个有最大子序列长度,哪个就是dp[i]=max(dp[i],dp[j]+1) 初始化为每个长度都为1; 前到后 */ class Solution { public: int lengthOfLIS(vector<int>& nums) { vector<int>dp(nums.size()+1,1); for(int i = 0;i<nums.size();i++){ for(int j = 0;j<i;j++){ if(nums[i]>nums[j]) dp[i] = max(dp[j]+1,dp[i]); } } return ranges::max(dp); } }; 3./思路:动规五部曲
/* dp[i][j]表示为nums1前i-1项,和nums2前j-1项最大的重复子集dp[i][j]; dp[i][j] = dp[i-1][j-1]+1 初始化都为0 */ class Solution { public: int findLength(vector<int>& nums1, vector<int>& nums2) { vector<vector<int>> dp (nums1.size() + 1, vector<int>(nums2.size() + 1, 0)); int result = 0; for (int i = 1; i <= nums1.size(); i++) { for (int j = 1; j <= nums2.size(); j++) { if (nums1[i - 1] == nums2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; } if (dp[i][j] > result) result = dp[i][j]; } } return result; } }; 4.思路:动规五部曲
/* dp[i][j]表示为text1前i-1项和text2的前j-1项的最大公共子序列长度 递推公式:dp[i][j] = dp[i-1][j-1]+1 初始化为0 */ class Solution { public: int longestCommonSubsequence(string text1, string text2) { vector<vector<int>>dp(text1.size()+1,vector<int>(text2.size()+1,0)); for(int i = 1; i <= text1.size(); i++){ for(int j = 1; j <= text2.size(); j++){ if(text1[i-1]==text2[j-1]) dp[i][j] = dp[i-1][j-1]+1; else dp[i][j] = max(dp[i-1][j],dp[i][j-1]); } } return dp[text1.size()][text2.size()]; } }; 二.回顾 1. 埃拉托斯特尼筛法 #include <iostream> #include <vector> using namespace std; const int MAX_N = 100000000; // n 的最大值为 10^8 // 埃拉托斯特尼筛法 void sieve_of_eratosthenes(int n, vector<int>& primes) { vector<bool> is_prime(n + 1, true); // 默认所有数是素数 is_prime[0] = is_prime[1] = false; // 0 和 1 不是素数 for (int i = 2; i * i <= n; ++i) { if (is_prime[i]) { for (int j = i * i; j <= n; j += i) { is_prime[j] = false; } } } // 收集所有素数 for (int i = 2; i <= n; ++i) { if (is_prime[i]) { primes.push_back(i); } } } int main() { ios::sync_with_stdio(0); // 加速 cin 和 cout int n, q; cin >> n >> q; // 找到小于等于 n 的所有素数 vector<int> primes; sieve_of_eratosthenes(n, primes); // 处理每个查询 while (q--) { int k; cin >> k; cout << primes[k - 1] << endl; // 输出第 k 小的素数 } return 0; } 2.二分
思路:二分答案加贪心
class Solution { public: int splitArray(vector<int>& nums, int k) { int l = 0,r= 0; for(int t:nums) r +=t; int ans = 0; while(l<=r){ int mid = (r+l)>>1; if(check(nums,mid,k)){ ans = mid; r = mid-1; }else l = mid+1; } return ans; } bool check(vector<int>& nums,int mid,int k){ int sum = 0; int count = 1; for(int i = 0;i<nums.size();i++){ if(nums[i]>mid)return false; sum+=nums[i]; if(sum>mid){ count++; sum = nums[i]; if(count>k)return false; } } return true; } }; 3.二分思路:二分答案模板题
#include <stack> #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <vector> #include <climits> #include <cstdlib> #include <cmath> #include <unordered_set> #include <unordered_map> #include <map> #include <set> #include <cctype> using namespace std; const int MAXN = 50001; int stone[MAXN], a, n, m; bool check(int d) { int p = 0, ans = 0; for (int i = 1; i <= n; i++) { if (stone[i] - p < d) ans++; else p = stone[i]; } if (ans <= m) return true; else return false; } int main() { scanf("%d %d %d", &a, &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &stone[i]); stone[++n] = a; int l = 0, r = a, mid; while (l < r) { mid = (l + r + 1) / 2; if (check(mid)) l = mid; else r = mid - 1; } printf("%d\n", l); return 0; } 4.卡特兰数 #include <stack> #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <vector> #include <climits> #include <cstdlib> #include <cmath> #include <unordered_set> #include <unordered_map> #include <map> #include <set> #include <cctype> using namespace std; int main() { int n; cin >> n; long long dp[10000]; dp[0] = 1; dp[1] = 1; for (int i = 2; i <= 2 * n + 1; i++) { dp[i] = i * dp[i - 1]; } cout << dp[2 * n] / (dp[n] * dp[n] * (n + 1)); return 0; } 三.算阶 1.思路:单调栈
#include <stack> #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <vector> #include <climits> #include <cstdlib> #include <cmath> #include <unordered_set> #include <unordered_map> #include <map> #include <set> #include <cctype> using namespace std; int main() { int n; while (cin >> n && n != 0) { vector<long long>arr(n + 2,0); for (int i = 1; i <= n; i++) cin >> arr[i]; long long stk[100005], top = 0; long long ans = INT_MIN; for (int i = 0; i <= n + 1; i++) { while (top && arr[stk[top]] > arr[i]) { int cur = stk[top--]; int high = arr[cur]; int weihgt = i - stk[top] - 1; ans = ans > high * weihgt ? ans : high * weihgt; } stk[++top] = i; } cout << ans << endl; } return 0; } 四.分治 1.思路:归并排序的思想加上分治,先左边,在右边,在跨左右计算小和
#include <stack> #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <vector> #include <climits> #include <cstdlib> #include <cmath> #include <unordered_set> #include <unordered_map> #include <map> #include <set> #include <cctype> using namespace std; const int N = 100005; long long arr[N], help[N]; int n; long long merge(int l, int mid, int r) { long long sum = 0, ans = 0; for (int i = l, j = mid + 1, sum = 0; j <= r; j++) { while (arr[i] <= arr[j] && i <= mid) sum += arr[i++]; ans += sum; } int i = l; int a = l; int b = mid + 1; while (a <= mid && b <= r) help[i++] = arr[a] <= arr[b] ? arr[a++] : arr[b++]; while (a <= mid) help[i++] = arr[a++]; while (b <= r) help[i++] = arr[b++]; for (int i = l; i <= r; i++) arr[i] = help[i]; return ans; } long long small(int l, int r) { if (l == r)return 0; int mid = (l + r) / 2; return small(l, mid) + small(mid + 1, r) + merge(l, mid, r); } int main() { cin >> n; for (int i = 0; i < n; i++) cin >> arr[i]; cout << small(0, n - 1); return 0; }