剑指 Offer II 动态规划
088. 爬楼梯的最少成本
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n=cost.size();
vector<int>f(n+1);
f[0]=cost[0],f[1]=cost[1];
//走到第i级台阶 最小代价
//状态转移 从前一个或 前两个走上来
cost.push_back(0);
for(int i=2;i<=n;i++)
{
f[i]=cost[i]+min(f[i-1],f[i-2]);
}
return f[n];
}
};
089. 房屋偷盗
class Solution {
public:
/*
f[i][0]
f[i][1]
偷还是不偷
*/
int rob(vector<int>& nums) {
int n=nums.size();
vector<vector<int>>f(n+1,vector<int>(2));
f[1][1]=nums[0];
for(int i=2;i<=n;i++)
{
f[i][0]=max(f[i-1][0],f[i-1][1]);//没偷前一个咋样都无所谓
f[i][1]=max(f[i-1][0],f[i-2][1]+nums[i-1]);
}
return max(f[n][0],f[n][1]);
}
};
090. 环形房屋偷盗
就两种情况 选1还是不选1
class Solution {
public:
/*
f[i][0]
f[i][1]
偷还是不偷
*/
int rob(vector<int>& nums) {
int n=nums.size();
if(n==1)return nums[0];
vector<vector<int>>f(n+1,vector<int>(2));
//不选1 不初始化f[1][1]
for(int i=2;i<=n;i++)
{
f[i][0]=max(f[i-1][0],f[i-1][1]);//没偷前一个咋样都无所谓
f[i][1]=f[i-1][0]+nums[i-1];
}
int ans= max(f[n][0],f[n][1]);
f[1][1]=nums[0];
for(int i=2;i<=n;i++)
{
f[i][0]=max(f[i-1][0],f[i-1][1]);//没偷前一个咋样都无所谓
f[i][1]=f[i-1][0]+nums[i-1];
}
ans=max(ans,f[n][0]);//选了1就别选n
return ans;
}
};
091. 粉刷房子
class Solution {
public:
/*
f[i][j]
j是颜色 从另外两个转移
*/
int minCost(vector<vector<int>>& cost) {
int n=cost.size();
vector<vector<int>>f(n,vector<int>(3));
f[0][0]=cost[0][0],f[0][1]=cost[0][1],f[0][2]=cost[0][2];
for(int i=1;i<n;i++)
{
f[i][0]=cost[i][0]+min(f[i-1][1],f[i-1][2]);
f[i][1]=cost[i][1]+min(f[i-1][0],f[i-1][2]);
f[i][2]=cost[i][2]+min(f[i-1][1],f[i-1][0]);
}
return min(min(f[n-1][0],f[n-1][1]),f[n-1][2]);
}
};
092. 翻转字符
前缀和
class Solution {
public:
/*
f[i] 1的前缀和
2e4
*/
int minFlipsMonoIncr(string s) {
int n=s.size();
vector<int>f(n+1);
for(int i=1;i<=n;i++)
{
f[i]=f[i-1]+ (s[i-1]=='1');
// cout<<f[i];
}
//puts("");
int ans=min(f[n],n-f[n]);//全0 全1
for(int i=1;i<=n;i++)
{
//把 i及以前变为0 以后变为1的代价 01111 00001
int res=f[i]-f[1-1];//1~i的1变为0
res+=(n-i)-(f[n]-f[i+1-1]);//i+1~n中0的个数;
// cout<<res<<endl;
ans=min(ans,res);
}
return ans;
}
};
093. 最长斐波那契数列
class Solution {
public:
/*
状态表示
f[i][j] 以arr[i]为结尾 arr[j]为arr[i]前一个元素组成的数列 的 最大值
状态转移
从f[j][k]
*/
int lenLongestFibSubseq(vector<int>& arr) {
int n=arr.size();
vector<vector<int> >f(n+1,vector<int>(n+1));
int res=0;
unordered_map<int,int>pos;
for(int i=0;i<n;i++)
{
pos[arr[i]]=i;//记录地址
for(int j=0;j<i;j++)
{
f[i][j]=2;
//找 j前面有没有x=arr[i]-arr[j]
int x=arr[i]-arr[j];
if(x<arr[j]&&pos.count(x)){
int k=pos[x];
f[i][j]=max(f[i][j],f[j][k]+1);
}
res=max(res,f[i][j]);
}
}
return res<3?0:res;
}
};
洞94 ?!最少回文分割 hard
class Solution {
public:
/*
f[i]状态表示 从1~i的方案 属性:最小值
阶段划分
可以分为1~i 2~i ... i~i
假设最后一步k~i转移
(1... k-1) (k...i)
转移方程
f[i]=min(f[i],f[k-1]+1);
快速枚举i 到j是不是回文串 g[i][j]
1.s[i]==s[j]
2. j-i== 0、1 || g[i+1][j-1]
*/
int minCut(string s) {
int n=s.size();
s=' '+s;//单引号 方便 下标从1开始
vector<int>f(n+1,1e9);
vector<vector<bool>>g(n+1,vector<bool>(n+1));
//初始化 st 第一次dp
// i到j j先循环 保证g[i+1][j-1]先创建出来了
for(int j=1;j<=n;j++)
for(int i=1;i<=n;i++){
if(s[i]==s[j]){
if(j-i<2||g[i+1][j-1])g[i][j]=true;
}
}
f[0]=0;//0种方案
for(int i=1;i<=n;i++)
for(int j=1;j<=i;j++){//j==i 1~(i-1) i
if(g[j][i]){//j前 i后
f[i]=min(f[i],f[j-1]+1);
}
}
return f[n]-1;
}
};
095. 最长公共子序列
模板题 背过 不解释
class Solution {
public:
/*
状态表示
f[i][j] a 1~i
b 1~j
属性 max
阶段划分
两个字符串的位置(已处理的前缀长度)
*/
int longestCommonSubsequence(string s1, string s2) {
int n=s1.size(),m=s2.size();
s1=' '+s1;s2=' '+s2;
vector<vector<int>>f(n+1,vector<int>(m+1,0));
f[n][0]=f[0][m]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=max(f[i-1][j],f[i][j-1]);
if(s1[i]==s2[j])f[i][j]=max(f[i-1][j-1]+1,f[i][j]);
}
}
return f[n][m];
}
};
老美从来没看过的洞96?!字符串交织
class Solution {
public:
/*
f[i][j]
a 1~i
b 1~j 能组成c 1~i+j
属性bool
阶段划分
i-1 j
i j-1 能组成1~i+j-1
转移方程
if(a[i]==c[i+j])f[i][j]|=f[i-1][j]
if(b[j]==c[i+j])f[i][j]|=f[i][j-1]
f[0][0]=true;
*/
bool isInterleave(string a, string b, string c) {
int n=a.size(),m=b.size();
if(n+m!=c.size())return false;
a=' '+a;b=' '+b;c=' '+c;
vector<vector<bool>>f(n+1,vector<bool>(m+1));
f[0][0]=true;
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
if(i&&a[i]==c[i+j])f[i][j]=f[i][j]||f[i-1][j];
if(j&&b[j]==c[i+j])f[i][j]=f[i][j]||f[i][j-1];
// cout<<f[i][j];
}
}
return f[n][m];
}
};
097. 子序列的数目 (多想想,不太熟)
// typedef long long LL;
class Solution {
public:
/*
f[i][j]状态表示s 1~i 组成 t 1~j的方案数
属性cnt
状态划分
if(s[i]!=t[j]) i不能与j匹配 所以f[i][j]=f[i-1][j]
i既可以与j匹配 也可以不与j匹配f[i][j]=f[i-1][j-1]+f[i-1][j]
f[1~n][0]=1;
*/
int numDistinct(string s, string t) {
int n=s.size(),m=t.size();
s=' '+s;t=' '+t;
vector<vector<unsigned long long>>f(n+1,vector<unsigned long long >(m+1,0));
for(int i=0;i<=n;i++)f[i][0]=1;//因为s可以从不同下标匹配
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
f[i][j]=f[i-1][j];
if(s[i]==t[j])
f[i][j]+=f[i-1][j-1];
}
}
return f[n][m];
}
};
098. 路径的数目
class Solution {
public:
int uniquePaths(int n, int m) {
vector<vector<int>>f(n+1,vector<int>(m+1));
f[1][1]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(i>1)f[i][j]+=f[i-1][j];
if(j>1)f[i][j]+=f[i][j-1];
}
}
return f[n][m];
}
};
099. 最小路径之和
class Solution {
public:
/*
到i,j这个点 最小代价
f[i][j]
i>2f[i-1][j]
f[i][j-1]
*/
int minPathSum(vector<vector<int>>& grid) {
int n=grid.size(),m=grid[0].size();
vector<vector<int>>f(n+1,vector<int>(m+1,1e9));
f[1][1]=grid[0][0];
//要初始化正无穷
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(j>1)f[i][j]=min(f[i][j],f[i][j-1]);
if(i>1)f[i][j]=min(f[i][j],+f[i-1][j]);
if(i>1||j>1)f[i][j]+=grid[i-1][j-1];
}
}
return f[n][m];
}
};
100. 三角形中最小路径之和
class Solution {
public:
/*
1
12
123
1234只能从上方或者斜上方转移
*/
int minimumTotal(vector<vector<int>>& triangle) {
int n=triangle.size(),m=triangle[n-1].size();
vector<vector<int>>f(n+1,vector<int>(m+1,1e9));
//初始化正无穷
f[1][1]=triangle[0][0];
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
if(i>1||j>1)f[i][j]=f[i-1][j];//除了1,1都能从上方转移
//从斜上方转移的条件是j>=2
if(j>1)f[i][j]=min(f[i][j],f[i-1][j-1]);
if(i>1||j>1)f[i][j]+=triangle[i-1][j-1];
}
}
int res=2e9;
for(int i=1;i<=m;i++)res=min(res,f[n][i]);
return res;
}
};
101. 分割等和子集
class Solution {
public:
/*
01背包
f[i][j] 前i个选 能不能拼成j这个数
属性 bool
状态划分
选与不选
f[i-1][j]
f[i-1][j-x] j>=x x为nums元素
*/
bool canPartition(vector<int>& nums) {
int m=0;
for(auto x:nums)m+=x;
if(m%2)return false;
int n=nums.size();
vector<vector<int>>f(n+1,vector<int>(m+1));
m/=2;
//cout<<m<<endl;
f[0][0]=1;
for(int i=1;i<=n;i++){
// f[i][0]=1;
for(int j=0;j<=m;j++){
f[i][j]=f[i-1][j];//不选i
int x=nums[i-1];
if(j>=x)f[i][j]|=f[i-1][j-x];//选i
//cout<<i<<"."<<j<<" "<<f[i][j]<<endl;
}
}
return f[n][m];
}
bool canPartition(vector<int>& nums) {
int m=0;
for(auto x:nums)m+=x;
if(m%2)return false;
m/=2;
vector<int>f(m+1);
f[0]=1;
for(int x:nums){
for(int j=m;j>=x;j--)f[j]|=f[j-x];
}
return f[m];
}
};
102. 加减的目标值
class Solution {
public:
/*
状态表示
f[i][j] 前i个全选 总和为j的方案数
为什么全选?
不全选没意义啊 你知道前i个选其中几个 总和为j有什么用?题目用不了
属性cnt
状态划分
选前i-1个 总和为j-x j+x的方案数
f[i-1][j-x]
f[i-1][j+x]
注意0 <= sum(nums[i]) <= 1000
审题很重要 我本以为要offset 2e5
-1000~1000 -> 0~2000
*/
int findTargetSumWays(vector<int>& nums, int target) {
if(target<-1000||target>1000)return 0;
int offset=1000,n=nums.size();
vector<vector<int>>f(n+1,vector<int>(2001));
f[0][offset]=1;
for(int i=1;i<=n;i++){
int x=nums[i-1];
for(int j=-1000;j<=1000;j++){
if(j-x>=-1000)f[i][j+offset]+=f[i-1][j-x+offset];
if(j+x<=1000)f[i][j+offset]+=f[i-1][j+x+offset];
}
}
return f[n][target+offset];
}
};
103. 最少的硬币数目
class Solution {
public:
/*
表示
f[j] 前i个货币选 总金额为j最少需要多少个硬币
属性min
划分
f[i-1][j]
f[i-1][j-x]+1
完全背包问题 正向枚举
0块钱只需要0个硬币 f[0]=0
*/
int coinChange(vector<int>& coins, int m) {
vector<int>f(m+1,1e9);
f[0]=0;
for(int x:coins){
for(int j=x;j<=m;j++){
f[j]=min(f[j],f[j-x]+1);
}
}
return f[m]==1e9?-1:f[m];
}
};
104. 排列的数目 (没想明白)
class Solution {
public:
/*
这题不是完全背包会将 所有排列方案当成一种
为什么先枚举j没想明白
*/
int combinationSum4(vector<int>& nums, int m) {
vector<long long >f(m+1,0);
f[0]=1;
for(int j=1;j<=m;j++)
for(int x:nums){
if(j>=x)f[j]=(f[j]+f[j-x])%INT_MAX;
}
return f[m];
}
};
剑指 Offer II 动态规划的更多相关文章
- 刷题-力扣-剑指 Offer II 055. 二叉搜索树迭代器
剑指 Offer II 055. 二叉搜索树迭代器 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/kTOapQ 著作权归领扣网络所有 ...
- 【剑指 Offer II 001. 整数除法】同leedcode 29.两数相除
剑指 Offer II 001. 整数除法 解题思路 在计算的时候将负数转化为正数,对于32位整数而言,最小的正数是-2^31, 将其转化为正数是2^31,导致溢出.因此将正数转化为负数不会导致溢出. ...
- 【力扣】剑指 Offer II 092. 翻转字符
题目 解题思路 一个很暴力的想法,在满足单调递增的前提下,使每一位分别取 1 或 0,去看看哪个结果小. 递归函数定义int dp(StringBuilder sb, int ind, int pre ...
- 剑指Offer——II平衡二叉树
class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None # 这道题使用中序遍历加上 ...
- 剑指 Offer 14- II. 剪绳子 II + 贪心 + 数论 + 快速幂
剑指 Offer 14- II. 剪绳子 II 题目链接 因为有取模的操作,动态规划中max不能用了,我们观察:正整数从1开始,但是1不能拆分成两个正整数之和,所以不能当输入. 2只能拆成 1+1,所 ...
- 剑指Offer——动态规划算法
剑指Offer--动态规划算法 什么是动态规划? 和分治法一样,动态规划(dynamic programming)是通过组合子问题而解决整个问题的解. 分治法是将问题划分成一些独立的子问题,递归地求解 ...
- 学会从后往前遍历,例 [LeetCode] Pascal's Triangle II,剑指Offer 题4
当我们需要改变数组的值时,如果从前往后遍历,有时会带来很多麻烦,比如需要插入值,导致数组平移,或者新的值覆盖了旧有的值,但旧有的值依然需要被使用.这种情况下,有时仅仅改变一下数组的遍历方向,就会避免这 ...
- [简单-剑指 Offer 53 - II. 0~n-1中缺失的数字]
[简单-剑指 Offer 53 - II. 0-n-1中缺失的数字] 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0-n-1之内.在范围0-n-1内的n个数字中有且只有一 ...
- 剑指 Offer 68 - II. 二叉树的最近公共祖先 + 最近公共祖先(LCA)
剑指 Offer 68 - II. 二叉树的最近公共祖先 Offer_68_2 题目详情 题解分析 java代码 package com.walegarrett.offer; /** * @Autho ...
- 剑指 Offer 63. 股票的最大利润 + 动态规划
剑指 Offer 63. 股票的最大利润 Offer_63 题目描述 方法一:暴力法 package com.walegarrett.offer; /** * @Author WaleGarrett ...
随机推荐
- HTML5 + canvas 汽车赛道,飙车游戏(附源码)
好玩的游戏千千万 有趣的万里挑一 最近逛 gitHub 时 发现的一个好玩的赛车游戏 ,试玩之后感觉还是挺不错的 在这分享给那些喜欢玩赛车的车友们 效果图如下 源码分析 TweenMax.min.js ...
- java_web案例文件下载案例
目的:完成javaweb的文件下载 <!--如果想要一个a标签点击后不论文件类型,都需要弹出下载,保存框:--><!--我们就需要创建一个servlet,让这个a标签指向servle ...
- 树莓派UBUNTU MATE 自动登录用户
1.sudo vim /usr/share/lightdm/lightdm.conf.d/60-lightdm-gtk-greeter.conf 2.添加autologin-user=youruser ...
- 转载:屎人-->诗人系列--码农之歌
转贴经常关注的一个博主的文,感觉还挺有趣: https://goofegg.github.io/content.html?id=141 ************************** 这个系列第 ...
- C语言-补漏 -内存管理
8. 全局就是简简单单编写的 静态函数--只能在当前文件内使用的函数
- 记一次完整的PHP代码审计——yccms v3.4审计
一.环境搭建与使用工具 (一)环境搭建 打开源码查看安装要求 PHP 5.4+,Mysql 5.0.*,直接使用phpstudy配置即可 查看源码目录结构,发现是mvc模式的,那么我们重点关注的就是c ...
- TNF拮抗剂的结构、功能与结核感染_Wallis2008
中信国健临床通讯 2009年第2期 TNF拮抗剂的结构.功能与结核感染 Robert S. Wallis. THE LANCET Infectious Diseases. 2008; 8:601–61 ...
- 病程极短(≤16周)的495例未分化关节炎患者随访2年的结局[EULAR2015_SAT0055]
病程极短(≤16周)的495例未分化关节炎患者随访2年的结局 SAT0055 TWO-YEAR OUTCOME IN 495 PATIENTS WITH UNDIFFERENTIATED ARTH ...
- 07#Web 实战:仿 GitHub 个人主页项目拖拽排序
实现效果图 GitHub 和 Gitee 个人主页中可以对自己的项目进行拖拽排序,于是我就想自己实现一个.本随笔只是记录一下大概的实现思路,如果感兴趣的小伙伴可以通过代码和本随笔的说明去理解实现过程. ...
- h5项目自适应字体和宽高。用rem
已知: 1.浏览器默认的字号是16px,html{font-size: 87.5%;}(16*0.875 = 14px). 2.css中的单位换算:rem 与 px 的换算为 px = rem * 设 ...