3606.优惠券校验器

目标

给你三个长度为 n 的数组,分别描述 n 个优惠券的属性:code、businessLine 和 isActive。其中,第 i 个优惠券具有以下属性:

  • code[i]:一个 字符串,表示优惠券的标识符。
  • businessLine[i]:一个 字符串,表示优惠券所属的业务类别。
  • isActive[i]:一个 布尔值,表示优惠券是否当前有效。

当以下所有条件都满足时,优惠券被认为是 有效的 :

  1. code[i] 不能为空,并且仅由字母数字字符(a-z、A-Z、0-9)和下划线(_)组成。
  2. businessLine[i] 必须是以下四个类别之一:"electronics"、"grocery"、"pharmacy"、"restaurant"。
  3. isActive[i] 为 true 。

返回所有 有效优惠券的标识符 组成的数组,按照以下规则排序:

  • 先按照其 businessLine 的顺序排序:"electronics"、"grocery"、"pharmacy"、"restaurant"。
  • 在每个类别内,再按照 标识符的字典序(升序)排序。

示例 1:

输入: code = ["SAVE20","","PHARMA5","SAVE@20"], businessLine = ["restaurant","grocery","pharmacy","restaurant"], isActive = [true,true,true,true]
输出: ["PHARMA5","SAVE20"]
解释:
第一个优惠券有效。
第二个优惠券的标识符为空(无效)。
第三个优惠券有效。
第四个优惠券的标识符包含特殊字符 @(无效)。

示例 2:

输入: code = ["GROCERY15","ELECTRONICS_50","DISCOUNT10"], businessLine = ["grocery","electronics","invalid"], isActive = [false,true,true]
输出: ["ELECTRONICS_50"]
解释:
第一个优惠券无效,因为它未激活。
第二个优惠券有效。
第三个优惠券无效,因为其业务类别无效。

说明:

  • n == code.length == businessLine.length == isActive.length
  • 1 <= n <= 100
  • 0 <= code[i].length, businessLine[i].length <= 100
  • code[i] 和 businessLine[i] 由可打印的 ASCII 字符组成。
  • isActive[i] 的值为 true 或 false。

思路

代码

性能

1925.统计平方和三元组的数目

目标

一个 平方和三元组 (a,b,c) 指的是满足 a² + b² = c² 的 整数 三元组 a,b 和 c 。

给你一个整数 n ,请你返回满足 1 <= a, b, c <= n 的 平方和三元组 的数目。

示例 1:

输入:n = 5
输出:2
解释:平方和三元组为 (3,4,5) 和 (4,3,5) 。

示例 2:

输入:n = 10
输出:4
解释:平方和三元组为 (3,4,5),(4,3,5),(6,8,10) 和 (8,6,10) 。

说明:

  • 1 <= n <= 250

思路

统计满足 a² + b² = c²,且 1 <= a,b,c <= n 的三元组个数。

暴力枚举 a b,判断平方和是否小于 ,同时判断开根号之后是否是整数。

代码


/**
 * @date 2025-12-08 8:55
 */
public class CountTriples1925 {

    public int countTriples(int n) {
        int res = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j < i && i * i + j * j <= n * n; j++) {
                int s = i * i + j * j;
                int k = (int) Math.sqrt(s);
                if (s == k * k){
                    res++;
                }
            }
        }
        return res * 2;
    }

}

性能

1523.在区间范围内统计奇数数目

目标

给你两个非负整数 low 和 high 。请你返回 low 和 high 之间(包括二者)奇数的数目。

示例 1:

输入:low = 3, high = 7
输出:3
解释:3 到 7 之间奇数数字为 [3,5,7] 。

示例 2:

输入:low = 8, high = 10
输出:1
解释:8 到 10 之间奇数数字为 [9] 。

说明:

  • 0 <= low <= high <= 10^9

思路

返回 low 到 high 之间的奇数数目。

如果数字个数是偶数,返回 (high - low + 1) / 2,否则,取决于 high 是奇数还是偶数,如果是奇数,需要再额外加上 1

代码


/**
 * @date 2025-12-07 22:22
 */
public class CountOdds1523 {

    public int countOdds(int low, int high) {
        int n = high - low + 1;
        return n / 2 + (n % 2 == 0 ? 0 : high % 2);
    }
}

性能

3432.统计元素和差值为偶数的分区方案

目标

给你一个长度为 n 的整数数组 nums 。

分区 是指将数组按照下标 i (0 <= i < n - 1)划分成两个 非空 子数组,其中:

  • 左子数组包含区间 [0, i] 内的所有下标。
  • 右子数组包含区间 [i + 1, n - 1] 内的所有下标。

对左子数组和右子数组先求元素 和 再做 差 ,统计并返回差值为 偶数 的 分区 方案数。

示例 1:

