题目:
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
Subscribe to see which companies asked this question
这道题不是很难,之前有做过类似的,详情可参照我的另外一篇博客:http://blog.csdn.net/caoyan_12727/article/details/51207826
本文这里一共提供三种方法来解决这个问题:
方法1:
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
row = grid.size();
col = grid[0].size();
if (row == 1 && col == 1)return grid[0][0];
vector<int>vec(col,INT_MAX);
vector<vector<int>> tmp;
for (int i = 0; i < row; i++)tmp.push_back(vec);
search(0,0,grid[0][0],grid,tmp);
return tmp[row-1][col-1];
}
void search(int t_row,int t_col,int n_value,vector<vector<int>>&grid,vector<vector<int>>&tmp){
if (t_row + 1 < row&& n_value + grid[t_row + 1][t_col]< tmp[t_row + 1][t_col]){//可以向下移动
tmp[t_row + 1][t_col] = n_value + grid[t_row + 1][t_col];
search(t_row + 1, t_col, n_value + grid[t_row + 1][t_col], grid, tmp);
}
if (t_col + 1 < col&& n_value + grid[t_row][t_col + 1]< tmp[t_row][t_col + 1]){//可以向右移动
tmp[t_row][t_col + 1] = n_value + grid[t_row][t_col + 1];
search(t_row, t_col + 1, n_value + grid[t_row][t_col + 1], grid, tmp);
}
}
private:
int row;
int col;
};
这种方法通过递归的方法进行,算法的逻辑机构就像是一颗二叉树的遍历,因为每个节点可以延生的方向只有两个,一个是向下,一个是向右,只有遍历到
某个节点的时候它的当前值要比历史记录的最好值要小的话,那么这个点就会更新,同样,这个点儿周围的下方和右方的节点都有可能得到更小值,所以
要继续深度遍历。一旦某个点的值没有更新的话,则类似进行剪树枝操作。
方法二:利用队列进行非递归的方式
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
row = grid.size();
col = grid[0].size();
if (row == 1 && col == 1)return grid[0][0];
vector<int>vec(col,INT_MAX);
vector<vector<int>> tmp;
for (int i = 0; i < row; i++)tmp.push_back(vec);
re.push_back(make_pair(make_pair(0,0),grid[0][0]));
tmp[0][0] = grid[0][0];
search(re,grid,tmp);
return tmp[row-1][col-1];
}
void search(vector<pair<pair<int,int>,int>>&se,vector<vector<int>>&grid,vector<vector<int>>&tmp){
while (se.size() != 0){
vector<pair<pair<int,int>, int>>::iterator iter = se.begin();
int t_row = (*iter).first.first, t_col = (*iter).first.second;
int n_value = (*iter).second;
if(t_row+1 < row&& n_value + grid[t_row + 1][t_col]< tmp[t_row + 1][t_col]){//可以向下移动
tmp[t_row + 1][t_col] = n_value + grid[t_row + 1][t_col];
se.push_back(make_pair(make_pair(t_row + 1, t_col), tmp[t_row + 1][t_col]));
}
if(t_col + 1 < col&& n_value + grid[t_row][t_col + 1]< tmp[t_row][t_col + 1]){//可以向右移动
tmp[t_row][t_col + 1] = n_value + grid[t_row][t_col + 1];
se.push_back(make_pair(make_pair(t_row, t_col+1), tmp[t_row][t_col+1]));
}
iter = se.begin();
se.erase(iter);
}
}
private:
int row;
int col;
vector<pair<pair<int, int>, int>>re;
};
但是很遗憾,最后一个测试用例超时:
但是可以确定这个方法的思想是没错的!!!!!!
方法三:当然是最简便的方法
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int row = grid.size();
int col = grid[0].size();
if (row == 1 && col == 1)return grid[0][0];
vector<int>vec(col, INT_MAX);
vector<vector<int>> tmp;
for (int i = 0; i < row; i++)tmp.push_back(vec);
tmp[0][0] = grid[0][0];
for (int i = 0; i < row; i++){
for (int j = 0; j < col;j++){
tmp[i][j]=min(tmp[i][j],min(i>0?(tmp[i-1][j]+grid[i][j]):INT_MAX,j>0?(tmp[i][j-1]+grid[i][j]):INT_MAX));
}
}
return tmp[row - 1][col - 1];
}
};
这个方法用时仅仅13ms。。。。。。。
既然写到这里,那么博客http://blog.csdn.net/caoyan_12727/article/details/51207826中的题目能不能也用方法三的思路呢???????
答案是不能的!!!!。因为这个题目的要求是在每一个节点上,都有三个方向可以移动,个题没有限制管道从那个第一列的哪个位置开始挖,所以我们在实现的时候要第一列的每个点都要尝试一遍且每次尝试的开始状态是一样的。当然这个有一点难以理解,那就是和我们上一个题比较,路径的延生方向只能是向下或向右,所以当更新tmp[i][j]的时候,它的上一个和左边的数组上的数已经更新。但是在这个挖管道的题目中,当更新到tmp[i][j]如果管道是由下方向上挖的时候,即我们的数组的索引为i从[1,N],j的索引也是从[1,N],当需要更新tmp[i][j]的时候tmp[i+1][j]还未更新,所以是不能的!!!!