这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
剑指 Offer 47. 礼物的最大价值
题目
在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例 1:
输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 12
解释: 路径 1→3→5→2→1 可以拿到最多价值的礼物
提示:
0 < grid.length <= 2000 < grid[0].length <= 200
方法一
动态规划:
f[i][j]表示在棋盘的第i行,第j列拿礼物的方案,值表示方案中的最大价值;- 根据题意,转移方程为
f[i][j] = max(f[i][j-1], f[i-1][j]);
class Solution {
public int maxValue(int[][] grid) {
int n = grid.length, m = grid[0].length;
int[][] f = new int[n + 1][m + 1];
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ ) {
f[i][j] = Math.max(f[i - 1][j], f[i][j - 1]) + grid[i - 1][j - 1];
}
return f[n][m];
}
}
时间复杂度: O(n*n)
空间复杂度: O(n*n)
利用滚动数组优化一维空间:
class Solution {
public int maxValue(int[][] grid) {
int n = grid.length, m = grid[0].length;
int[][] f = new int[2][m + 1];
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ ) {
f[i & 1][j] = Math.max(f[(i - 1) & 1][j], f[i & 1][j - 1]) + grid[i - 1][j - 1];
}
return f[n & 1][m];
}
}
时间复杂度: O(n*n)
空间复杂度: O(n)
剑指 Offer 48. 最长不含重复字符的子字符串
题目
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
提示:
s.length <= 40000
方法一
由于本题的数据范围是0~40000,如果用n*n的算法会超时,所以只能用时间复杂度为nlogn或者n的算法;
双指针:
- 首先维护一个哈希表,用来存储遍历到当前位置之前的各个字符的出现次数;
- 头指针指向的字符在哈希表中
+1 - 如果此时
+1后,该字符出现的次数大于1,说明从尾指针到头指针的这段区间,有和当前字符重复的元素; - 移动尾指针,并将尾指针指向的字符在哈希表中
-1,直至头指针指向的字符出现的次数变为1;
class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
char[] str = s.toCharArray();
HashMap<Character, Integer> map = new HashMap<>();
int res = 0;
for (int i = 0, j = 0; i < n; i ++) {
char c = str[i];
map.put(c, map.getOrDefault(c, 0) + 1);
while(map.get(c) > 1)
map.put(str[j], map.getOrDefault(str[j ++], 0) - 1);
res = Math.max(res, i - j + 1);
}
return res;
}
}
时间复杂度: O(n)
空间复杂度: O(n)