关键词:动态规划,重叠子问题,原地修改,空间压缩,vector函数,std::
题解
解法1(自顶向下):
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
vector<vector<int>> path(triangle);//开辟同形状的路径三角形,值为当前位置的最小路径值
int row=triangle.size();
path[0][0]=triangle[0][0];
for(int i=1;i<row;i++){
for(int j=0;j<=i;j++){
if(j==0)
path[i][j] = path[i-1][j] + triangle[i][j];
if(j>0 && j<i)
path[i][j] = min(path[i-1][j],
path[i-1][j-1])+triangle[i][j];
if(j==i)
path[i][j] = path[i-1][j-1]+triangle[i][j];
}
}
return *std::min_element(path[row-1].begin(),path[row-1].end());
}
};
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
//改进版,没有必要在开辟一个二维数组,直接修改triangle(原地修改)*
int row=triangle.size();
for(int i=1;i<row;i++){
triangle[i][0]+=triangle[i-1][0];
triangle[i][i]+=triangle[i-1][i-1];
for(int j=1;j<i;j++)
triangle[i][j] = min(triangle[i-1][j], triangle[i-1][j-1])+triangle[i][j];
}
return *std::min_element(triangle[row-1].begin(),triangle[row-1].end());
}
};
解法2(自底向上):
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
//自底向上的解法,避免了临界值的讨论
//采用空间压缩(减少对二维数组的访问,变为对一维数组的访问)
int row=triangle.size();
vector<int> res=vector<int>(triangle[row-1]);//一维数组
for(int i=row-2;i>=0;i--)
for(int j=0;j<=i;j++)
res[j]=min(res[j],res[j+1])+triangle[i][j];
return res[0];
}
};
解法3(暴力破解):
待补
解法4(递归):
待补
注:
1.暴力破解的问题是重复的路径计算了多次,但无需开辟空间存储路径值。
2.动态规划法避免了重复计算,并且存储值的方法有:
a.额外开辟空间(记忆化搜索)
b.原地修改(即在提给数组上进行修改,本质是覆盖)
c.空间压缩(粗浅的理解:二维数组通过覆盖的方法化为一维数组,实现空间的节约及访问的便捷。)
3.动态规划关键:
拆分问题,保存子问题答案,状态转移方程
问题形式:具有重叠子问题和最优子结构
4.自底向上和自顶向下 时间性能差不多,不同:a.代码结构(简洁性),b.可能避免掉约束条件
5.分治法:子问题相互独立。 动态规划:子问题有关联
6.其他:
最优化原理:最优化策略的子策略总是最优的
无后效性:每个状态都是对过去历史的一个完整总结
空间换时间 ->避免重复计算产生的冗余 ->将指数级时间转为多项式时间 (参考:百度百科-动态规划)
7.题解一中的两种解法,关于边界情况的处理,注意累加(也是一种覆盖)的使用,可使得代码更简洁。
语法
1.vector:
a.vector< int > var1;
var1=vector< int >(length,value); 先定义,再赋值。
vector< int > var1(length,value);赋值定义同时完成
b.vector< int > var2 (var1). 和var1同值同结构
c.vector< int > var3( length ).指定长度,值默认
d.vector< vector< int > > var4(5).指定5行(vector甚至允许每行的长度不一样,即可以构造非矩阵形式的二维数组) var4 等价于var4(0)的写法,即0行。
另:<vector < int >‘空格 ’> 否则会和 >>输入符冲突
vector<vector < int > > var=vector<vector < int >>(行数,vector< int >(列数,值))
e.var4.push_back(var3) 末尾添加一行,var4此时6行
f.var4[0].size(); 第一行的长度
g.与普通数组的比较:
1能够一次性批量赋同一个值,而对于int dp[5][5]={1};只是给dp[0][0]赋值为1,其余值默认为0;
2.int dp[N][M]这种写法是错误的,只能放常量,vector则支持变量。
2.*std::max/min_element( arr.begin() , arr.end())
3.关于std::
a.名字空间std定义了C++标准库中的函数和对象
b.被std限定后的标识符作用范围就变成了全局域
#include< iostream >
std::cout<<value;
等价于
#include< iostream >
using namespace std;//将标准库中的全部暴露在全局域中
cout<<value;
等价于
#include< iostream.h > (非标准库)
cout<<value;
c.#include “iostream"与#include< iostream >的区别:前者先在当前目录找iostream文件,找不到再去系统头文件路径找,后者反之。因此,做为一个良好的习惯,在包含系统头文件时尽量用<>,而在包含自己的工程中的头文件时用”"。
e.参考链接:
https://www.cnblogs.com/mhq-martin/p/8604842.html
https://zhidao.baidu.com/question/431965787776866044.html
其他
1.leetcode 同样的代码每次执行结果也会不同。
2.12ms 8ms 4ms 没有区别,可能下次执行时间就是一样的值了,除非出现100ms以上的差别,否则视为等同。