LeetCode 174 Dungeon Game

题目给的条件
1. 二维网格m*n 行列 //m=1 n=1
2. P右下角
3. k左上角
4. k可以向右和向下移动
5. 遇怪掉血
6. 遇药加血
7. 血量<=0骑士会死

要求:求出救到公主的最小血量

  • 骑士的健康没有上限
  • 每个房子有怪物或者血瓶

第一个想法:

深度优先搜索遍历,从p开始假设救到公主只剩1滴血,
开始搜索,遇到怪加血,遇到血瓶把血压下去,最后到达k的时候更新最小血量
当遇到草鸡大的血瓶可能会把自己血量压空甚至压成负数,所以判断一下

//java 
//TLE 美滋滋ლ(′◉❥◉`ლ)
class Solution {
    public int calculateMinimumHP(int[][] dungeon) {
        int m = dungeon.length;
        int n = dungeon[0].length;
        if(m==1&&n==1) {
            if(dungeon[0][0]>0)
                return 1;
            else
                return -dungeon[0][0]+1;
        }
        if(m==1) {//只有一行
            int ans = 1;//假设救到公主的时候就1滴血了
            for(int i=n-1;i>=0;i--) {//从P到K
                if(ans-dungeon[0][i]>0) {
                    ans -= dungeon[0][i];//能捡到药包血量可以压低一点
                }else {//不能压到死,死了是捡不到血包的
                    ans = 1;
                }
            }
            return ans;
        }
        if(n==1) {//只有一列
            int ans = 1;//假设救到公主的时候就1滴血了
            for(int i=m-1;i>=0;i--) {//从P到K
                if(ans-dungeon[i][0]>0) {
                    ans -= dungeon[i][0];//能捡到药包血量可以压低一点
                }else {//不能压到死,死了是捡不到血包的
                    ans = 1;
                }
            }
            return ans;
        }
        //位置,遍历过程记录中间血量,最小血量
        int [] status = new int[] {Integer.MAX_VALUE};
        dfs(dungeon,m-1,n-1,1,status);
//      System.out.println("status>>>>>>>>>>>>>>>>>>>>>>>");
//      System.out.println(status[0]);
        return status[0];
    }

    private void dfs(int[][] dungeon,int x,int y,int now, int[] status) {
        if(x<0||y<0||
            x>=dungeon.length||
            y>=dungeon[0].length)//出界了
            return ;
        if(x==0&&y==0) {
            //K这个格子不要忘记
            if(now-dungeon[0][0]<0) {
                now = 1;
            }else {
                now -= dungeon[0][0];
            }
            if(status[0]>now) { //更新血量
                status[0] = now;
            }
        }else {
            for(int i=0;i<2;i++) {//0表示左移,1表示上移
                int what = dungeon[x][y];
                int temp = now;//保存未改变的血量
                if(what<0) {
                    now -= what;
                }else {
                    if(now-what>0) {
                        now -= what;//能捡到药包血量可以压低一点
                    }else {//不能压到死,死了是捡不到血包的
                        now = 1;
                    }
                }
                if(i==0) 
                    dfs(dungeon,x,y-1,now,status);
                else 
                    dfs(dungeon,x-1,y,now,status);
                now=temp;
            }
        }
    }
}

又想了一个方法递推:
规则说了K只能向右和向下,所以公主也只能向左或向上,所以后一列和底行是直接能求出最小值,然后从左下角开始推,比较向左和向上走哪个更优,然后取最小值这里写图片描述

//美滋滋ლ(′◉❥◉`ლ)
class Solution {
    public int calculateMinimumHP(int[][] dungeon) {


        int m = dungeon.length;
        int n = dungeon[0].length;

        if(m==1&&n==1) {
            if(dungeon[0][0]>0)
                return 1;
            else
                return -dungeon[0][0]+1;
        }
        if(m==1) {//只有一行
            int ans = 1;//假设救到公主的时候就1滴血了
            for(int i=n-1;i>=0;i--) {//从P到K
                if(ans-dungeon[0][i]>0) {
                    ans -= dungeon[0][i];//能捡到药包血量可以压低一点
                }else {//不能压到死,死了是捡不到血包的
                    ans = 1;
                }
            }
            return ans;
        }
        if(n==1) {//只有一列
            int ans = 1;//假设救到公主的时候就1滴血了
            for(int i=m-1;i>=0;i--) {//从P到K
                if(ans-dungeon[i][0]>0) {
                    ans -= dungeon[i][0];//能捡到药包血量可以压低一点
                }else {//不能压到死,死了是捡不到血包的
                    ans = 1;
                }
            }
            return ans;
        }




        //其实就用到两列数据
        int[] bottom = new int[n];//底行
        bottom[n-1] = 1;
        if(bottom[n-1]-dungeon[m-1][n-1]>0) {
            bottom[n-1] -= dungeon[m-1][n-1];
        }else {
            bottom[n-1] = 1;
        }

        for(int i=bottom.length-2;i>=0;i--) {//底行
            if(bottom[i+1]-dungeon[m-1][i]>0) {
                bottom[i] = bottom[i+1]-dungeon[m-1][i];
            }else {
                bottom[i] = 1;
            }
        }
        //最左侧一列
        int[] col = new int[m-1];
        if(bottom[n-1]-dungeon[m-2][n-1]>0) {
            col[col.length-1] = bottom[n-1]-dungeon[m-2][n-1];
        }else {
            col[col.length-1] = 1;
        } 
        for(int i=col.length-2;i>=0;i--) {
            if(col[i+1]-dungeon[i][n-1]>0) {
                col[i] = col[i+1]-dungeon[i][n-1];
            }else {
                col[i] = 1;
            }
        }


//      开始推:
        for(int i=n-2;i>=0;i--) {//列
            for(int j=m-2;j>=0;j--) {//行
                //向左
                int left = col[j];
                if(left-dungeon[j][i]>0) {
                    left = left-dungeon[j][i];
                }else {
                    left = 1;
                }
                //向上
                int top = bottom[i];
                if(top-dungeon[j][i]>0) {
                    top = top-dungeon[j][i];
                }else {
                    top = 1;
                }
                col[j] = Math.min(left,top);
                bottom[i] = col[j];
            }
        }
        return col[0];
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值