3876.构造奇偶一致的数组II

目标

给你一个长度为 n 的数组 nums1,其中包含 互不相同 的整数。

你需要构造另一个长度为 n 的数组 nums2,使得 nums2 中的元素要么全部为 奇数,要么全部为 偶数。

对于每个下标 i,你必须从以下两种选择中 任选其一(顺序不限):

  • nums2[i] = nums1[i]
  • nums2[i] = nums1[i] - nums1[j],其中 j != i,且满足 nums1[i] - nums1[j] >= 1

如果能够构造出满足条件的数组,则返回 true;否则,返回 false。

示例 1:

输入: nums1 = [1,4,7]
输出: true
解释:
设置 nums2[0] = nums1[0] = 1。
设置 nums2[1] = nums1[1] - nums1[0] = 4 - 1 = 3。
设置 nums2[2] = nums1[2] = 7。
nums2 = [1, 3, 7],所有元素均为奇数。因此答案为 true。

示例 2:

输入: nums1 = [2,3]
输出: false
解释:
无法构造出满足所有元素奇偶性相同的 nums2。因此答案为 false。

示例 3:

输入: nums1 = [4,6]
输出: true
解释:
设置 nums2[0] = nums1[0] = 4。
设置 nums2[1] = nums1[1] = 6。
nums2 = [4, 6],所有元素均为偶数。因此答案为 true。

说明:

  • 1 <= n == nums1.length <= 10^5
  • 1 <= nums1[i] <= 10^9
  • nums1 中的所有整数互不相同。

思路

有一个元素互不相同的整数数组 nums1,问能否构造另一个相同长度的数组 nums2nums2[i] = nums1[i] 或者 nums2[i] = nums1[i] - nums1[j],其中 j != i && nums1[i] - nums1[j] >= 1。使得 nums2 中的元素全为 奇数偶数

本题加了一个限制,只能减去比自身小的数。减去一个偶数不会改变奇偶性,还得考虑奇数。

如果全为奇数或偶数返回 true,枚举奇数与偶数的最小值,如果奇数最小值小于偶数最小值则返回 true

代码


/**
 * @date 2026-09-03 10:08
 */
public class UniformArray3876 {

    public boolean uniformArray(int[] nums1) {
        int oddMin = Integer.MAX_VALUE;
        int evenMin = Integer.MAX_VALUE;
        for (int num : nums1) {
            if (num % 2 == 0) {
                evenMin = Math.min(num, evenMin);
            } else {
                oddMin = Math.min(num, oddMin);
            }
        }
        if (oddMin == Integer.MAX_VALUE || evenMin == Integer.MAX_VALUE) {
            return true;
        }
        return oddMin < evenMin;
    }
}

性能

3875.构造奇偶一致的数组I

目标

给你一个长度为 n 的数组 nums1,其中包含 互不相同 的整数。

你需要构造另一个长度为 n 的数组 nums2,使得 nums2 中的元素要么全部为 奇数,要么全部为 偶数。

对于每个下标 i,你必须从以下两种选择中 任选其一(顺序不限):

  • nums2[i] = nums1[i]
  • nums2[i] = nums1[i] - nums1[j],其中 j != i

如果能够构造出满足条件的数组,则返回 true;否则,返回 false。

示例 1:

输入: nums1 = [2,3]
输出: true
解释:
    选择 nums2[0] = nums1[0] - nums1[1] = 2 - 3 = -1。
    选择 nums2[1] = nums1[1] = 3。
    nums2 = [-1, 3],两个元素均为奇数。因此答案为 true。

示例 2:

输入: nums1 = [4,6]
输出: true
解释:​​​​​​​
    选择 nums2[0] = nums1[0] = 4。
    选择 nums2[1] = nums1[1] = 6。
    nums2 = [4, 6],两个元素均为偶数。因此答案为 true。

说明:

  • 1 <= n == nums1.length <= 100
  • 1 <= nums1[i] <= 100
  • nums1 中的所有整数互不相同。

