欢迎大家加QQ群:623375442,可以方便群里面交流。

100345. Find Minimum Operations to Make All Elements Divisible by Three

给你一个整数数组 nums 。一次操作中,你可以将 nums 中的 任意 一个元素增加或者减少 1 。

请你返回将 nums 中所有元素都可以被 3 整除的 最少 操作次数。

测试样例:

输入:nums = [1,2,3,4]

输出:3

解释:通过以下 3 个操作,数组中的所有元素都可以被 3 整除:将 1 减少 1 。将 2 增加 1 。将 4 减少 1 。

解答:非常简单的数学题。% 3之后,看当前数利用加法还是减法可以更快的到达3的倍数。

class Solution {
    public int minimumOperations(int[] nums) {
        int res = 0;
        for (int n : nums) {
            int r = n % 3;
            res += Math.min(3 - r, r);
        }
        return res;
    }
}

100344. Minimum Operations to Make Binary Array Elements Equal to One I

给你一个二进制数组 nums 。

你可以对数组执行以下操作 任意 次(也可以 0 次):

  • 选择数组中 任意连续 3 个元素,并将它们 全部反转 。

反转 一个元素指的是将它的值从 0 变 1 ,或者从 1 变 0 。

请你返回将 nums 中所有元素变为 1 的 最少 操作次数。如果无法全部变成 1 ,返回 -1 。

测试样例:

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

输出:3

解释:我们可以执行以下操作:

  • 选择下标为 0 ,1 和 2 的元素并反转,得到 nums = [1,0,0,1,0,0] 。
  • 选择下标为 1 ,2 和 3 的元素并反转,得到 nums = [1,1,1,0,0,0] 。
  • 选择下标为 3 ,4 和 5 的元素并反转,得到 nums = [1,1,1,1,1,1] 。

解答:暴力遍历,如果当前数字不符合要求,那么就尝试一次操作。

class Solution {
    public int minOperations(int[] nums) {
        int res = 0;
        for (int i = 0; i < nums.length; ++i) {
            if (nums[i] == 0) {
                if (i + 2 >= nums.length) return -1;
                nums[i] ^= 1;
                nums[i + 1] ^= 1;
                nums[i + 2] ^= 1;
                ++res;
            }
        }
        return res;
    }
}

100346. Minimum Operations to Make Binary Array Elements Equal to One II

给你一个二进制数组 nums 。

你可以对数组执行以下操作 任意 次(也可以 0 次):

  • 选择数组中 任意 一个下标 i ,并将从下标 i 开始一直到数组末尾 所有 元素 反转 。

反转 一个元素指的是将它的值从 0 变 1 ,或者从 1 变 0 。

请你返回将 nums 中所有元素变为 1 的 最少 操作次数。

测试样例:

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

输出:4

解释:我们可以执行以下操作:

  • 选择下标 i = 1 执行操作,得到 nums = [0,0,0,1,0] 。
  • 选择下标 i = 0 执行操作,得到 nums = [1,1,1,0,1] 。
  • 选择下标 i = 4 执行操作,得到 nums = [1,1,1,0,0] 。
  • 选择下标 i = 3 执行操作,得到 nums = [1,1,1,1,1] 。

解答:没啥难度,类似前缀和。记录一下当前数字的反转次数。如果当前数经过计算之后,不满足要求,那么就翻转一下。

class Solution {
    public int minOperations(int[] nums) {
        int res = 0, xor = 0;
        for (int n : nums) {
            if ((n ^ xor) == 0) {
                ++res;
                xor ^= 1;
            }
        }
        return res;
    }
}

100333. Count the Number of Inversions

给你一个整数 n 和一个二维数组 requirements ,其中 requirements[i] = [endi, cnti] 表示这个要求中的末尾下标和 逆序对 的数目。

整数数组 nums 中一个下标对 (i, j) 如果满足以下条件,那么它们被称为一个 逆序对 :

  • i < j 且 nums[i] > nums[j]

请你返回 [0, 1, 2, ..., n - 1] 的 排列 perm 的数目,满足对 所有 的 requirements[i] 都有 perm[0..endi] 恰好有 cnti 个逆序对。

由于答案可能会很大,将它对 10^9 + 7 取余 后返回。

测试样例:

输入:n = 3, requirements = [[2,2],[0,0]]

输出:2

解释:两个排列为:

  • [2, 0, 1]
    • 前缀 [2, 0, 1] 的逆序对为 (0, 1) 和 (0, 2) 。
    • 前缀 [2] 的逆序对数目为 0 个。
  • [1, 2, 0]
    • 前缀 [1, 2, 0] 的逆序对为 (0, 2) 和 (1, 2) 。
    • 前缀 [1] 的逆序对数目为 0 个。

解答:这题我觉得还挺难的,但是看AC的人还挺多的。大致思路可以参考这题903. Valid Permutations for DI Sequence。也是类似的map的思路。然后遍历到第i个数的时候,最后一位为0,那么当前的位数需要增加i,1就是i - 1。。。以此类推。唯一需要注意的是,还需要满足requirement。

class Solution {
    private static final int mod = 1_000_000_007;

    public int numberOfPermutations(int n, int[][] requirements) {
        int[] rq = new int[n];
        Arrays.fill(rq, -1);
        int max = 0;
        for (int[] r : requirements) {
            rq[r[0]] = r[1];
            max = Math.max(max, r[1]);
        }
        if (rq[0] > 0) {
            return 0;
        }
        int[] cur = new int[max + 1];
        cur[0] = 1;
        for (int i = 1; i < n; ++i) {
            int[] next = new int[max + 1];
            int sum = 0;
            for (int j = 0; j <= max; ++j) {
                sum = (sum + cur[j]) % mod;
                if (rq[i] == -1 || rq[i] == j) {
                    next[j] = sum;
                }
                if (j >= i) {
                    sum = (sum + mod - cur[j - i]) % mod;
                }
            }
            cur = next;
        }
        return cur[max];
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *