LeetCode第27场双周赛20200530

174 阅读8分钟

第27场双周赛

20200530

1460. 通过翻转子数组使两个数组相等

题目描述1

给你两个长度相同的整数数组 target 和 arr 。

每一步中,你可以选择 arr 的任意 非空子数组 并将它翻转。你可以执行此过程任意次。

如果你能让 arr 变得与 target 相同,返回 True;否则,返回 False 。

示例 1:

输入:target = [1,2,3,4], arr = [2,4,1,3]
输出:true
解释:你可以按照如下步骤使 arr 变成 target:
1- 翻转子数组 [2,4,1] ,arr 变成 [1,4,2,3]
2- 翻转子数组 [4,2] ,arr 变成 [1,2,4,3]
3- 翻转子数组 [4,3] ,arr 变成 [1,2,3,4]
上述方法并不是唯一的,还存在多种将 arr 变成 target 的方法。

示例 2:

输入:target = [7], arr = [7]
输出:true
解释:arr 不需要做任何翻转已经与 target 相等。

示例 3:

输入:target = [1,12], arr = [12,1]
输出:true

示例 4:

输入:target = [3,7,9], arr = [3,7,11]
输出:false
解释:arr 没有数字 9 ,所以无论如何也无法变成 target 。

示例 5:

输入:target = [1,1,1,1,1], arr = [1,1,1,1,1]
输出:true

提示:

  • target.length == arr.length
  • 1 <= target.length <= 1000
  • 1 <= target[i] <= 1000
  • 1 <= arr[i] <= 1000

解答1

判断每个数的个数是否一样,用哈希表存储target元素,再利用iterator来判断是否每个元素相同。

class Solution {
    public boolean canBeEqual(int[] target, int[] arr) {
        int len = target.length;
        Map<Integer, Integer> map =new HashMap<>();
        for(int i = 0; i < len; i++){
            map.put(target[i], map.getOrDefault(target[i], 0) + 1);
        }
        for(int i = 0; i < len; i++){
            map.put(arr[i], map.getOrDefault(arr[i], 0) - 1);
        }
        Iterator iter = map.entrySet().iterator();
        while(iter.hasNext()){
            Map.Entry entry = (Map.Entry) iter.next();
            Integer val =(Integer) entry.getValue();
            if(val != 0){
                return false;
            }
        }
        return true;

    }
}

1461. 检查一个字符串是否包含所有长度为 K 的二进制子串

题目描述2

给你一个二进制字符串 s 和一个整数 k 。

如果所有长度为 k 的二进制字符串都是 s 的子串,请返回 True ,否则请返回 False 。

示例 1:

输入:s = "00110110", k = 2
输出:true
解释:长度为 2 的二进制串包括 "00""01""10""11"。它们分别是 s 中下标为 0132 开始的长度为 2 的子串。

示例 2:

输入:s = "00110", k = 2
输出:true

示例 3:

输入:s = "0110", k = 1
输出:true
解释:长度为 1 的二进制串包括 "0""1",显然它们都是 s 的子串。

示例 4:

输入:s = "0110", k = 2
输出:false
解释:长度为 2 的二进制串 "00" 没有出现在 s 中。

示例 5:

输入:s = "0000000001011100", k = 4
输出:false

提示:

  • 1 <= s.length <= 5 * 10^5
  • s 中只含 0 和 1 。
  • 1 <= k <= 20

解答2

  1. 建立一个array数组,存储所以子串的十进制数表示,下标对应数字大小。遍历所有子串,判断是否数组中有对应下标的值没有array[i]++。
class Solution {
    public boolean hasAllCodes(String s, int k) {
        int num = (int) Math.pow(2, k) - 1;
        int[] array = new int [num + 1];
        Arrays.fill(array, -1);
        int len = s.length();
        String kString = Integer.toBinaryString(k);
        int temp = 0;
        for(int i = 0; i <= len - k; i++){
            temp = Integer.parseInt(s.substring(i, i+k), 2);
            array[temp]++;
        }
        for(int i = 0; i <= num; i++){
            if(array[i] < 0){
                return false;
            }
        }
        return true;
    }
}
  1. 直接判断不重复子串的数目是不是为个就行了。省去加值的时间,用Set。
class Solution {
    public boolean hasAllCodes(String s, int k) {
        Set<Integer> set = new HashSet<>();
        for(int i = 0, w = 0; i < s.length(); i++ ){
            w = w * 2 + s.charAt(i) - '0';
            if(i >= k){
                w -= s.charAt(i - k) - '0' << k;
            }
            if(i >= k - 1){
                set.add(w);
            }
        }
        return set.size() == 1 << k;
    }
}

1462. 课程安排 IV

题目描述3

你总共需要上 n 门课,课程编号依次为 0 到 n-1 。

有的课会有直接的先修课程,比如如果想上课程 0 ,你必须先上课程 1 ,那么会以 [1,0] 数对的形式给出先修课程数对。

给你课程总数 n 和一个直接先修课程数对列表 prerequisite 和一个查询对列表 queries 。

对于每个查询对 queries[i] ,请判断 queries[i][0] 是否是 queries[i][1] 的先修课程。

请返回一个布尔值列表,列表中每个元素依次分别对应 queries 每个查询对的判断结果。

注意:如果课程 a 是课程 b 的先修课程且课程 b 是课程 c 的先修课程,那么课程 a 也是课程 c 的先修课程。

示例 1:

输入:n = 2, prerequisites = [[1,0]], queries = [[0,1],[1,0]]
输出:[false,true]
解释:课程 0 不是课程 1 的先修课程,但课程 1 是课程 0 的先修课程。

示例 2:

输入:n = 2, prerequisites = [], queries = [[1,0],[0,1]]
输出:[false,false]
解释:没有先修课程对,所以每门课程之间是独立的。

示例 3:

输入:n = 3, prerequisites = [[1,2],[1,0],[2,0]], queries = [[1,0],[1,2]]
输出:[true,true]

示例 4:

输入:n = 3, prerequisites = [[1,0],[2,0]], queries = [[0,1],[2,0]]
输出:[false,true]

示例 5:

输入:n = 5, prerequisites = [[0,1],[1,2],[2,3],[3,4]], queries = [[0,4],[4,0],[1,3],[3,0]]
输出:[true,false,true,false]

提示:

  • 2 <= n <= 100
  • 0 <= prerequisite.length <= (n * (n - 1) / 2)
  • 0 <= prerequisite[i][0], prerequisite[i][1] < n
  • prerequisite[i][0] != prerequisite[i][1]
  • 先修课程图中没有环。
  • 先修课程图中没有重复的边。
  • 1 <= queries.length <= 10^4
  • queries[i][0] != queries[i][1]

解答3

Folyd算法,三层1~n循环,时间复杂度

tips:二维数组的遍历我算法用了两种方法,可以参考for(int m = 0; m < len; m++ )for(int[] q : queries)

class Solution {
    public List<Boolean> checkIfPrerequisite(int n, int[][] prerequisites, int[][] queries) {
        int len = prerequisites.length;
        boolean[][] flag = new boolean[n][n];
        for(int m = 0; m < len; m++ ){
            flag[prerequisites[m][0]][prerequisites[m][1]] = true;
        }
        for(int k = 0; k < n; k++ ){
            for(int i = 0; i < n; i++ ){
                for(int j = 0; j < n; j++ ){
                    if(flag[i][k] && flag[k][j]){
                        flag[i][j] = true;
                    }

                }
            }
        }
        List<Boolean> res = new LinkedList<>();
        for(int[] q : queries){
            res.add(flag[q[0]][q[1]]);
        }
        return res;
    }
}

1463. 摘樱桃 II

题目描述4

给你一个 rows x cols 的矩阵 grid 来表示一块樱桃地。 grid 中每个格子的数字表示你能获得的樱桃数目。

你有两个机器人帮你收集樱桃,机器人 1 从左上角格子 (0,0) 出发,机器人 2 从右上角格子 (0, cols-1) 出发。

请你按照如下规则,返回两个机器人能收集的最多樱桃数目:

从格子 (i,j) 出发,机器人可以移动到格子 (i+1, j-1),(i+1, j) 或者 (i+1, j+1) 。 当一个机器人经过某个格子时,它会把该格子内所有的樱桃都摘走,然后这个位置会变成空格子,即没有樱桃的格子。 当两个机器人同时到达同一个格子时,它们中只有一个可以摘到樱桃。 两个机器人在任意时刻都不能移动到 grid 外面。 两个机器人最后都要到达 grid 最底下一行。 示例 1:

输入:grid = [[3,1,1],[2,5,1],[1,5,5],[2,1,1]]
输出:24
解释:机器人 1 和机器人 2 的路径在上图中分别用绿色和蓝色表示。
机器人 1 摘的樱桃数目为 (3 + 2 + 5 + 2) = 12机器人 2 摘的樱桃数目为 (1 + 5 + 5 + 1) = 12樱桃总数为: 12 + 12 = 24

示例 2:

输入:grid = [[3,1,1],[2,5,1],[1,5,5],[2,1,1]]
输出:24
解释:机器人 1 和机器人 2 的路径在上图中分别用绿色和蓝色表示。
机器人 1 摘的樱桃数目为 (3 + 2 + 5 + 2) = 12机器人 2 摘的樱桃数目为 (1 + 5 + 5 + 1) = 12樱桃总数为: 12 + 12 = 24

示例 3:

输入:grid = [[1,0,0,3],[0,0,0,3],[0,0,3,3],[9,0,3,3]]
输出:22

示例 4:

输入:grid = [[1,1],[1,1]]
输出:4

提示:

  • rows == grid.length
  • cols == grid[i].length
  • 2 <= rows, cols <= 70
  • 0 <= grid[i][j] <= 100

解答4

动态规划,dp[k][i][j]表示第i行第一个机器人在i列,第二个机器人在j列的收取樱桃的最大值。那么有第k - 1行时i-1,i,i+1与j-1,j,j+1,相乘9种状态。

class Solution {
    public int cherryPickup(int[][] grid) {
        int rows = grid.length, cols = grid[0].length;
        int[][][] dp = new int[rows][cols][cols];

        int res = 0;
        for(int i = 0; i < rows; i++){
            for(int j = 0; j < cols; j++){
                Arrays.fill(dp[i][j], -1);
            }
        }
        dp[0][0][cols - 1] = grid[0][0] + grid[0][cols - 1];

        for(int k = 1; k < rows; k++){
            for(int i = 0; i < cols; i++){
                for(int j = 0; j < cols; j++){
                    for(int a = i - 1; a <= i + 1; a++){
                        for(int b = j - 1; b <= j + 1; b++){
                            if(a < 0 || a >= cols || b < 0 || b >= cols){
                                continue;
                            }
                            int t = dp[k -1][a][b];
                            if(t == -1) continue;
                            if(i == j) t += grid[k][j];
                            else t += grid[k][i] + grid[k][j];
                            dp[k][i][j] = Math.max(dp[k][i][j], t);

                            res = Math.max(res, dp[k][i][j]);
                        }
                    }
                }
            }
        }

        return res;
    }
}

本文使用 mdnice 排版