思路

有一个元素互不相同的整数数组 nums1,问能否构造另一个相同长度的数组 nums2nums2[i] = nums1[i] 或者 nums2[i] = nums1[i] - nums1[j],其中 j != i。使得 nums2 中的元素全为 奇数偶数

如果数组元素均为奇数/偶数直接满足条件,否则,可以将偶数减去任意奇数,使得整个数组变为奇数。直接返回 true 即可。

代码


/**
 * @date 2026-09-02 9:17
 */
public class UniformArray3875 {

    public boolean uniformArray(int[] nums1) {
        return true;
    }
}

性能

877.石子游戏

目标

Alice 和 Bob 用几堆石子在做游戏。一共有偶数堆石子,排成一行;每堆都有 正 整数颗石子,数目为 piles[i] 。

游戏以谁手中的石子最多来决出胜负。石子的 总数 是 奇数 ,所以没有平局。

Alice 和 Bob 轮流进行,Alice 先开始 。 每回合,玩家从行的 开始 或 结束 处取走整堆石头。 这种情况一直持续到没有更多的石子堆为止,此时手中 石子最多 的玩家 获胜 。

假设 Alice 和 Bob 都发挥出最佳水平,当 Alice 赢得比赛时返回 true ,当 Bob 赢得比赛时返回 false 。

示例 1:

输入:piles = [5,3,4,5]
输出:true
解释:
Alice 先开始,只能拿前 5 颗或后 5 颗石子 。
假设他取了前 5 颗,这一行就变成了 [3,4,5] 。
如果 Bob 拿走前 3 颗,那么剩下的是 [4,5],Alice 拿走后 5 颗赢得 10 分。
如果 Bob 拿走后 5 颗,那么剩下的是 [3,4],Alice 拿走后 4 颗赢得 9 分。
这表明,取前 5 颗石子对 Alice 来说是一个胜利的举动,所以返回 true 。

示例 2:

输入:piles = [3,7,2,3]
输出:true

说明:

  • 2 <= piles.length <= 500
  • piles.length 是 偶数
  • 1 <= piles[i] <= 500
  • sum(piles[i]) 是 奇数

思路

有偶数堆石子排成一行,piles[i] 表示第 i 堆石子的数量,石子总数为奇数。从 Alice 开始,与 Bob 轮流取走左侧或右侧的整堆石子,直到取走所有石子堆为止。获得石子最多的玩家获胜。假设 AliceBob 都能做出最优的选择,判断 Alice 能否获胜。

定义 dp[i][j] 表示剩余石堆为 [i, j] 时,先手与后手获得的石子数量之差的最大值。dp[i][j] = max(piles[i] - dp[i + 1][j], piles[j] - dp[i][j - 1])

  • 先手 A 选择 i,剩余问题变成 B 先手 [i + 1, j],而当前问题的先手是 A,剩余问题则是 B - A,应该取相反数。
  • 先手 A 选择 j 同理。

外层倒序遍历,内存正序遍历。因为 i 依赖 i + 1j 依赖 j - 1。初始化 dp[i][i] = pilesp[i]

本题使用了空间优化,当前状态是从下方与左侧转移而来,从右下角到左上对角线开始,从左向右更新。每次状态更新只用到了下方与左侧的值,因此可以使用滚动数组保存下方的值。

先手玩家必定可以获胜,首先石子总数为奇数(不可能平局),奇数堆与偶数堆的石子数量必定不同,先手可以控制自己只选择偶数堆或者奇数堆,因此必胜。

因为开始时首尾的奇偶性不同,偶,……,奇,如果奇数堆的石子更多,那么先手就选奇数堆,这时留给后手的只有首尾的两个偶数下标。

代码


/**
 * @date 2026-08-03 14:45
 */
public class StoneGame877 {

    public boolean stoneGame_v1(int[] piles) {
        return true;
    }

