其他分享
首页 > 其他分享> > Leetcode第300场周赛记录

Leetcode第300场周赛记录

作者:互联网

6108. 解密消息

题目分析:给定keymessage,其中key中26个英文小写字母首次出现的顺序作为替换表中的字母顺序,听起来有点绕口,如:"the quick..."对应"abc defgh...",即key首次出现的字母按字母表顺序映射,因此直接用哈希表模拟,将message的每个字母替换,' '不变。

class Solution {
    public String decodeMessage(String key, String message) {
        char[] keyChars = key.toCharArray();
        Map<Character, Character> keyMap = new HashMap<>();
        int index = 0;
        for (char keyChar : keyChars) {
            if (keyChar != ' ' && !keyMap.containsKey(keyChar)) {
                keyMap.put(keyChar, (char) (index++ + 'a'));
            }
            if (index == 26) {
                break;
            }
        }
        StringBuilder sb = new StringBuilder();
        for (char c : message.toCharArray()) {
            sb.append(keyMap.getOrDefault(c, ' '));
        }
        return sb.toString();
    }
}

6111. 螺旋矩阵 IV

题目分析:对矩阵左上角开始,顺时针按螺旋顺序,将整数链表的值进行填充,不足的部分用-1填充,该类型的题搜索方式和以前的54. 螺旋矩阵大同小异,直接按该模拟方式即可。

class Solution {
    public int[][] spiralMatrix(int m, int n, ListNode head) {
        int[][] matrix = new int[m][n];
        for (int i = 0; i < m; i++) {
            Arrays.fill(matrix[i], -1); // 默认为-1,当head为空时中断全部遍历,提升效率
        }
        int l = 0, r = n - 1, t = 0, b = m - 1; //初始化左、右、上、下边界
        while (true) {
            for (int i = l; i <= r && head != null; i++) { // 左上角出发
                matrix[t][i] = head.val;
                head = head.next;
            }
            if (++t > b) break; // 上边界下移,判断是否大于下边界
            for (int i = t; i <= b && head != null; i++) { // 右上角出发
                 matrix[i][r] = head.val;
                 head = head.next;
            }
            if (--r < l) break; // 右边界左移,判断是否小于左边界
            for (int i = r; i >= l && head != null; i--) {  // 右下角出发
                matrix[b][i] = head.val;
                head = head.next;
            }
            if (--b < t) break; // 下边界上移,判断是否大于上边界
            for (int i = b; i >= t && head != null; i--) { // 左下角触发
                matrix[i][l] = head.val;
                head = head.next;
            }
            if (++l > r) break; // 左边界右移,判断是否大于右边界
        }
        return matrix;
    }
}

6109. 知道秘密的人数

题目分析:第1天一个人发现秘密,给定变量ndelayforget,从那天在静默期delay天后的每一天分享秘密给新人,在超期forget天后则忘记秘密。问n天结束时有几个人知道秘密,结果要对 109+7 取余。很遗憾这题折腾了1小时多就AC不了,第一想法就是用DFS,但这是我的弱项,所以写的DFS是有问题的,而且是1天1天递增的,效率太低了。该题要过滤重复的搜索,使用dfs+一维记忆化来解决这个问题:

// 解法一:dfs+一维记忆化
	/**
	Java 记忆化搜索:
	我们记dfs(i)为第i天发现的秘密的人包含自己在内一共可以使得后面多少人知道秘密
    i从i+delay天起,到i+forget-1天都是可以将秘密散播出去的
    也就是[min(i+delay,n),min(i+forget-1,n)]=[a,b]这个时间段是i的传播阶段
    此时知道秘密的人数有1+∑dfs(a,b)
    同时应该注意知道了秘密的人会忘记秘密,因此也会有一个期限
    这里由于子问题的出现可以使用记忆化减少搜索次数
	*/
class Solution {
    int n, delay, forget;
    int MOD = (int) 1e9 + 7;
    int[] memo;
    public int peopleAwareOfSecret(int _n, int _delay, int _forget) {
        n = _n;
        delay = _delay;
        forget = _forget;
        memo = new int[n + 1]; // 初始化一维记录
        return dfs(1);
    }

