给定一个矩阵matrix,先从左上角开始,每一步只能往右或者往下走,走到右下角。然后从右下角出发,每一步只能往上或者往左走,再回到左上角。任何一个位置的数字,只能获得一遍。返回最大路径和。

问题描述:

        给定一个矩阵matrix,先从左上角开始,每一步只能往右或者往下走,走到右下角。然后从右下角出发,每一步只能往上或者往左走,再回到左上角。任何一个位置的数字,只能获得一遍。返回最大路径和。

思路:

思路一:暴力递归方法。此题可以转化为两个人A和B同时从左上角位置开始走,并且每一步只能往右或者往下走,走到右下角,A和B一定迈出相同的步数同步走。

        我们从转化后的问题可以得知:

  1. A和B会同时来到右下角的位置。
  2. A所在行号用Ar表示,列号用Ac表示;B所在行号用Br表示,列号用Bc表示;四个变量之前存在一定的关系:Ar + Ac = Br + Bc,所以我门在递归函数中可以省去一个变量Bc (Bc = Ar + Ac - Br)。
  3. 不同时刻,A所在数组的第i行和第j列,B在第i行时不在第j列上,则B之后不会经过第i行和第j列这个位置。
  4. 某一时刻,A和B都是所在数组的第i行,那么A和B一定在同一个格子里面。

        递归函数表示的含义是:两个人同时到达右下角,返回两个人路径的最大累加和。

思路二:使用记忆化搜索的方法,建立缓存数组。

代码:

思路一代码

    public static int comeGoMaxPathSum(int[][] matrix) {
        return process(matrix, 0, 0, 0);
    }

    //matrix中没有负数
    //A和B,一定迈出相同的步数,同步走
    //两个人会共同到达右下角,返回两个人路径的最大累加和
    public static int process(int[][] matrix, int Ar, int Ac, int Br) {
        int N = matrix.length;
        int M = matrix[0].length;
        if (Ar == N - 1 && Ac == M - 1) {
            return matrix[Ar][Ac];
        }

        //没有到达右下角
        // A 下    B 右
        // A 下    B 下
        // A 右    B 右
        // A 右    B 下
        int Bc = Ar + Ac - Br;
        int ADownBRight = 0;
        if (Ar + 1 < N && Bc + 1 < M) {
            ADownBRight = process(matrix, Ar + 1, Ac, Br);
        }
        int ADownBDown = 0;
        if (Ar + 1 < N && Br + 1 < N) {
            ADownBDown = process(matrix, Ar + 1, Ac, Br + 1);
        }
        int ARightBRight = 0;
        if (Ac + 1 < M && Bc + 1 < M) {
            ARightBRight = process(matrix, Ar, Ac + 1, Br);
        }
        int ARightBDown = 0;
        if (Ac + 1 < M && Br + 1 < N) {
            ARightBDown = process(matrix, Ar, Ac + 1, Br + 1);
        }
        int nextBest = Math.max(Math.max(ADownBRight, ADownBDown), Math.max(ARightBRight, ARightBDown));

        int curNum = Ar == Br ? matrix[Ar][Ac] : matrix[Ar][Ac] + matrix[Br][Bc];
        int res = curNum + nextBest;
        return res;
    }

思路二代码

    public static int dp(int[][] matrix) {
        int M = matrix.length;
        int N = matrix[0].length;

        int[][][] dp = new int[M][N][M];

        //最后一个位置
        dp[M - 1][N - 1][M - 1] = matrix[M - 1][N - 1];
        //普通位置
        for (int i = 0; i < M; i++) {
            for (int j = 0; j < N; j++) {
                for (int k = 0; k < M; k++) {
                    dp[i][j][k] = Integer.MIN_VALUE;
                }
            }
        }
        return process2(matrix, 0, 0, 0, dp);
    }

    public static int process2(int[][] matrix, int Ar, int Ac, int Br, int[][][] dp) {
        if (dp[Ar][Ac][Br] != Integer.MIN_VALUE) {
            return dp[Ar][Ac][Br];
        }
        int N = matrix.length;
        int M = matrix[0].length;
        if (Ar == N - 1 && Ac == M - 1) {
            //A B来到右下角
            return matrix[N - 1][M - 1];
        }
        //没有到达右下角
        // A 下    B 右
        // A 下    B 下
        // A 右    B 右
        // A 右    B 下
        int Bc = Ar + Ac - Br;
        int ADownBRight = 0;
        if (Ar + 1 < N && Bc + 1 < M) {
            ADownBRight = process2(matrix, Ar + 1, Ac, Br, dp);
        }
        int ADownBDown = 0;
        if (Ar + 1 < N && Br + 1 < N) {
            ADownBDown = process2(matrix, Ar + 1, Ac, Br + 1, dp);
        }
        int ARightBRight = 0;
        if (Ac + 1 < M && Bc + 1 < M) {
            ARightBRight = process2(matrix, Ar, Ac + 1, Br, dp);
        }
        int ARightBDown = 0;
        if (Ac + 1 < M && Br + 1 < N) {
            ARightBDown = process2(matrix, Ar, Ac + 1, Br + 1, dp);
        }
        int nextBest = Math.max(Math.max(ADownBRight, ADownBDown), Math.max(ARightBRight, ARightBDown));

        int curNum = Ar == Br ? matrix[Ar][Ac] : matrix[Ar][Ac] + matrix[Br][Bc];
        int res = curNum + nextBest;
        dp[Ar][Ac][Br] = res;
        return res;
    }

    public static void main(String[] args) {
        int[][] matrix = {
                {1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 1, 0, 0, 0, 0, 1},
                {1, 0, 0, 0, 1, 0, 0, 0, 0, 0},
                {0, 0, 0, 0, 1, 1, 1, 1, 1, 1}
        };

        System.out.println(comeGoMaxPathSum(matrix));
        System.out.println(dp(matrix));
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值