利用动态规划求解——给定矩阵求路径之和最大最小类问题

题1:下降路径最小和
给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。

下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选元素最多相隔一列(即位于正下方或者沿对角线向左或者向右的第一个元素)。具体来说,位置 (row, col) 的下一个元素应当是 (row + 1, col - 1)、(row + 1, col) 或者 (row + 1, col + 1) 。

算法思路:
对于这类问题,给定矩阵求解最值,很明显可以使用动态规划来求解问题,有以下三个特殊位置:最左侧一列、最右侧一列、其他剩余列;对于最左侧一列元素只能从其正上方或者右上方来;对于最右侧一列只能从正上方或者左上方来;其他剩余元素可以从正上方、左上方和右上方来。
这里初始化二维数组时要注意,不能先初始化最左侧和最右侧然后再初始化剩余元素;因为在初始化最左侧或最右侧元素时,同时需要中间剩余元素的参与;那么我们只能一行一行进行存储元素。

算法实现:

class Solution {
    public static int minFallingPathSum(int[][] matrix) {
        //定义一格二维数组用来存储
        int[][] res = new int[matrix.length][matrix.length];
        //将res数组的第一行初始化
        for (int j=0;j<matrix[0].length;j++){
            res[0][j] = matrix[0][j];
        }
        //填充元素得一行一行来
        for (int i = 1;i<matrix.length;i++){
            //首先填充两边
            //最左侧
            res[i][0] = Math.min(res[i-1][0],res[i-1][1])+matrix[i][0];
            //最右侧
            res[i][matrix[0].length-1] = Math.min(res[i-1][matrix[0].length-1],res[i-1][matrix[0].length-2])+matrix[i][matrix[0].length-1];
            for (int j = 1;j<matrix[0].length-1;j++){
                //中间剩余元素
                res[i][j] = Math.min(Math.min(res[i-1][j],res[i-1][j-1]),res[i-1][j+1])+matrix[i][j];
            }
        }
        //在最后这一行找最小值
        int min = Integer.MAX_VALUE;
        for (int j = 0;j<matrix[0].length;j++){
            min = Math.min(min,res[matrix.length-1][j]);
        }
        return min;
    }
}

题2:礼物的最大价值
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?

算法思路:
这里思路与上一题类似,只需要定义一个二维数组进行存储元素,然后逐步遍历即可。

算法实现:

class Solution {
    public int maxValue(int[][] grid) {
        //定义一个二维数组用来存储(总和)
        int[][] res = new int[grid.length][grid[0].length];
        //初始化左上角
        res[0][0] = grid[0][0];
        //对于第一行只能向右走
        for (int j=1;j<grid[0].length;j++){
            res[0][j] = res[0][j-1]+grid[0][j]; 
        }
        //对于第一列只能向下走
        for (int i = 1;i<grid.length;i++){
            res[i][0] = res[i-1][0]+grid[i][0];
        }
        //剩余元素找最大的
        for (int i = 1;i<grid.length;i++){
            for (int j = 1;j<grid[0].length;j++){
                res[i][j] = Math.max(res[i-1][j],res[i][j-1])+grid[i][j];
            }
        }
        return res[res.length-1][res[0].length-1];
    }
}

题3:最长不含重复字符的子字符串
——利用HashMap简化步骤
题目描述:
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

1)
输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
(2)
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1

算法思路:
这道题,我采用的是通过HashMap存储已经遍历过的元素,当再次遇到相同元素时,此时可以利用HashMap判断是否有重复元素,当没有重复元素则将当前元素put入HashMap当中;遇到重复元素那么就清空HashMap,然后从上一次出发位置的下一个位置开始进行寻找。

ps:
这里需要注意当遍历到字符串的最后一个元素时,倘若还没有重复元素,那么就需要比较出和之前的哪个最大值。
同时更新下一次遍历起点的时候,由于start更新是在for循环里面,那么采用的时start++,而不是++start!(因为赋值后会在加一次,那么只需要上一次的就可以,加1会出现在for循环的更新表达式中)

算法实现:

class Solution {
    public static int lengthOfLongestSubstring(String s) {
        if (s.length()==1){
            return 1;
        }else if ("".equals(s)){
            return 0;
        }else{
            HashMap<Character,Integer> hash = new HashMap<>();
            int start = 0;
            int max = 0;
            for (int i = 0;i<s.length();i++){
                char c = s.charAt(i);
                //不重复元素
                if (!hash.containsKey(c)){
                    //将该元素放入
                    hash.put(c,1);
                    if (i==s.length()-1){
                        max = Math.max(max,hash.size());
                    }
                }else if (hash.containsKey(c)){
                    //包含重复元素
                    max = Math.max(max,hash.size());
                    hash.clear();
                    //从上次起始位置的下一位开始遍历
                    i = start++;
                }
            }
            return max;
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值