    public boolean stoneGame(int[] piles) {
        int n = piles.length;
        int[] dp = new int[n];
        for (int i = n - 1; i >= 0; i--) {
            dp[i] = piles[i];
            for (int j = i + 1; j < n; j++) {
                dp[j] = Math.max(piles[i] - dp[j], piles[j] - dp[j - 1]);
            }
        }
        return dp[n - 1] > 0;
    }
}

性能

3513.不同 XOR 三元组的数目I

目标

给你一个长度为 n 的整数数组 nums,其中 nums 是范围 [1, n] 内所有数的 排列 。

XOR 三元组 定义为三个元素的异或值 nums[i] XOR nums[j] XOR nums[k],其中 i <= j <= k。

返回所有可能三元组 (i, j, k) 中 不同 的 XOR 值的数量。

排列 是一个集合中所有元素的重新排列。

示例 1:

输入: nums = [1,2]
输出: 2
解释:
所有可能的 XOR 三元组值为:
(0, 0, 0) → 1 XOR 1 XOR 1 = 1
(0, 0, 1) → 1 XOR 1 XOR 2 = 2
(0, 1, 1) → 1 XOR 2 XOR 2 = 1
(1, 1, 1) → 2 XOR 2 XOR 2 = 2
不同的 XOR 值为 {1, 2},因此输出为 2。

示例 2:

输入: nums = [3,1,2]
输出: 4
解释:
可能的 XOR 三元组值包括:
(0, 0, 0) → 3 XOR 3 XOR 3 = 3
(0, 0, 1) → 3 XOR 3 XOR 1 = 1
(0, 0, 2) → 3 XOR 3 XOR 2 = 2
(0, 1, 2) → 3 XOR 1 XOR 2 = 0
不同的 XOR 值为 {0, 1, 2, 3},因此输出为 4。

说明:

  • 1 <= n == nums.length <= 10^5
  • 1 <= nums[i] <= n
  • nums 是从 1 到 n 的整数的一个排列。

思路

有一个 1 ~ n 的排列,从中取三个数(可重复)的异或值 XOR,求不同的 XOR 值有多少个。

可以构造出 0 ~ 2^(k + 1) - 1 之间的任意数字,其中 k 是从右向左的最高位(从 0 开始)。

代码


/**
 * @date 2026-07-23 9:55
 */
public class UniqueXorTriplets3513 {

    public int uniqueXorTriplets(int[] nums) {
        int n = nums.length;
        return n <= 2 ? n : 1 << (32 - Integer.numberOfLeadingZeros(n));
    }
}

性能

3689.最大子数组总值I

目标

给定一个长度为 n 的整数数组 nums 和一个整数 k。

你必须从 nums 中选择 恰好 k 个非空子数组 nums[l..r]。子数组可以重叠,同一个子数组(相同的 l 和 r)可以 被选择超过一次。

子数组 nums[l..r] 的 值 定义为:max(nums[l..r]) - min(nums[l..r])。

总值 是所有被选子数组的 值 之和。

返回你能实现的 最大 可能总值。

子数组 是数组中连续的 非空 元素序列。

示例 1:

输入: nums = [1,3,2], k = 2
输出: 4
解释:
一种最优的方法是:
选择 nums[0..1] = [1, 3]。最大值为 3,最小值为 1,得到的值为 3 - 1 = 2。
选择 nums[0..2] = [1, 3, 2]。最大值仍为 3,最小值仍为 1,所以值也是 3 - 1 = 2。
将它们相加得到 2 + 2 = 4。

示例 2:

输入: nums = [4,2,5,1], k = 3
输出: 12
解释:
一种最优的方法是:
选择 nums[0..3] = [4, 2, 5, 1]。最大值为 5,最小值为 1,得到的值为 5 - 1 = 4。
选择 nums[1..3] = [2, 5, 1]。最大值为 5,最小值为 1,所以值也是 4。
选择 nums[2..3] = [5, 1]。最大值为 5,最小值为 1,所以值同样是 4。
将它们相加得到 4 + 4 + 4 = 12。

