题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;
}
}
}