天天看点

LeetCode Weekly Contest 1665279. 整数的各位积和之差 显示英文描述5280. 用户分组 显示英文描述5281. 使结果不超过阈值的最小除数 显示英文描述5282. 转化为全零矩阵的最少反转次数 显示英文描述

5279. 整数的各位积和之差 显示英文描述

题目难度Easy

给你一个整数 n,请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。

示例 1:

输入:n = 234

输出:15

解释:

各位数之积 = 2 * 3 * 4 = 24

各位数之和 = 2 + 3 + 4 = 9

结果 = 24 - 9 = 15

示例 2:

输入:n = 4421

输出:21

解释:

各位数之积 = 4 * 4 * 2 * 1 = 32

各位数之和 = 4 + 4 + 2 + 1 = 11

结果 = 32 - 11 = 21

提示:

1 <=

n <= 10^5

代码

class Solution {
    public int subtractProductAndSum(int n) {
        int sum = 0, prod = 1;
        while (n > 0) {
            int tmp = n % 10;
            n /= 10;
            sum += tmp;
            prod *= tmp;
        }
        return prod - sum;
    }
}
           

5280. 用户分组 显示英文描述

题目难度Medium

有 n 位用户参加活动,他们的 ID 从 0 到 n - 1,每位用户都 恰好 属于某一用户组。给你一个长度为 n 的数组 groupSizes,其中包含每位用户所处的用户组的大小,请你返回用户分组情况(存在的用户组以及每个组中用户的 ID)。

你可以任何顺序返回解决方案,ID 的顺序也不受限制。此外,题目给出的数据保证至少存在一种解决方案。

示例 1:

输入:groupSizes = [3,3,3,3,3,1,3]

输出:[[5],[0,1,2],[3,4,6]]

解释:

其他可能的解决方案有 [[2,1,6],[5],[0,4,3]] 和 [[5],[0,6,2],[4,3,1]]。

示例 2:

输入:groupSizes = [2,1,3,3,3,2]

输出:[[1],[0,5],[2,3,4]]

提示:

groupSizes.length == n

1 <= n <= 500

1 <= groupSizes[i] <= n

思路

哈希表

代码

class Solution {
    public List<List<Integer>> groupThePeople(int[] groupSizes) {
        List<List<Integer>> ans = new ArrayList<>();
        HashMap<Integer, List<Integer>> sizeMap = new HashMap<>();
        int idx = 0;
        for (int gs: groupSizes) {
            if (!sizeMap.containsKey(gs)) {
                sizeMap.put(gs, new ArrayList<Integer>());
            }
            sizeMap.get(gs).add(idx++);
            if (sizeMap.get(gs).size() == gs) {
                ans.add(new ArrayList<Integer>(sizeMap.get(gs)));
                sizeMap.get(gs).clear();
            }
        }
        return ans;
    }
}
           

5281. 使结果不超过阈值的最小除数 显示英文描述

题目难度Medium

给你一个整数数组 nums 和一个正整数 threshold ,你需要选择一个正整数作为除数,然后将数组里每个数都除以它,并对除法结果求和。

请你找出能够使上述结果小于等于阈值 threshold 的除数中 最小 的那个。

每个数除以除数后都向上取整,比方说 7/3 = 3 , 10/2 = 5 。

题目保证一定有解。

示例 1:

输入:nums = [1,2,5,9], threshold = 6

输出:5

解释:如果除数为 1 ,我们可以得到和为 17 (1+2+5+9)。

如果除数为 4 ,我们可以得到和为 7 (1+1+2+3) 。如果除数为 5 ,和为 5 (1+1+1+2)。

示例 2:

输入:nums = [2,3,5,7,11], threshold = 11

输出:3

示例 3:

输入:nums = [19], threshold = 5

输出:4

提示:

1 <= nums.length <= 5 * 10^4

1 <= nums[i] <= 10^6

nums.length <= threshold <= 10^6

思路

求出除数的上界和下界,二分查找最小的满足的题意的除数(该二分查找是标准二分的变式,关于二分查找的各种变式的一个整理见二分查找及其若干变种)

代码