说明:

  • 1 <= n == nums.length <= 5 * 10^4
  • 0 <= nums[i] <= 10^9
  • 1 <= k <= 10^5

思路

定义子数组的值是最大值与最小值之差。已知一个长度为 n 的非负整数数组 nums,从中选择 k 个子数组(允许重复选择),求所选子数组的最大总值(即子数组值之和)。

由于可以重复选择,都选区间 [0, n - 1],区间范围越大,最大值越大,最小值越小,差值越大。

代码


/**
 * @date 2026-06-09 9:07
 */
public class MaxTotalValue3689 {

    public long maxTotalValue(int[] nums, int k) {
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int num : nums) {
            max = Math.max(max, num);
            min = Math.min(min, num);
        }
        return (long) (max - min) * k;
    }
}

性能

2078.两栋颜色不同且距离最远的房子

目标

街上有 n 栋房子整齐地排成一列,每栋房子都粉刷上了漂亮的颜色。给你一个下标从 0 开始且长度为 n 的整数数组 colors ,其中 colors[i] 表示第 i 栋房子的颜色。

返回 两栋 颜色 不同 房子之间的 最大 距离。

第 i 栋房子和第 j 栋房子之间的距离是 abs(i - j) ,其中 abs(x) 是 x 的绝对值。

示例 1:

输入:colors = [1,1,1,6,1,1,1]
输出:3
解释:上图中,颜色 1 标识成蓝色,颜色 6 标识成红色。
两栋颜色不同且距离最远的房子是房子 0 和房子 3 。
房子 0 的颜色是颜色 1 ,房子 3 的颜色是颜色 6 。两栋房子之间的距离是 abs(0 - 3) = 3 。
注意,房子 3 和房子 6 也可以产生最佳答案。

示例 2:

输入:colors = [1,8,3,8,3]
输出:4
解释:上图中,颜色 1 标识成蓝色,颜色 8 标识成黄色,颜色 3 标识成绿色。
两栋颜色不同且距离最远的房子是房子 0 和房子 4 。
房子 0 的颜色是颜色 1 ,房子 4 的颜色是颜色 3 。两栋房子之间的距离是 abs(0 - 4) = 4 。

示例 3:

输入:colors = [0,1]
输出:1
解释:两栋颜色不同且距离最远的房子是房子 0 和房子 1 。
房子 0 的颜色是颜色 0 ,房子 1 的颜色是颜色 1 。两栋房子之间的距离是 abs(0 - 1) = 1 。

说明:

  • n == colors.length
  • 2 <= n <= 100
  • 0 <= colors[i] <= 100
  • 生成的测试数据满足 至少 存在 2 栋颜色不同的房子

思路

有一排房子,colors[i] 表示房子 i 的颜色,求不同颜色的房子之间的最远距离。

暴力解法是写一个双重循环,内层从后往前遍历,直到找到第一个不同的颜色下标。

O(n) 的解法是找到不等于首尾颜色的最小与最大下标,想清楚首尾房子一定参与最远距离的计算。如果 colors[0] != colors[n - 1] 直接返回 n - 1,否则,假设首尾的颜色均为 c,找到颜色不为 c 的下标最大值 r 与最小值 l,取 max(r, n - 1 - l)

可以使用反证法证明,假设最远距离 i, j 在中间 0 < i < j < n - 1colors[i] = a, colors[j] = b, colors[0] == colors[n - 1] == c

  • 如果 a != c && b != c,显然 (0, j) 或者 (i, n - 1) 距离更远
  • 如果 a == c && b != c,那么 (0, j) 距离更远
  • 如果 a != c && b == c,那么 (i, n - 1) 更远

代码


/**
 * @date 2026-04-20 8:55
 */
public class MaxDistance2078 {

    public int maxDistance(int[] colors) {
        int n = colors.length;
        int res = 0;
        for (int i = 0; i < n; i++) {
            for (int j = n - 1; j > i; j--) {
                if (colors[i] != colors[j]) {
                    res = Math.max(res, j - i);
                    break;
                }
            }
        }
        return res;
    }
}

