Problem#
You are given two integer arrays nums1
and nums2
of length n
.
The XOR sum of the two integer arrays is (nums1[0] XOR nums2[0]) + (nums1[1] XOR nums2[1]) + ... + (nums1[n - 1] XOR nums2[n - 1])
(0-indexed ).
For example, the XOR sum of [1,2,3]
and [3,2,1]
is equal to (1 XOR 3) + (2 XOR 2) + (3 XOR 1) = 2 + 0 + 2 = 4
.
Rearrange the elements of nums2
such that the resulting XOR sum is
minimized .
Return theXOR sum after the rearrangement .
Examples#
Example 1#
1
2
3
4
Input: nums1 = [ 1 , 2 ], nums2 = [ 2 , 3 ]
Output: 2
Explanation: Rearrange nums2 so that it becomes [ 3 , 2 ].
The XOR sum is ( 1 XOR 3 ) + ( 2 XOR 2 ) = 2 + 0 = 2.
Example 2#
1
2
3
4
Input: nums1 = [ 1 , 0 , 3 ], nums2 = [ 5 , 3 , 4 ]
Output: 8
Explanation: Rearrange nums2 so that it becomes [ 5 , 4 , 3 ].
The XOR sum is ( 1 XOR 5 ) + ( 0 XOR 4 ) + ( 3 XOR 3 ) = 4 + 4 + 0 = 8.
Constraints#
n == nums1.length
n == nums2.length
1 <= n <= 14
0 <= nums1[i], nums2[i] <= 10^7
Solution#
Method 1 – Bitmask Dynamic Programming#
Intuition#
This problem is a variant of the assignment problem, where we want to pair each element in nums1
with a unique element in nums2
to minimize the total XOR sum. Since n is small (≤ 14), we can use bitmask DP to efficiently try all possible assignments.
Approach#
Use a DP array where dp[mask]
is the minimum XOR sum for a given assignment mask.
For each state, try assigning the next nums1
element to every unused nums2
element.
Use recursion with memoization to avoid recomputation.
The answer is dp[0]
(no elements assigned yet).
Code#
Cpp
Go
Java
Kotlin
Python
Rust
Typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public :
int minimumXORSum(vector< int >& nums1, vector< int >& nums2) {
int n = nums1.size();
vector< int > dp(1 << n, INT_MAX);
dp[0 ] = 0 ;
for (int mask = 0 ; mask < (1 << n); ++ mask) {
int i = __builtin_popcount(mask);
for (int j = 0 ; j < n; ++ j) {
if (! (mask & (1 << j))) {
int next = mask | (1 << j);
dp[next] = min(dp[next], dp[mask] + (nums1[i] ^ nums2[j]));
}
}
}
return dp[(1 << n) - 1 ];
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func MinimumXORSum (nums1 , nums2 []int ) int {
n := len(nums1 )
dp := make([]int , 1 << n )
for i := range dp {
dp [i ] = 1 << 31 - 1
}
dp [0 ] = 0
for mask := 0 ; mask < 1 << n ; mask ++ {
i := bits .OnesCount (uint(mask ))
for j := 0 ; j < n ; j ++ {
if mask & (1 << j ) == 0 {
next := mask | (1 << j )
if dp [next ] > dp [mask ]+ (nums1 [i ]^nums2 [j ]) {
dp [next ] = dp [mask ] + (nums1 [i ] ^ nums2 [j ])
}
}
}
}
return dp [(1 << n )- 1 ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public int minimumXORSum (int [] nums1, int [] nums2) {
int n = nums1.length ;
int [] dp = new int [ 1 << n] ;
Arrays.fill (dp, Integer.MAX_VALUE );
dp[ 0] = 0;
for (int mask = 0; mask < (1 << n); mask++ ) {
int i = Integer.bitCount (mask);
for (int j = 0; j < n; j++ ) {
if ((mask & (1 << j)) == 0) {
int next = mask | (1 << j);
dp[ next] = Math.min (dp[ next] , dp[ mask] + (nums1[ i] ^ nums2[ j] ));
}
}
}
return dp[ (1 << n) - 1] ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
fun minimumXORSum (nums1: IntArray, nums2: IntArray): Int {
val n = nums1.size
val dp = IntArray(1 shl n) { Int .MAX_VALUE }
dp[0 ] = 0
for (mask in 0 until (1 shl n)) {
val i = mask.countOneBits()
for (j in 0 until n) {
if (mask and (1 shl j) == 0 ) {
val next = mask or (1 shl j)
dp[next] = minOf(dp[next], dp[mask] + (nums1[i] xor nums2[j]))
}
}
}
return dp[(1 shl n) - 1 ]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
from typing import List
class Solution :
def minimumXORSum (self, nums1: List[int], nums2: List[int]) -> int:
n = len(nums1)
dp = [float('inf' )] * (1 << n)
dp[0 ] = 0
for mask in range(1 << n):
i = bin(mask). count('1' )
for j in range(n):
if not (mask & (1 << j)):
next_mask = mask | (1 << j)
dp[next_mask] = min(dp[next_mask], dp[mask] + (nums1[i] ^ nums2[j]))
return dp[(1 << n) - 1 ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
impl Solution {
pub fn minimum_xor_sum (nums1: Vec< i32 > , nums2: Vec< i32 > ) -> i32 {
let n = nums1.len();
let mut dp = vec! [i32 ::MAX ; 1 << n];
dp[0 ] = 0 ;
for mask in 0 .. (1 << n) {
let i = mask.count_ones() as usize ;
for j in 0 .. n {
if (mask & (1 << j)) == 0 {
let next = mask | (1 << j);
dp[next] = dp[next].min(dp[mask] + (nums1[i] ^ nums2[j]));
}
}
}
dp[(1 << n) - 1 ]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
minimumXORSum (nums1 : number [], nums2 : number []): number {
const n = nums1 .length ;
const dp = Array(1 << n ).fill (Number.POSITIVE_INFINITY );
dp [0 ] = 0 ;
for (let mask = 0 ; mask < (1 << n ); mask ++ ) {
const i = mask .toString (2 ).split ('1' ).length - 1 ;
for (let j = 0 ; j < n ; j ++ ) {
if ((mask & (1 << j )) === 0 ) {
const next = mask | (1 << j );
dp [next ] = Math.min (dp [next ], dp [mask ] + (nums1 [i ] ^ nums2 [j ]));
}
}
}
return dp [(1 << n ) - 1 ];
}
}
Complexity#
⏰ Time complexity: O(n^2 * 2^n)
— There are 2^n
states and for each state up to n
transitions.
🧺 Space complexity: O(2^n)
— The DP array stores results for each mask.