学习剑指offer 第九天,第十天
42 连续子数组最大和
- 题目描述
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。 - 解答
双指针法:
public int maxSubArray(int[] nums) {
//使用双指针,窗口内包含了最大和的子数组
int left = 0, right = 0;
int max = Integer.MIN_VALUE;
int sum = 0;
//记录数组中的最大值,如果最大值小于0,则代表数组均为负数,则最大和就是负数的最大值
int tmp = Integer.MIN_VALUE;
for(; right < nums.length; right++){
sum += nums[right];
//和为负数时,就移动左指针
if(sum < 0){
while(left <= right && sum < 0){
sum -= nums[left++];
}
}
max = Math.max(max, sum);
tmp = Math.max(tmp, nums[right]);
}
return tmp < 0 ? tmp : max;
}
贪心法:
public int maxSubArray(int[] nums) {
//贪心思想:遇到负值,就重新开始计算
int max = Integer.MIN_VALUE;
int tmp = 0;
for(int i = 0; i < nums.length; i++){
//先判断是否为负值,再加当前数组值,可以保证全负的情况下,也可以正确的输出
tmp = Math.max(0, tmp) + nums[i];
max = Math.max(tmp, max);
}
return max;
}
动态规划法:
public int maxSubArray(int[] nums) {
//动态规划法
//dp数组为到第i个数字时,最大和的值
int[] dp = new int[nums.length];
//初始化
dp[0] = nums[0];
int max = dp[0];
for(int i = 1; i < nums.length; i++){
//如果前面的和为负数,则舍弃,从当前位置算起
dp[i] = Math.max(dp[i - 1], 0) + nums[i];
max = Math.max(max, dp[i]);
}
return max;
}
47 礼物最大价值
-
题目描述
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物? -
解答:动态规划
public int maxValue(int[][] grid) {
//dp[i][j]:走到该位置时可以拿到礼物的最大价值
int[][] dp = new int[grid.length][grid[0].length];
//初始化
dp[0][0] = grid[0][0];
for(int i = 1; i < grid.length; i++){
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for(int j = 1; j < grid[0].length; j++){
dp[0][j] = dp[0][j - 1] + grid[0][j];
}
for(int i = 1; i < grid.length; i++){
for(int j = 1; j < grid[0].length; j++){
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
}
}
return dp[grid.length - 1][grid[0].length - 1];
}
46 把字符翻译成字符串
- 题目描述:
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
-解答
使用动态规划:
public int translateNum(int num) {
String str = String.valueOf(num);
//动态规划
//dp数组:截止到第i位有多少种翻译方法
int[] dp = new int[str.length()];
//初始化
dp[0] = 1;
if(str.length() == 1) return 1;
if(Integer.parseInt(str.substring(0, 2)) <= 25) dp[1] = 2;
else dp[1] = 1;
for(int i = 2; i < str.length(); i++){
//如果该位可以与前面的数字凑成大于10,小于25的数字,则截止到该位,翻译方法为把该位置当作是单独的数字以及把该位和前一位当作是整体的方法总数
if(str.charAt(i - 1) != '0' && Integer.parseInt(str.substring(i - 1, i + 1)) <= 25) dp[i] = dp[i - 1] + dp[i - 2];
else dp[i] = dp[i - 1];
}
return dp[str.length() - 1];
}
48 最长不含重复字符的子字符串
- 题目描述
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。 - 解答
双指针法
public int lengthOfLongestSubstring(String s) {
if(s.length() == 0) return 0;
//双指针
char[] sarray = s.toCharArray();
int left = 0, right = 0;
//记录是否有重复的元素,ascii的长度
int[] record = new int[128];
int max = Integer.MIN_VALUE;
for(; right < sarray.length; right++){
char c = sarray[right];
record[c]++;
//有重复元素
if(record[c] > 0){
while(left <= right && record[c] > 1){
record[sarray[left ++]] --;
}
}
max = Math.max(max, right - left + 1);
}
return max;
}