Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1787. Make the XOR of All Segments Equal to Zero - Leetcode Solution

Code Implementation

class Solution:
    def minChanges(self, arr, k):
        from collections import Counter, defaultdict

        n = len(arr)
        MAXX = 1 << 10  # 2^10 = 1024, since arr[i] <= 2*10^4
        dp = [float('inf')] * MAXX
        dp[0] = 0

        for i in range(k):
            count = Counter()
            j = i
            total = 0
            while j < n:
                count[arr[j]] += 1
                total += 1
                j += k
            ndp = [float('inf')] * MAXX
            most = max(count.values())
            for x in range(MAXX):
                for v in count:
                    ndp[x] = min(ndp[x], dp[x ^ v] + total - count[v])
            dp = ndp
        return dp[0]
      
class Solution {
public:
    int minChanges(vector<int>& arr, int k) {
        int n = arr.size();
        int MAXX = 1 << 10;
        vector<int> dp(MAXX, 1e9);
        dp[0] = 0;

        for (int i = 0; i < k; ++i) {
            unordered_map<int, int> count;
            int total = 0;
            for (int j = i; j < n; j += k) {
                count[arr[j]]++;
                total++;
            }
            vector<int> ndp(MAXX, 1e9);
            for (int x = 0; x < MAXX; ++x) {
                for (auto& [v, c] : count) {
                    ndp[x] = min(ndp[x], dp[x ^ v] + total - c);
                }
            }
            dp = ndp;
        }
        return dp[0];
    }
};
      
class Solution {
    public int minChanges(int[] arr, int k) {
        int n = arr.length;
        int MAXX = 1 << 10;
        int[] dp = new int[MAXX];
        Arrays.fill(dp, Integer.MAX_VALUE / 2);
        dp[0] = 0;

        for (int i = 0; i < k; ++i) {
            Map<Integer, Integer> count = new HashMap<>();
            int total = 0;
            for (int j = i; j < n; j += k) {
                count.put(arr[j], count.getOrDefault(arr[j], 0) + 1);
                total++;
            }
            int[] ndp = new int[MAXX];
            Arrays.fill(ndp, Integer.MAX_VALUE / 2);
            for (int x = 0; x < MAXX; ++x) {
                for (int v : count.keySet()) {
                    ndp[x] = Math.min(ndp[x], dp[x ^ v] + total - count.get(v));
                }
            }
            dp = ndp;
        }
        return dp[0];
    }
}
      
var minChanges = function(arr, k) {
    const n = arr.length;
    const MAXX = 1 << 10;
    let dp = new Array(MAXX).fill(Infinity);
    dp[0] = 0;

    for (let i = 0; i < k; ++i) {
        let count = new Map();
        let total = 0;
        for (let j = i; j < n; j += k) {
            count.set(arr[j], (count.get(arr[j]) || 0) + 1);
            total++;
        }
        let ndp = new Array(MAXX).fill(Infinity);
        for (let x = 0; x < MAXX; ++x) {
            for (let [v, c] of count.entries()) {
                ndp[x] = Math.min(ndp[x], dp[x ^ v] + total - c);
            }
        }
        dp = ndp;
    }
    return dp[0];
};
      

Problem Description

You are given an array arr of integers and an integer k. Partition arr into k groups, where the i-th group contains all elements whose indices satisfy index % k == i. For each group, you can change any element to any integer you want (even to previously unused values). Your goal is to make the XOR of all elements in each group (after changes) such that the XOR of the entire array is zero.

Return the minimum number of changes needed to achieve this.

  • Each element of arr can be changed independently.
  • You do not need to preserve the original elements.
  • There is always at least one valid solution.

Thought Process

At first glance, the problem seems to be about brute-forcing all possible ways to change elements so that the overall XOR is zero. But since each group can be changed independently, and the number of possibilities grows exponentially with the size of the array, brute force is impractical.

Instead, we realize that the key constraint is on the final XOR of the entire array. Since we can change any element, we want to minimize the changes needed in each group to achieve a global XOR of zero. If we can, for each group, keep as many elements as possible unchanged (i.e., pick the most frequent element in each group), we minimize the number of changes.

The main challenge is to assign values to each group such that the XOR of group values is zero, and the values match as many original elements as possible in their groups. This is a classic dynamic programming problem where we track possible XORs as we process each group.

Solution Approach

  • Step 1: For each group (based on i % k), count the frequency of each number.
  • Step 2: Use dynamic programming (dp), where dp[x] is the minimum number of changes needed so that the XOR of the processed groups so far is x.
  • Step 3: For each group, try all possible values that could be assigned to that group. For each possible previous XOR, update the DP for the new XOR (previous XOR ^ new value), adding the number of changes needed (i.e., group size minus frequency of chosen value).
  • Step 4: After processing all groups, dp[0] gives the answer, since we want the overall XOR to be zero.
  • Step 5: Since numbers can be up to 2*104, but XOR only depends on the lower 10 bits (because of constraints), we can limit our DP array size to 1024 (210).
  • Why this works: For each group, we are free to choose any value, so we pick the value that minimizes changes. The DP ensures that the XOR constraint is maintained globally.

Example Walkthrough

Input: arr = [1,2,0,3,0], k = 1

  • All elements are in a single group.
  • Count frequency: {0:2, 1:1, 2:1, 3:1}
  • We want to pick a value for the whole group so that the XOR is zero.
  • Try all possible values (since group size is small):
    • If we pick 0 for all, XOR is 0, changes needed: 3 (change 1,2,3 to 0)
    • If we pick 1 for all, XOR is 1, changes needed: 4
    • ...so on.
  • Best is to pick 0 for all, with 3 changes.
  • Output: 3

For k=2, groups are [1,0,0] and [2,3]. We repeat the process for each group, updating the DP table at each step.

Time and Space Complexity

  • Brute-force: Would be O((maxValue)k), since for each group we could try all possible assignments. This is not feasible for large arrays.
  • Optimized DP: For each of k groups, for each possible XOR (up to 1024), and for each unique value in the group (up to group size), we update the DP. So the time complexity is O(k * 1024 * groupSize), which is manageable.
  • Space Complexity: O(1024) for the DP array.

Summary

The problem leverages dynamic programming to efficiently assign values to groups so that the overall XOR is zero, while minimizing changes. By grouping elements by index modulo k and using frequency counts, we limit the number of changes needed. The use of a DP array indexed by possible XOR values is the key insight, making the solution both elegant and efficient.