性能

2087.网格图中机器人回家的最小代价

目标

给你一个 m x n 的网格图,其中 (0, 0) 是最左上角的格子,(m - 1, n - 1) 是最右下角的格子。给你一个整数数组 startPos ,startPos = [startrow, startcol] 表示 初始 有一个 机器人 在格子 (startrow, startcol) 处。同时给你一个整数数组 homePos ,homePos = [homerow, homecol] 表示机器人的 家 在格子 (homerow, homecol) 处。

机器人需要回家。每一步它可以往四个方向移动:上,下,左,右,同时机器人不能移出边界。每一步移动都有一定代价。再给你两个下标从 0 开始的额整数数组:长度为 m 的数组 rowCosts 和长度为 n 的数组 colCosts 。

  • 如果机器人往 上 或者往 下 移动到第 r 行 的格子,那么代价为 rowCosts[r] 。
  • 如果机器人往 左 或者往 右 移动到第 c 列 的格子,那么代价为 colCosts[c] 。

请你返回机器人回家需要的 最小总代价 。

示例 1:

输入:startPos = [1, 0], homePos = [2, 3], rowCosts = [5, 4, 3], colCosts = [8, 2, 6, 7]
输出:18
解释:一个最优路径为:
从 (1, 0) 开始
-> 往下走到 (2, 0) 。代价为 rowCosts[2] = 3 。
-> 往右走到 (2, 1) 。代价为 colCosts[1] = 2 。
-> 往右走到 (2, 2) 。代价为 colCosts[2] = 6 。
-> 往右走到 (2, 3) 。代价为 colCosts[3] = 7 。
总代价为 3 + 2 + 6 + 7 = 18

示例 2:

输入:startPos = [0, 0], homePos = [0, 0], rowCosts = [5], colCosts = [26]
输出:0
解释:机器人已经在家了,所以不需要移动。总代价为 0 。

说明:

  • m == rowCosts.length
  • n == colCosts.length
  • 1 <= m, n <= 10^5
  • 0 <= rowCosts[r], colCosts[c] <= 10^4
  • startPos.length == 2
  • homePos.length == 2
  • 0 <= startrow, homerow < m
  • 0 <= startcol, homecol < n

思路

有一个 m x n 矩阵,其中有一个机器人在坐标 startPos,机器人家的坐标是 homePos,机器人可以上下左右移动,从上/下移动到第 i 行的成本为 rowCosts[i],从左/右移动到第 j 列的成本为 colCosts[j],求机器人回家需要的最小总代价。

根据题意代价均为非负数,只要不折返代价就是最小的,可以将横向与纵向移动分开考虑,分别计算 startPos[0]homePos[0] 以及 startPos[1]homePos[1] 的代价。

由于起点与家的相对位置是不确定的,循环的步长(+1 还是 -1)、结束条件(大于等于 还是 小于等于)需要动态定义。

网友题解则是直接减掉了起点的代价,统一由小坐标到大坐标累加成本。

代码


/**
 * @date 2026-04-07 11:21
 */
public class MinCost2087 {

    public int minCost(int[] startPos, int[] homePos, int[] rowCosts, int[] colCosts) {
        int res = 0;
        int sx = startPos[0];
        int sy = startPos[1];
        int hx = homePos[0];
        int hy = homePos[1];
        int dx = sx <= hx ? 1 : -1;
        int dy = sy <= hy ? 1 : -1;
        for (int i = sx + dx; dx == 1 ? i <= hx : i >= hx; i += dx) {
            res += rowCosts[i];
        }
        for (int i = sy + dy; dy == 1 ? i <= hy : i >= hy; i += dy) {
            res += colCosts[i];
        }
        return res;
    }

}

性能

1784.检查二进制字符串字段

目标

给你一个二进制字符串 s ,该字符串 不含前导零 。