输入:nums = [10,10,3,7,6]
输出:4
解释:
共有 4 个满足题意的分区方案:
[10]、[10, 3, 7, 6] 元素和的差值为 10 - 26 = -16 ,是偶数。
[10, 10]、[3, 7, 6] 元素和的差值为 20 - 16 = 4,是偶数。
[10, 10, 3]、[7, 6] 元素和的差值为 23 - 13 = 10,是偶数。
[10, 10, 3, 7]、[6] 元素和的差值为 30 - 6 = 24,是偶数。

示例 2:

输入:nums = [1,2,2]
输出:0
解释:
不存在元素和的差值为偶数的分区方案。

示例 3:

输入:nums = [2,4,6,8]
输出:3
解释:
所有分区方案都满足元素和的差值为偶数。

说明:

  • 2 <= n == nums.length <= 100
  • 1 <= nums[i] <= 100

思路

将数组 nums 划分为非空的左右两部分,满足左子数组的元素和与右子数组的元素和之差为偶数,返回划分的方案数。

数组所有元素和为 sum,假设左子数组和为 left,那么右子树和为 sum - left,二者之差为 2 * left - sum,只需判断 sum 是否是偶数即可,如果是偶数,有 n - 1 种方案,否则没有满足要求的方案。

代码


/**
 * @date 2025-12-05 9:10
 */
public class CountPartitions3432 {

    public int countPartitions(int[] nums) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        return sum % 2 == 0 ? nums.length - 1 : 0;
    }
}

性能

3512.使数组和能被K整除的最少操作次数

目标

给你一个整数数组 nums 和一个整数 k。你可以执行以下操作任意次:

  • 选择一个下标 i,并将 nums[i] 替换为 nums[i] - 1。

返回使数组元素之和能被 k 整除所需的最小操作次数。

示例 1:

输入: nums = [3,9,7], k = 5
输出: 4
解释:
对 nums[1] = 9 执行 4 次操作。现在 nums = [3, 5, 7]。
数组之和为 15,可以被 5 整除。

示例 2:

输入: nums = [4,1,3], k = 4
输出: 0
解释:
数组之和为 8,已经可以被 4 整除。因此不需要操作。

示例 3:

输入: nums = [3,2], k = 6
输出: 5
解释:
对 nums[0] = 3 执行 3 次操作,对 nums[1] = 2 执行 2 次操作。现在 nums = [0, 0]。
数组之和为 0,可以被 6 整除。

说明:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 1000
  • 1 <= k <= 100

思路

返回数组元素和模 k 的余数。

代码


/**
 * @date 2025-11-29 21:53
 */
public class MinOperations3512 {

    public int minOperations(int[] nums, int k) {
        int sum = 0;
        for (int num : nums) {
            sum += num;
        }
        return sum % k;
    }
}

性能

1018.可被5整除的二进制前缀

目标

给定一个二进制数组 nums ( 索引从0开始 )。

我们将 xi 定义为其二进制表示形式为子数组 nums[0..i] (从最高有效位到最低有效位)。

  • 例如,如果 nums =[1,0,1] ,那么 x0 = 1, x1 = 2, 和 x2 = 5。

返回布尔值列表 answer,只有当 xi 可以被 5 整除时,答案 answer[i] 为 true,否则为 false。

示例 1:

输入:nums = [0,1,1]
输出:[true,false,false]
解释:
输入数字为 0, 01, 011;也就是十进制中的 0, 1, 3 。只有第一个数可以被 5 整除,因此 answer[0] 为 true 。

示例 2:

输入:nums = [1,1,1]
输出:[false,false,false]

说明:

  • 1 <= nums.length <= 10^5
  • nums[i] 仅为 0 或 1

思路

有一个二进制数组 nums,定义 xi 为二进制表示为 子数组 [0, i] 的数字,判断 x0 ~ x_(n-1) 能否被 5 整除。

模拟存在的问题是左移多次会溢出。假设 num = k * 5 + mod,左移 1 位相当于乘以 22 * num = k * 10 + 2 * mod,能否被 5 整除只需考虑 2 * mod | nums[i]

代码


/**
 * @date 2025-11-24 8:52
 */
public class PrefixesDivBy5_1018 {

    public List<Boolean> prefixesDivBy5_v1(int[] nums) {
        List<Boolean> res = new ArrayList<>();
        int mod = 0;
        for (int num : nums) {
            mod = (mod << 1) % 5 + num;
            res.add(mod % 5 == 0);
        }
        return res;
    }

}

性能

3190.使所有元素都可以被3整除的最少操作数

目标

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

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

示例 1:

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

示例 2:

输入:nums = [3,6,9]
输出:0

说明:

1 <= nums.length <= 50
1 <= nums[i] <= 50

思路

统计数组中不能被 3 整除的元素个数。

代码


/**
 * @date 2025-11-22 2:02
 */
public class MinimumOperations3190 {

    public int minimumOperations(int[] nums) {
        int res = 0;
        for (int num : nums) {
            if (num % 3 != 0){
                res++;
            }
        }
        return res;
    }
}

