From c357fb056b2ede651783ce9c0c1cac8df2be889f Mon Sep 17 00:00:00 2001 From: Estom Date: Sat, 18 Sep 2021 10:19:59 +0800 Subject: [PATCH] 123 --- code_segment/xiaohongshu1.cpp | 47 +++++ code_segment/xiecheng1.cpp | 0 工作日志/2021年8月31日-九月份国企.md | 1 + 工作日志/2021年8月31日-九月份计划.md | 7 +- 工作日志/2021年8月3日-八月份计划.md | 6 +- 工作日志/2021年9月12日.md | 1 - 工作日志/2021年9月15日-今日计划.md | 6 + 算法/A类:基本算法/11 递归与迭代.md | 6 +- 算法/A类:基本算法/4.4 拓扑排序问题.md | 163 +++++++++++++++++- 算法/A类:基本算法/4.4.cpp | 115 ++++++++++++ 算法/A类:基本算法/4.7 数组中的逆序对.md | 6 +- 算法/A类:基本算法/5 动态规划.md | 2 +- .../A类:基本算法/5 动态规划——序列动态规划.md | 2 +- .../A类:基本算法/5 动态规划——矩阵动态规划.md | 2 +- .../A类:基本算法/5 动态规划——线性动态规划.md | 14 +- 算法/A类:基本算法/5.10 零钱兑换.md | 83 +++++++++ 算法/A类:基本算法/5.13 正则表达式的匹配.md | 40 +++++ 17 files changed, 478 insertions(+), 23 deletions(-) create mode 100644 code_segment/xiaohongshu1.cpp create mode 100644 code_segment/xiecheng1.cpp delete mode 100644 工作日志/2021年9月12日.md create mode 100644 工作日志/2021年9月15日-今日计划.md create mode 100644 算法/A类:基本算法/4.4.cpp create mode 100644 算法/A类:基本算法/5.10 零钱兑换.md diff --git a/code_segment/xiaohongshu1.cpp b/code_segment/xiaohongshu1.cpp new file mode 100644 index 00000000..3c83ed70 --- /dev/null +++ b/code_segment/xiaohongshu1.cpp @@ -0,0 +1,47 @@ +#include +using namespace std; +/** + * 交换任意两数的本质是改变了元素位置, + * 故建立元素与其目标状态应放置位置的映射关系 + */ +int getMinSwaps(vector v) +{ + vector v1(v); //将A内元素复制到B。 + sort(v1.begin(), v1.end()); + map m; + int len = v.size(); + for (int i = 0; i < len; i++) + { + m[v1[i]] = i; // 建立每个元素与其应放位置的映射关系 + } + int loops = 0; // 循环节个数 + vector flag(len, false); //初始化 + //找出循环节的个数 + for (int i = 0; i < len; i++) + { + if (!flag[i]) + { + int j = i; + while (!flag[j]) //对环处理 + { + flag[j] = true; + j = m[v[j]]; //原序列中j位置的元素在有序序列中的位置 + } + loops++; + } + } + return len - loops; +} +vector v; +int main() +{ + int n,k; + cin>>n; + while(n--){ + cin>>k; + v.push_back(k); + } + int num = getMinSwaps(v); + cout<<"交换次数:"< tuopu1(vector> vec){ + vector res; + vector in(vec.size(),0); + vector flag(vec.size(),0); + for(int i=0;i> &vec,stack &st,vector &flag,int node){ + for(int i=0;i> &vec,vector &cost,int node,int c){ + int max_cost=c+cost[node]; + // cout<>N; + cout< cost(N,0); + // 使用邻接链表表示关系吧。单点触发的所有边 + vector> vec(N,vector()); + cin.ignore(); + // string input2; + // getline(cin,input2); + for(int i=0;i>name; + is>>cost[i]; + int next; + while(is>>next){ + vec[i].push_back(next); + } + cout< res = tuopu1(vec); + for(auto a:res){ + cout< flag(vec.size(),0); + stack st; + tuopu2(vec,st,flag,0); + vector res2; + while(!st.empty()){ + cout< +#include +#include +#include +#include +using namespace std; +// 拓扑排序——循环入度为零 +vector tuopu1(vector> vec){ + vector res; + vector in(vec.size(),0); + vector flag(vec.size(),0); + for(int i=0;i> &vec,stack &st,vector &flag,int node){ + for(int i=0;i> &vec,vector &cost,int node,int c){ + int max_cost=c+cost[node]; + // cout<>N; + cout< cost(N,0); + // 使用邻接链表表示关系吧。单点触发的所有边 + vector> vec(N,vector()); + cin.ignore(); + // string input2; + // getline(cin,input2); + for(int i=0;i>name; + is>>cost[i]; + int next; + while(is>>next){ + vec[i].push_back(next); + } + cout< res = tuopu1(vec); + for(auto a:res){ + cout< flag(vec.size(),0); + stack st; + tuopu2(vec,st,flag,0); + vector res2; + while(!st.empty()){ + cout< 1. ### 选择策略 * 数组 * 动态规划 - * 原理: 以斐波那契数列性质 f(n + 1) = f(n) + f(n - 1)f(n+1)=f(n)+f(n−1) 为转移方程。 + * 原理: 以斐波那契数列性质f(n+1)=f(n)+f(n−1) 为转移方程。 ### 算法设计 * 状态定义: 设$dp$为一维数组,其中 $dp[i]$ 的值代表 斐波那契数列第 $i$个数字 。 * 转移方程: $dp[i + 1] = dp[i] + dp[i - 1]$,即对应数列定义 $f(n + 1) = f(n) + f(n - 1)$; -* 初始状态: $dp[0] = 0 dp[1] = 1$,即初始化前两个数字; +* 初始状态: $dp[0] = 0,dp[1] = 1$,即初始化前两个数字; * 返回值:$dp[n]$ ,即斐波那契数列的第 n 个数字。 @@ -122,12 +122,12 @@ public int climbStairs(int n) { ### 算法设计 * **状态定义**: 设动态规划列表 dp ,dp[i]dp[i] 代表以元素 nums[i]nums[i] 为结尾的连续子数组最大和。 - * 为何定义最大和 dp[i]dp[i] 中必须包含元素 nums[i]nums[i] :保证 dp[i]dp[i] 递推到 dp[i+1]dp[i+1] 的正确性;如果不包含 nums[i]nums[i] ,递推时则不满足题目的 连续子数组 要求。 -* **转移方程**: 若 dp[i-1] \leq 0dp[i−1]≤0 ,说明 dp[i - 1]dp[i−1] 对 dp[i]dp[i] 产生负贡献,即 dp[i-1] + nums[i]dp[i−1]+nums[i] 还不如 nums[i]nums[i] 本身大。 - * 当 dp[i - 1] > 0dp[i−1]>0 时:执行 dp[i] = dp[i-1] + nums[i]dp[i]=dp[i−1]+nums[i] - * 当 dp[i - 1] \leq 0dp[i−1]≤0 时:执行 dp[i] = nums[i]dp[i]=nums[i] ; + * 为何定义最大和 dp[i] 中必须包含元素 nums[i] :保证dp[i] 递推到 dp[i+1]的正确性;如果不包含nums[i] ,递推时则不满足题目的 连续子数组 要求。 +* **转移方程**: 若dp[i−1]≤0 ,说明 dp[i - 1]对 dp[i] 产生负贡献,即 dp[i-1] + nums[i]还不如 nums[i]本身大。 + * 当 dp[i - 1] > 0时:执行 dp[i] = dp[i-1] + nums[i] + * 当 dp[i−1]≤0 时:执行 dp[i] = nums[i]; * **初始状态**: dp[0] = nums[0]dp[0]=nums[0],即以 nums[0]nums[0] 结尾的连续子数组最大和为 nums[0]nums[0] 。 -* **返回值**: 返回 dpdp 列表中的最大值,代表全局最大值。 +* **返回值**: 返回 dp 列表中的最大值,代表全局最大值。 ![](image/2021-03-29-09-50-50.png) diff --git a/算法/A类:基本算法/5.10 零钱兑换.md b/算法/A类:基本算法/5.10 零钱兑换.md new file mode 100644 index 00000000..95b793f1 --- /dev/null +++ b/算法/A类:基本算法/5.10 零钱兑换.md @@ -0,0 +1,83 @@ +## 零钱兑换 + +### 问题描述 + +给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 + +请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 + +假设每一种面额的硬币有无限个。  + +``` +输入:amount = 5, coins = [1, 2, 5] +输出:4 +解释:有四种方式可以凑成总金额: +5=5 +5=2+2+1 +5=2+1+1+1 +5=1+1+1+1+1 +``` + +### 问题分析 + +* 典型的动态规划 +* 典型的完全背包问题 + +### 策略选择 +* 动态规划 + * 采取两个方向上的动态规划。两个方向上的动态规划是非等价独立的。 +* 数组矩阵线性数据结构 + + +### 算法设计 + +* 阶段划分:规模增长的方向有两个。第一个规模增长的方向是硬币的种类。第二个规模增长的方向是金钱的总量。 +* 状态变量dp[i][j]表示使用第i个硬币,达到j分钱所有的可能。 +* 状态转移方程 + * if k*coins[i]== amount dp[i][j]++; + * if k*coins[i]& coins) { + vector dp(amount + 1); + dp[0] = 1; + for (int& coin : coins) { + for (int i = coin; i <= amount; i++) { + dp[i] += dp[i - coin]; + } + } + return dp[amount]; + } +// 使用两个规模增长方向 + int change(int amount, vector& coins) { + if(amount==0)return 1; + vector> dp(coins.size()+1,vector(amount + 1,0)); + for (int k=1;k<=coins.size();k++) { + int coin=coins[k-1]; + for(int i=1;i<=amount;i++){ + for(int j=0;j*coin<=i;j++){ + if(j*coin==i){ + dp[k][i]++; + } + dp[k][i]+=dp[k-1][i-j*coin]; + } + } + } + return dp[coins.size()][amount]; + } +}; +``` \ No newline at end of file diff --git a/算法/A类:基本算法/5.13 正则表达式的匹配.md b/算法/A类:基本算法/5.13 正则表达式的匹配.md index 45af2f86..b1627feb 100644 --- a/算法/A类:基本算法/5.13 正则表达式的匹配.md +++ b/算法/A类:基本算法/5.13 正则表达式的匹配.md @@ -72,4 +72,44 @@ public: return dp[m - 1][n - 1]; } }; +``` + + +## 递归法 + + + +### 代码实现 +``` +class Solution { +public: + bool isMatch(string s, string p) { + return isMatchR(s,p,0,0); + } + // 递归和循环混搭,果然很恶心。直接使用递归好了。 + bool isMatchR(string &s,string &p,int i,int j){ + //递归终止的条件 + if(i>=s.size() && j>=p.size()){ + return true; + } + // cout<