【leetcode】dungeon Game

前言:
这一题是我最近几天做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] < 0kmap[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];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值