3227.字符串元音游戏

目标

小红和小明在玩一个字符串元音游戏。

给你一个字符串 s,小红和小明将轮流参与游戏,小红 先 开始:

  • 在小红的回合,她必须移除 s 中包含 奇数 个元音的任意 非空 子字符串。
  • 在小明的回合,他必须移除 s 中包含 偶数 个元音的任意 非空 子字符串。

第一个无法在其回合内进行移除操作的玩家输掉游戏。假设小红和小明都采取 最优策略 。

如果小红赢得游戏,返回 true,否则返回 false。

英文元音字母包括:a, e, i, o, 和 u。

示例 1:

输入: s = "leetcoder"
输出: true
解释:
小红可以执行如下移除操作来赢得游戏:
小红先手,她可以移除加下划线的子字符串 s = "leetcoder",其中包含 3 个元音。结果字符串为 s = "der"。
小明接着,他可以移除加下划线的子字符串 s = "der",其中包含 0 个元音。结果字符串为 s = "er"。
小红再次操作,她可以移除整个字符串 s = "er",其中包含 1 个元音。
又轮到小明,由于字符串为空,无法执行移除操作,因此小红赢得游戏。

示例 2:

输入: s = "bbcd"
输出: false
解释:
小红在她的第一回合无法执行移除操作,因此小红输掉了游戏。

说明:

  • 1 <= s.length <= 10^5
  • s 仅由小写英文字母组成。

思路

小红与小明在玩字符串元音游戏,小红的回合必须移除包含 奇数 个元音的任意非空子串,小明的回合必须移除包含 偶数 个元音的任意非空子串。如果无法完成操作则输掉游戏,假设小红和小明都采取最优策略,判断小红能否赢得游戏。

如果字符串中包含奇数个元音字符,小红必定获胜。否则,小红应该移除最大的奇数个元音字符,这时剩余一个元音字符,小明只能删除不含元音字符的子串,这时小红将剩余的子串全部删掉,就赢得了游戏。

因此只要字符包含元音字符,小红必定获胜。

代码


/**
 * @date 2025-09-12 8:43
 */
public class DoesAliceWin3227 {

    public boolean doesAliceWin(String s) {
        char[] chars = s.toCharArray();
        for (char c : chars) {
            if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
                return true;
            }
        }
        return false;
    }
}

性能

2749.得到整数零需要执行的最少操作数

目标

给你两个整数:num1 和 num2 。

在一步操作中,你需要从范围 [0, 60] 中选出一个整数 i ,并从 num1 减去 2^i + num2 。

请你计算,要想使 num1 等于 0 需要执行的最少操作数,并以整数形式返回。

如果无法使 num1 等于 0 ,返回 -1 。

示例 1:

输入:num1 = 3, num2 = -2
输出:3
解释:可以执行下述步骤使 3 等于 0 :
- 选择 i = 2 ,并从 3 减去 2^2 + (-2) ,num1 = 3 - (4 + (-2)) = 1 。
- 选择 i = 2 ,并从 1 减去 2^2 + (-2) ,num1 = 1 - (4 + (-2)) = -1 。
- 选择 i = 0 ,并从 -1 减去 2^0 + (-2) ,num1 = (-1) - (1 + (-2)) = 0 。
可以证明 3 是需要执行的最少操作数。

示例 2:

输入:num1 = 5, num2 = 7
输出:-1
解释:可以证明,执行操作无法使 5 等于 0 。

说明:

  • 1 <= num1 <= 10^9
  • -10^9 <= num2 <= 10^9

思路

已知整数 num1num2,每次操作需要从 0 ~ 60 选一个整数 i,并将 num1 -= 2^i + num2,返回将 num1 变为 0 的最小操作次数,如果无法完成返回 -1

假设最少需要操作 k 次,那么 num1 - k * num2 = 2^i1 + 2^i2 + …… + 2^ik,其中 ik 表示第 k 次选择的 i

问题转换为 num1 - k * num2 能否用 k2 的幂表示。

二进制中 1 的个数就是最少的 k 的个数,它自身的值就是最多可以拆分的个数 ,也就是说 num = num1 - k * num2 的二进制表示中 1 的个数应小于等于 k 并且 num >= k

代码


/**
 * @date 2025-09-05 8:46
 */
public class MakeTheIntegerZero2749 {