    public int dfs(int day) {
        if (day + delay > n) { // 如果在第n天才能传播,只有当事人知道
            return 1;
        }
        if (memo[day] != 0) { // 如果当天已有深搜记录,直接返回
            return memo[day];
        }
        int l = Math.min(day + delay, n), r = Math.min(day + forget - 1, n); // 秘密的传播范围,[静默期结束-忘记)
        long res = day + forget <= n ? 0 : 1; // 如果当事人在n天内给忘了,那结果为0,否则1
        for (int i = l; i <= r; i++) {
            int t = dfs(i);
            memo[i] = t; // 记录结果
            res = (res + t) % MOD;
        }   
        return (int) res; // 返回全部结果
    }
}
// 解法二:用哈希表模拟
class Solution {
    public int peopleAwareOfSecret(int n, int delay, int forget) {
        long mod = 1000000007L;
        Map<Integer, Long> perMap = new HashMap<>(); // day-knowNum
        long res = 1L;
        perMap.put(1, 1L); // 第一天只有1人知道
        for (int day = 2; day <= n; day++) {
            long add = 0, del= 0; // 当天新增知道的人数,忘记的人数
            for (Map.Entry<Integer, Long> entry : perMap.entrySet()) {
                if (day - entry.getKey() >= forget) { // 如果当天的人数满足忘记条件,则记到del,将map对应val设置0
                    del += entry.getValue() % mod;
                    entry.setValue(0L);
                } else if (day - entry.getKey() >= delay) {  // 如果当天的人数满足传播秘密条件,则记到add
                    add += entry.getValue() % mod;
                }

            }
            res = (res + add - del) % mod; // 对当天的新增,忘记人数累加
            if (add != 0) {
                perMap.put(day, add); // 如果当天有新增的人数,存到map
            }
        }
        return (int) res;
    }
}

6110. 网格图中递增路径的数目

题目分析:给定m x n的整数网络图grid,从任意各自触发,到达任意格子,但是路径中的数字是严格递增的,结果对 109+7 取余。依据题意,可以依次遍历每个格子,往上下左右四个方向前进,如果下一个格子比当前格子大,可以前进。使用memo[i][j]保持从grid[i][j]出发的递增路径数,dfs(i,j)的主逻辑:grid[i][j]出发的递增路径数=自身1条+上下左右出发严格递增路径之和。注意,如果路径不能重复走,那么需要加个变量来标记如vis[i][j]=true

// dfs+二维记忆化
class Solution {
    int MOD = (int) 1e9 + 7;
    int[][] dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}};
    int[][] grid, memo;
    int m, n;
    public int countPaths(int[][] _grid) {
        grid = _grid;
        m = grid.length;
        n = grid[0].length;
        memo = new int[m][n]; // 初始化二维记录
        for (int i = 0; i < m; i++) {
            Arrays.fill(memo[i], -1);
        }
        int ans = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                ans = (ans + dfs(i, j)) % MOD; // 对网络的每个节点进行深搜求结果
            }
        }
        return ans;
    }

    public int dfs(int i, int j) {
        if (memo[i][j] != -1) {
            return memo[i][j]; // 该位置已搜索过,直接返回
        }
        long res = 1L; // 自身路径
        for (int[] dir : dirs) { // 四个方向出发
            int dx = i + dir[0];
            int dy = j + dir[1];
            if (dx >= 0 && dx < m && dy >= 0 && dy < n && grid[dx][dy] > grid[i][j]) {
                res = (res + dfs(dx, dy)) % MOD; // 如果新的位置满足在矩阵内,且大于旧位置,继续深搜,结果累加
            }
        }
        memo[i][j] = (int) res; // 记录结果
        return memo[i][j]; // 返回结果
    }
}

标签:周赛,forget,300,memo,day,delay,int,grid,Leetcode
来源: https://www.cnblogs.com/loghorizion/p/16440534.html