返回

C/C++ 2317. 操作后的最大异或和:充分利用数学原理,轻松高效解决!

后端

题目

给定一个由非负整数组成的数组 nums 和一个正整数 k,您需要执行以下操作任意次:

  1. 选择一个整数 i,其中 0 <= i < nums.length,并令 nums[i] = nums[i] xor k
  2. 移除数组 nums 中的所有零元素。

您的目标是让剩余的数组元素的最大异或和尽可能大。

请返回您能得到的最大的异或和。

注意:

  • 1 <= nums.length <= 500
  • 0 <= nums[i], k <= 10^5

题目整理

  • 输入 :非负整数数组 nums 和正整数 k
  • 输出 :剩余数组元素的最大异或和。
  • 约束条件
    • 1 <= nums.length <= 500
    • 0 <= nums[i], k <= 10^5

解题思路

异或和的性质

为了解决该问题,我们需要了解异或和的一些性质:

  • 异或和的结合律和交换律:对于任意整数 abc,有 (a xor b) xor c = a xor (b xor c)a xor b = b xor a
  • 异或和的幂等律:对于任意整数 a,有 a xor a = 0
  • 异或和的逆元:对于任意非零整数 a,存在唯一的整数 b,使得 a xor b = 0,我们称 ba 的异或和的逆元。

贪心算法

基于异或和的性质,我们可以使用贪心算法来解决该问题:

  1. nums 数组中的所有元素按从大到小的顺序排序。
  2. 对于数组中的每个元素 nums[i]
    • 如果 nums[i] 的异或和逆元 b 存在于数组中,则将 nums[i]b 从数组中移除。
    • 否则,将 nums[i]k 进行异或运算,得到 nums[i] xor k,并将其添加到数组中。

重复步骤 2,直到数组中只剩下一个元素或数组为空。此时,数组中剩下的元素就是能得到的最大异或和。

动态规划

我们也可以使用动态规划来解决该问题:

  1. 定义状态 dp[i][j] 为在考虑数组 nums 的前 i 个元素时,最大异或和为 j 的方案数。
  2. 初始化 dp[0][0] = 1,其他 dp[i][j] = 0
  3. 对于数组中的每个元素 nums[i]
    • 对于每个可能的异或和 j
      • 如果 nums[i] 的异或和逆元 b 存在于数组中,并且 j xor b 也存在于数组中,则 dp[i][j] += dp[i - 1][j xor b]
      • 否则,dp[i][j xor nums[i]] += dp[i - 1][j]

最终,dp[nums.length][k] 的值就是能得到的最大异或和的方案数。

实现和代码

C++ 实现

#include <algorithm>
#include <vector>

using namespace std;

class Solution {
public:
    int maxResult(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end(), greater<int>());

        int n = nums.size();
        vector<int> dp(100001, 0);
        dp[0] = 1;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= 100000; j++) {
                if (dp[j]) {
                    int b = j ^ nums[i];
                    if (b >= 0 && b <= 100000) {
                        dp[j ^ nums[i]] += dp[j];
                    }
                    dp[j xor k] += dp[j];
                }
            }
        }

        int maxXor = 0;
        for (int i = 0; i <= 100000; i++) {
            if (dp[i] > 0) {
                maxXor = max(maxXor, i);
            }
        }

        return maxXor;
    }
};

Java 实现

import java.util.Arrays;

class Solution {
    public int maxResult(int[] nums, int k) {
        int n = nums.length;
        int[] dp = new int[n];
        dp[0] = nums[0];

        for (int i = 1; i < n; i++) {
            for (int j = i - 1; j >= 0 && j >= i - k; j--) {
                dp[i] = Math.max(dp[i], dp[j] ^ nums[i]);
            }
        }

        return dp[n - 1];
    }
}

复杂度分析

  • 时间复杂度
    • 贪心算法的时间复杂度为 O(n log n),其中 n 是数组 nums 的长度。
    • 动态规划的时间复杂度为 O(n * k),其中 n 是数组 nums 的长度,k 是正整数 k 的值。
  • 空间复杂度
    • 贪心算法的空间复杂度为 O(n),其中 n 是数组 nums 的长度。
    • 动态规划的空间复杂度为 O(n * k),其中 n 是数组 nums 的长度,k 是正整数 k 的值。