美团面试第二题:求解路径的最大利益

268 阅读2分钟

1. 题目描述

小团在一个n*m的网格地图上探索。网格地图上第i行第j列的格子用坐标(ij)简记。初始时,小团的位置在地图的左上角,即坐标(1,1)。地图上的每一个格子上都有一定的金币,特别地,小团位于的初始位置(1,1)上的金币为0。小团在进行探索移动时,可以选择向右移动一格(即从(x,y)到达(x,y+1))或向下移动一格(即从(x,y)到达(x+1,y)))。地图上的每个格子都有一个颜色,红色或蓝色。

如果小团一次移动前后的两个格子颜色不同,那么他需要支付k个金币才能够完成放一次移动;如果移动前后的两个格子颜色相同,则不需要支付金币。小团可以在任意格子选择结束探索。

现在给你网格地图上每个格子的颜色与金币数量,假设小团初始时的金币数量为0,请你帮助小团计算出最优规划,使他能获得最多的金币,输出能获得的最多金币数量即可。

注意:要求保证小团任意时刻金币数量不小于零

2. 输入描述

第一行是三个用空格隔开的整数n、m和k,表示网格地图的行数为n,列数为m,在不同颜色的两个格子间移动需要支付k个金币。

接下来n行,每行是一个长度为m的字符串,字符串仅包含字符’R’或’B’。第i行字符串的第j个字符表示地图上第i行第j列的格子颜色,如果字符为’R’则表示格子颜色为红色,为’B’表示格子颜色为蓝色。

接下来是一个n行m列的非负整数矩阵,第i行第j列的数字表示地图上第i行第j列的格子上的金币数量。保证所有数据中数字大小都是介于[0,10]的整数。

1<=n,m<=200,1<=k<=5

1 7 2
BBRBRBR
0 3 2 4 1 1 1

例如:

0 B
3 B
2 R
4 B
1 R
1 B
1 R

3. 输出描述

一行一个整数,表示小团能获得的最多金币数量

output: 5

4. 样例解释

小团先从(1,1)移动到(1,2),获得3个金币;

再从(1,2)移动到(1,3),需要先支付2个金币,然后获得2个金币,此时持有3个金币;再从(1,3)移动到(1,4),需要先支付2个金币,然后获得4个金币,此时持有5个金币;然后结束探索,最终获得5个金币。

如果继续向右走,每一步都需要支付2个金币,但只获得1个金币,因此在(1,4)结束是最优的

5. Java 代码

public class Solution {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入三个字符");
        String[] s = sc.nextLine().split(" ");
        int n = Integer.parseInt(s[0]);
        int m = Integer.parseInt(s[1]);
        int k = Integer.parseInt(s[2]);

        // 单个输入 --- 输入硬币数字 "" 该位置颜色   例如: 0 B
        int[][] coins = new int[n][m];
        char[][] colors = new char[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                String[] row = sc.nextLine().split(" ");
                coins[i][j] = Integer.parseInt(row[0]);
                colors[i][j] = row[1].charAt(0);
            }
        }

        //1. 确定 dp 数组含义: dp[i][j]: 代表从 (0,0) 到 (i,j) 这个位置的最多金币数量
        int[][] dp = new int[n][m];
        dp[0][0] = 0;   // 初始化
        int ans = 0;    // 记录
        for(int i = 0; i < n; i++){
            for(int j = 0; j < m; j++){
                if(i>0 || j>0) dp[i][j] = -1;
                else continue;
                // 1. 上一步是否可以到达(如果为-1那么就是不可达)
                if(i > 0 && dp[i-1][j] >= 0){
                    // 2.如果有颜色转换,上一步是否可以移动到此位置也就是是否大于等于K
                    if(colors[i-1][j] == colors[i][j]) dp[i][j] = Math.max(dp[i][j], dp[i-1][j] + coins[i][j]);
                    else if(dp[i-1][j] >= k) dp[i][j] = Math.max(dp[i][j], dp[i-1][j] + coins[i][j] - k);
                }
                // dp[i][j] = -1;
                if(j > 0 && dp[i][j-1] >= 0){
                    if(colors[i][j-1] == colors[i][j]) dp[i][j] = Math.max(dp[i][j], dp[i][j-1] + coins[i][j]);
                    else if(dp[i][j-1] >= k) dp[i][j] = Math.max(dp[i][j], dp[i][j-1] + coins[i][j] - k);
                }
                ans = Math.max(ans, dp[i][j]);
            }
        }
        System.out.println(ans);
    }
}