性能

2154.将找到的值乘以2

目标

给你一个整数数组 nums ,另给你一个整数 original ,这是需要在 nums 中搜索的第一个数字。

接下来,你需要按下述步骤操作:

  1. 如果在 nums 中找到 original ,将 original 乘以 2 ,得到新 original(即,令 original = 2 * original)。
  2. 否则,停止这一过程。
  3. 只要能在数组中找到新 original ,就对新 original 继续 重复 这一过程。

返回 original 的 最终 值。

示例 1:

输入:nums = [5,3,6,1,12], original = 3
输出:24
解释: 
- 3 能在 nums 中找到。3 * 2 = 6 。
- 6 能在 nums 中找到。6 * 2 = 12 。
- 12 能在 nums 中找到。12 * 2 = 24 。
- 24 不能在 nums 中找到。因此,返回 24 。

示例 2:

输入:nums = [2,7,9], original = 4
输出:4
解释:
- 4 不能在 nums 中找到。因此,返回 4 。

说明:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i], original <= 1000

思路

有一个数组 nums 和一个整数 original,如果数组中存在 original,可以执行操作将 original 变为 2 * original,重复执行直到无法继续为止,返回 original 的最终值。

需要反复地判断 original 是否在数组中,可以将数组放入哈希表,然后从小到大模拟操作过程。

代码


/**
 * @date 2025-11-19 8:46
 */
public class FindFinalValue2154 {

    public int findFinalValue(int[] nums, int original) {
        Set<Integer> set = new HashSet<>();
        for (int num : nums) {
            set.add(num);
        }
        while (true) {
            if (set.contains(original)) {
                original *= 2;
            } else {
                return original;
            }
        }
    }

}

性能

717.1比特与2比特字符

目标

有两种特殊字符:

  • 第一种字符可以用一比特 0 表示
  • 第二种字符可以用两比特(10 或 11)表示

给你一个以 0 结尾的二进制数组 bits ,如果最后一个字符必须是一个一比特字符,则返回 true 。

示例 1:

输入: bits = [1, 0, 0]
输出: true
解释: 唯一的解码方式是将其解析为一个两比特字符和一个一比特字符。
所以最后一个字符是一比特字符。

示例 2:

输入:bits = [1,1,1,0]
输出:false
解释:唯一的解码方式是将其解析为两比特字符和两比特字符。
所以最后一个字符不是一比特字符。

说明:

  • 1 <= bits.length <= 1000
  • bits[i] 为 0 或 1

思路

有一个二进制数组 bits 最后一个元素是 0,其中 1011 表示一个 2 比特字符, 0 表示一个 1 比特字符,判断二进制数组的最后一个 0 是否只能解码为 1 比特字符。

实际上就是判断将数组最后一个 0 去掉之后能否解码。由于 0 可以单独解码,遇到 1 一定要与后面一个元素结合。按照这个策略,只需判断是否剩下倒数第二个元素待解码且该元素是 1

代码


/**
 * @date 2025-11-18 8:55
 */
public class IsOneBitCharacter717 {

    public boolean isOneBitCharacter(int[] bits) {
        int n = bits.length;
        int i = 0;
        while (i < n - 1) {
            if (bits[i] == 0) {
                i++;
            } else if (i == n - 2) {
                return false;
            } else {
                i += 2;
            }
        }
        return true;
    }
}

性能

1437.是否所有1都至少相隔k个元素

目标

给你一个由若干 0 和 1 组成的数组 nums 以及整数 k。如果所有 1 都至少相隔 k 个元素,则返回 true ;否则,返回 false 。

示例 1:

输入:nums = [1,0,0,0,1,0,0,1], k = 2
输出:true
解释:每个 1 都至少相隔 2 个元素。

示例 2:

输入:nums = [1,0,0,1,0,1], k = 2
输出:false
解释:第二个 1 和第三个 1 之间只隔了 1 个元素。

提示:

  • 1 <= nums.length <= 10^5
  • 0 <= k <= nums.length
  • nums[i] 的值为 0 或 1

思路

有一个二进制数组 nums,判断是否所有 1 都至少间隔 k 个元素。

要使所有 1 都至少间隔 k 个元素,只需保证相邻的 1 间隔 k 个元素。记录上一个 1 的下标 prev,如果遇到 1 那么它们间隔元素的个数为 i - prev - 1。注意 prev 的初始化,要保证遇到第一个 1 时间隔大于等于 k

代码


/**
 * @date 2025-11-17 8:53
 */
public class KLengthApart1437 {

    public boolean kLengthApart(int[] nums, int k) {
        int n = nums.length;
        int prev = -k - 1;
        for (int i = 0; i < n; i++) {
            if (nums[i] == 0) {
                continue;
            }
            if (i - prev - 1 < k) {
                return false;
            }
            prev = i;
        }
        return true;
    }

}

性能