前言:
这一题是我最近几天做leetcode以来,用时最久的一题,说一下我的思想误区吧。
【误区算法】
最开始的时候,拿到题目的感觉就是应该用动态规划,但是我错误的从出发点开始考虑,这样求得了每个点最多的生命值。后来发现与题目要求不符。
于是重新开始考虑,但是思维还是固化在从头开始考虑。重新考虑题目要求,发现问题可以等同于求所有路径中能力值极低点的最大值,然后将这个值取绝对值加一就是题目想要的答案。在编程时我借助了图深度遍历是思想,采用递归的方法。编程上花费了一定的难度,但是提交时在大数据集上发现了时间超过的错误。考虑到可能是时间复杂度高,于是又加上了限界的条件,但是仍然报时间复杂度的错误。
void traceSmallest(vector<vector<int> > dungeon, int r, int c, int n, int m,int & value, int & minmum, vector<int> & min)
{
value += dungeon[r][c];
if(value < minmum)
minmum = value;
if(min.size() > 0 && minmum < min[0])
return;
int vc = value;
int mv = minmum;
if(r == n - 1 && c == m - 1)
{
if(min.size() == 0 && minmum <= 0)
min.push_back(minmum);
else if(min.size() > 0 && minmum > min[0])
min[0] = minmum;
return;
}
if(r < n - 1)
traceSmallest(dungeon, r + 1, c, n, m,value, minmum, min);
if(c < m - 1)
{
value = vc;
minmum = mv;
traceSmallest(dungeon, r, c + 1,n, m,value, minmum, min);
}
return;
}
//问题为找出一条路,在这条路中,体力花费最多(负的最多)的情况,这个体力极值点最大
int calculateMinimumHP(vector<vector<int> >& dungeon)
{
int N = dungeon.size();
if(N <= 0)
return -1;
int M = dungeon[0].size();
//back trace
vector<int> min;
int minmum = 0;
int value = 0;
traceSmallest(dungeon, 0, 0, N, M,value, minmum, min);
minmum = min[0];
for(vector<int>::size_type i = 1; i < min.size(); ++i)
{
if(min[i] > minmum)
minmum = min[i];
}
return abs(minmum) + 1;
}
【正确解法】
翻看了网上大神们的普遍解法,发现还是应该用动态规划的解法进行求解,而且不需要把问题的答案进行拆解。如果要求出发点要拥有的最小体力值,可以根据到达点所需要的最小体力值来进行推导。在[i][j]所需要的最小体力值,与[i + 1][j]和[i][j + 1]的最小体力值有关,首先要保证能向右走或者能下走。
//思路:用动态规划的方法求解
int calculateMinimumHP(vector<vector<int> >& dungeon)
{
int N = dungeon.size();
if(N <= 0)
return -1;
int M = dungeon[0].size();
vector<vector<int> > kmap(N);
for(int i = 0; i < N; ++i)
{
vector<int> v(M);
kmap.push_back(v);
}
//kmap中存放了在某一点能活下来的最小生命值,最开始初始化最右下角的为max(1 - dungeon[n - 1][m - 1], 1),因为到0就会死亡
//从到达点开始往上回溯,就可以求出在出发点所要的最小生命值为多少
//若求kmap[i][j],现已知kmap[i + 1][j],kmap[i][j + 1],在某一点能活下来,则需要要么能向下走,要么能向右走
//kmap[i][j] = min(kmap[i + 1][j], kmap[i][j + 1]) - dungenon[i][j];
//如果kmap[i][j] < 0 则 kmap[i][j] = 1;
kmap[N - 1][M - 1] = max(1 - dungeon[N - 1][M - 1], 1);
for(int i = N - 2; i >= 0; --i)
kmap[i][M - 1] = max(kmap[i + 1][M - 1] - dungeon[i][M - 1], 1);
for(int j = M - 2; j >= 0; --j)
kmap[N - 1][j] = max(kmap[N - 1][j + 1] - dungeon[N - 1][j], 1);
for(int i = N - 2; i >= 0; --i)
{
for(int j = M - 2; j >= 0; --j)
kmap[i][j] = max(min(kmap[i + 1][j], kmap[i][j + 1]) - dungeon[i][j], 1);
}
return kmap[0][0];
}