如果 s 包含 零个或一个由连续的 '1' 组成的字段 ,返回 true​​​ 。否则,返回 false 。

示例 1:

输入:s = "1001"
输出:false
解释:由连续若干个 '1' 组成的字段数量为 2,返回 false

示例 2:

输入:s = "110"
输出:true

说明:

  • 1 <= s.length <= 100
  • s[i] 为 '0' 或 '1'
  • s[0] 为 '1'

思路

有一个 不含前导零 的二进制字符串,判断除了开头连续的 1 之外还有没有其它的 1

即判断是否存在 01 子串。

代码


/**
 * @date 2026-03-06 8:46
 */
public class CheckOnesSegment1784 {

    public boolean checkOnesSegment_v1(String s) {
        return s.indexOf("01") == -1;
    }

}

性能

1689.十-二进制数的最少数目

目标

如果一个十进制数字不含任何前导零,且每一位上的数字不是 0 就是 1 ,那么该数字就是一个 十-二进制数 。例如,101 和 1100 都是 十-二进制数,而 112 和 3001 不是。

给你一个表示十进制整数的字符串 n ,返回和为 n 的 十-二进制数 的最少数目。

示例 1:

输入:n = "32"
输出:3
解释:10 + 11 + 11 = 32

示例 2:

输入:n = "82734"
输出:8

示例 3:

输入:n = "27346209830709182346"
输出:9

说明:

  • 1 <= n.length <= 10^5
  • n 仅由数字组成
  • n 不含任何前导零并总是表示正整数

思路

返回整数 n 中的最大数字即可。

代码


/**
 * @date 2026-04-17 16:06
 */
public class MinPartitions1689 {

    public int minPartitions(String n) {
        int res = 0;
        char[] chars = n.toCharArray();
        for (char c : chars) {
            res = Math.max(res, c - '0');
        }
        return res;
    }
}

性能

1975.最大方阵和

目标

给你一个 n x n 的整数方阵 matrix 。你可以执行以下操作 任意次 :

  • 选择 matrix 中 相邻 两个元素,并将它们都 乘以 -1 。

如果两个元素有 公共边 ,那么它们就是 相邻 的。

你的目的是 最大化 方阵元素的和。请你在执行以上操作之后,返回方阵的 最大 和。

示例 1:

输入:matrix = [[1,-1],[-1,1]]
输出:4
解释:我们可以执行以下操作使和等于 4 :
- 将第一行的 2 个元素乘以 -1 。
- 将第一列的 2 个元素乘以 -1 。

示例 2:

输入:matrix = [[1,2,3],[-1,-2,-3],[1,2,3]]
输出:16
解释:我们可以执行以下操作使和等于 16 :
- 将第二行的最后 2 个元素乘以 -1 。

说明:

  • n == matrix.length == matrix[i].length
  • 2 <= n <= 250
  • -10^5 <= matrix[i][j] <= 10^5

思路

有一个 n x n 矩阵,每次操作可以将相邻的元素乘以 -1,执行操作任意次,求能够得到的最大方阵和。

经过观察发现,可以将任意两个元素乘以 -1,只需对路径上的每个元素执行操作,改变 (cur, next) 的符号,中间每个元素的符号都被改变了两次,即首尾元素改变了符号。

只需判断矩阵中负数的个数,如果是偶数,可以将负数全部变为相反数;如果是奇数,则需要找到最小的非负数,将其变为负数,其余元素全部变为非负数。

代码


/**
 * @date 2026-01-05 9:07
 */
public class MaxMatrixSum1975 {

    public long maxMatrixSum(int[][] matrix) {
        long res = 0L;
        int negativeCnt = 0;
        int min = Integer.MAX_VALUE;
        for (int[] row : matrix) {
            for (int col : row) {
                res += Math.abs(col);
                min = Math.min(min, Math.abs(col));
                if (col < 0) {
                    negativeCnt++;
                }
            }
        }
        if (negativeCnt % 2 == 1) {
            res -= 2 * min;
        }
        return res;
    }

}

性能