剑指Offer 47 48

176 阅读1分钟

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

剑指 Offer 47. 礼物的最大价值

题目

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

示例 1:

输入: 
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 12
解释: 路径 13521 可以拿到最多价值的礼物

提示:

  • 0 < grid.length <= 200
  • 0 < 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)