剑指 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 ...
随机推荐
- Java编译异常捕捉与上报笔记
异常处理机制的作用:增强程序的健壮性 处理编译异常方式一: 在方法声明位置上使用throws关键字抛出,谁调用该方法,就交给谁处理 注意:为Exception的是需要处理的,否则编译器会报错,可以一直 ...
- 学习Java Day19
今天学习了包(package)将类组织在一个集合里,知道了如何导入类.
- JZOJ 3737. 【NOI2014模拟7.11】挖宝藏
\(\text{Solution}\) 当 \(h=1\) 时显然是斯坦纳树板子,最方案必然是树形的 \(h > 1\) 时,考虑在每一层新建一个状态表示上一层宝藏全部挖完到这层某个点的答案 同 ...
- Python常见面试题006 类方法、类实例方法、静态方法有何区别?
006. Python中类方法.类实例方法.静态方法有何区别? 全部放一个里面篇幅过大了,就拆分成1个个发布 示例代码 class Human: def __init__(self, name): s ...
- OpenLayers之图形交互绘制
一.实验内容 回顾鼠标事件及事件对象,练习鼠标坐标获取: 点.线.面.圆等常规图形的交互绘制: 点.线.面.圆等常规图形的样式编辑: 点.线.面.圆等常规图形编辑: 二.实验步骤 2.1 鼠标坐标获取 ...
- Postgresql动态共享内存类型
一.简介 linux为多个进程通信提供了不同的IPC机制,如:System V , POSIX 和 MMAP,所以Postgresql共享内存管理也支持以上类型. 在Postgresql中可以使用dy ...
- 552. 学生出勤记录 II (Hard)
问题描述 552. 学生出勤记录 II (Hard) 可以用字符串表示一个学生的出勤记录,其中的每个字符用来标记当天的出勤情况(缺勤.迟到.到场).记录中只含下面三种字符: 'A':Absent,缺勤 ...
- SVN的安装和使用手册2
转载:http://www.cnblogs.com/armyfai/p/3985660.html SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版本,这就需 ...
- 初识redis之性能测试
最近接触一项新技术的方法都是通过测试来入门的.对测试这件事情有了新的认识,觉得是类似做实验的一种方式.尤其对于后端,测试的性能指标是技术选型的重要参考. 好了,如果你想做一下redis的性能测试,不要 ...
- java.io.StreamCorruptedException: invalid stream header: 00013174
java.io.StreamCorruptedException: invalid stream header: 00013174 at java.io.ObjectInputStream.readS ...