    public int makeTheIntegerZero(int num1, int num2) {
        for (int i = 0; i < 61; i++) {
            long num = num1 - (long) i * num2;
            if (num <= 0) {
                return -1;
            } else if (Long.bitCount(num) <= i && num >= i) {
                return i;
            }
        }
        return -1;
    }

}

性能

2419.按位与最大的最长子数组

目标

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

考虑 nums 中进行 按位与(bitwise AND)运算得到的值 最大 的 非空 子数组。

  • 换句话说,令 k 是 nums 任意 子数组执行按位与运算所能得到的最大值。那么,只需要考虑那些执行一次按位与运算后等于 k 的子数组。

返回满足要求的 最长 子数组的长度。

数组的按位与就是对数组中的所有数字进行按位与运算。

子数组 是数组中的一个连续元素序列。

示例 1:

输入:nums = [1,2,3,3,2,2]
输出:2
解释:
子数组按位与运算的最大值是 3 。
能得到此结果的最长子数组是 [3,3],所以返回 2 。

示例 2:

输入:nums = [1,2,3,4]
输出:1
解释:
子数组按位与运算的最大值是 4 。
能得到此结果的最长子数组是 [4],所以返回 1 。

说明:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^6

思路

两个数按位与的结果一定不会比这两个数更大。问题转化为连续的最大值长度。

代码


/**
 * @date 2025-07-30 10:28
 */
public class LongestSubarray2419 {

    public int longestSubarray(int[] nums) {
        int n = nums.length;
        int max = Arrays.stream(nums).max().getAsInt();
        int res = 1;
        int i = 0;
        while (i < n){
            int l = 0;
            while (i < n && nums[i++] == max){
                l++;
            }
            res = Math.max(res, l);
        }
        return res;
    }
}

性能

2712.使所有字符相等的最小成本

目标

给你一个下标从 0 开始、长度为 n 的二进制字符串 s ,你可以对其执行两种操作:

  • 选中一个下标 i 并且反转从下标 0 到下标 i(包括下标 0 和下标 i )的所有字符,成本为 i + 1 。
  • 选中一个下标 i 并且反转从下标 i 到下标 n - 1(包括下标 i 和下标 n - 1 )的所有字符,成本为 n - i 。

返回使字符串内所有字符 相等 需要的 最小成本 。

反转 字符意味着:如果原来的值是 '0' ,则反转后值变为 '1' ,反之亦然。

示例 1:

输入:s = "0011"
输出:2
解释:执行第二种操作,选中下标 i = 2 ,可以得到 s = "0000" ,成本为 2 。可以证明 2 是使所有字符相等的最小成本。

示例 2:

输入:s = "010101"
输出:9
解释:执行第一种操作,选中下标 i = 2 ,可以得到 s = "101101" ,成本为 3 。
执行第一种操作,选中下标 i = 1 ,可以得到 s = "011101" ,成本为 2 。
执行第一种操作,选中下标 i = 0 ,可以得到 s = "111101" ,成本为 1 。
执行第二种操作,选中下标 i = 4 ,可以得到 s = "111110" ,成本为 2 。
执行第二种操作,选中下标 i = 5 ,可以得到 s = "111111" ,成本为 1 。
使所有字符相等的总成本等于 9 。可以证明 9 是使所有字符相等的最小成本。 

说明:

  • 1 <= s.length == n <= 10^5
  • s[i] 为 '0' 或 '1'

思路

有一个二进制字符串,每次操作可以反转前缀 0 ~ i,成本是 i + 1,也可以反转后缀 i ~ n - 1,成本是 n - i。求使字符串所有字符相等的最小成本。

如何操作才能使字符相等?相等字符是 0 还是 1?操作哪边才能使成本最小?

关键点是想清楚与是 0 还是 1 没有关系,只要相邻的元素值不同,就必须要反转,无非是考虑反转前缀还是后缀,每次操作只影响相邻的元素关系。

代码


/**
 * @date 2025-03-27 1:33
 */
public class MinimumCost2712 {

    public long minimumCost(String s) {
        int n = s.length();
        long res = 0;
        for (int i = 1; i < n; i++) {
            if (s.charAt(i) != s.charAt(i - 1)) {
                // i 表示反转 0 ~ i - 1,n - i 表示反转 i ~ n - 1
                res += Math.min(i, n - i);
            }
        }
        return res;
    }
}

性能