class Solution {
    private boolean check(int[] nums, int div, int threshold) {
        int ans = 0;
        for (int num: nums) {
            ans += num / div;
            if (num % div != 0) {
                ++ans;
            }
        }
        return ans <= threshold;
    }
    
    public int smallestDivisor(int[] nums, int threshold) {
        int sum = 0, lower = 0, upper = 0, uthr = threshold - nums.length;
        for (int num: nums) {
            sum += num;
            if (sum > threshold) {
                lower += sum / threshold;
                sum %= threshold;
            }
        }
        if (sum != 0) {
            ++lower;
        }
        sum = 0;
        for (int num: nums) {
            sum += num;
            if (sum > uthr) {
                upper += sum / uthr;
                sum %= uthr;
            }
        }
        int mid = 0;
        while (lower <= upper) {
            // System.out.println(lower + " " + upper);
            mid = (lower + upper) / 2;
            if (check(nums, mid, threshold)) {
                upper = mid - 1;
            } else {
                lower = mid + 1;
            }
        }
        return lower;
    }
}
           

5282. 转化为全零矩阵的最少反转次数 显示英文描述

题目难度Hard

给你一个 m x n 的二进制矩阵 mat。

每一步,你可以选择一个单元格并将它反转(反转表示 0 变 1 ,1 变 0 )。如果存在和它相邻的单元格,那么这些相邻的单元格也会被反转。(注:相邻的两个单元格共享同一条边。)

请你返回将矩阵 mat 转化为全零矩阵的最少反转次数,如果无法转化为全零矩阵,请返回 -1 。

二进制矩阵的每一个格子要么是 0 要么是 1 。

全零矩阵是所有格子都为 0 的矩阵。

示例 1:

输入:mat = [[0,0],[0,1]]

输出:3

解释:一个可能的解是反转 (1, 0),然后 (0, 1) ,最后是 (1, 1) 。

示例 2:

输入:mat = [[0]]

输出:0

解释:给出的矩阵是全零矩阵,所以你不需要改变它。

示例 3:

输入:mat = [[1,1,1],[1,0,1],[0,0,0]]

输出:6

示例 4:

输入:mat = [[1,0,0],[1,0,0]]

输出:-1

解释:该矩阵无法转变成全零矩阵

提示:

m == mat.length

n == mat[0].length

1 <= m <= 3

1 <= n <= 3

mat[i][j] 是 0 或 1

思路

bfs找最短路,用二进制数表示矩阵状态,用位运算表示状态转移

代码

class Solution {
    class Node {
        public int state, len;
        
        public Node(int state, int len) {
            this.state = state;
            this.len = len;
        }
    }
    public int minFlips(int[][] mat) {
        int m = mat.length, n = mat[0].length, tot = (1 << (m * n)), state = 0, i = 0, j = 0, nstate = 0, bit = 0;
        boolean[] vis = new boolean[tot];
        for (i = 0; i < m; ++i) {
            for (j = 0; j < n; ++j) {
                if (mat[i][j] == 1) {
                    state |= (1 << (i * n + j));
                }
            }
        }
        if (state == 0) {
            return 0;
        }
        LinkedList<Node> queue = new LinkedList<>();
        queue.add(new Node(state, 0));
        vis[state] = true;
        while (!queue.isEmpty()) {
            Node node = queue.removeFirst();
            // System.out.println(node.state + " " + node.len);
            for (i=0; i<m; ++i) {
                for (j=0; j<n; ++j) {
                    bit = (1 << (i * n + j));
                    if (i - 1 >= 0) {
                        bit |= (1 << ((i-1)*n + j));
                    }
                    if (i + 1 < m) {
                        bit |= (1 << ((i+1)*n + j));
                    }
                    if (j - 1 >= 0) {
                        bit |= (1 << (i*n + j-1));
                    }
                    if (j + 1 < n) {
                        bit |= (1 << (i*n + j + 1));
                    }
                    nstate = node.state ^ bit;
                    if (nstate == 0) {
                        return node.len + 1;
                    }
                    if (!vis[nstate]) {
                        vis[nstate] = true;
                        queue.add(new Node(nstate, node.len + 1));
                    }
                }
            }
        }
        return -1;
    }
}