Please upgrade to NeetCode Pro to view company tags.
Prerequisites
Before attempting this problem, you should be comfortable with:
Recursion/Backtracking - Used to generate all possible subsets by making include/exclude decisions for each element
XOR Operation - Understanding that XOR is self-inverse (a ^ a = 0) and its bit-level behavior
Bit Manipulation - Bitmasks can represent subsets, and the optimal solution uses OR and bit shifting
1. Backtracking
Intuition
We need to generate all possible subsets and compute the XOR total of each. The standard backtracking approach builds subsets by deciding for each element whether to include it or not. At each step, we compute the XOR of the current subset and add it to our running total.
Algorithm
Initialize res = 0 to accumulate the sum of XOR totals.
Define a backtracking function that takes the current index and the current subset:
Compute the XOR of all elements in the subset and add it to res.
For each remaining element starting from the current index:
Add the element to the subset.
Recursively call backtrack with the next index.
Remove the element from the subset.
Call the backtracking function starting at index0 with an empty subset.
classSolution:defsubsetXORSum(self, nums: List[int])->int:
res =0defbacktrack(i, subset):nonlocal res
xorr =0for num in subset:
xorr ^= num
res += xorr
for j inrange(i,len(nums)):
subset.append(nums[j])
backtrack(j +1, subset)
subset.pop()
backtrack(0,[])return res
classSolution{/**
* @param {number[]} nums
* @return {number}
*/subsetXORSum(nums){let res =0;constbacktrack=(i, subset)=>{let xorr =0;for(let num of subset) xorr ^= num;
res += xorr;for(let j = i; j < nums.length; j++){
subset.push(nums[j]);backtrack(j +1, subset);
subset.pop();}};backtrack(0,[]);return res;}}
publicclassSolution{privateint res =0;publicintSubsetXORSum(int[] nums){Backtrack(0,newList<int>(), nums);return res;}privatevoidBacktrack(int i,List<int> subset,int[] nums){int xorr =0;foreach(int num in subset){
xorr ^= num;}
res += xorr;for(int j = i; j < nums.Length; j++){
subset.Add(nums[j]);Backtrack(j +1, subset, nums);
subset.RemoveAt(subset.Count -1);}}}
funcsubsetXORSum(nums []int)int{
res :=0var backtrack func(i int, subset []int)
backtrack =func(i int, subset []int){
xorr :=0for_, num :=range subset {
xorr ^= num
}
res += xorr
for j := i; j <len(nums); j++{
subset =append(subset, nums[j])backtrack(j+1, subset)
subset = subset[:len(subset)-1]}}backtrack(0,[]int{})return res
}
class Solution {privatevar res =0funsubsetXORSum(nums: IntArray): Int {backtrack(0,mutableListOf(), nums)return res
}privatefunbacktrack(i: Int, subset: MutableList<Int>, nums: IntArray){var xorr =0for(num in subset){
xorr = xorr xor num
}
res += xorr
for(j in i until nums.size){
subset.add(nums[j])backtrack(j +1, subset, nums)
subset.removeAt(subset.size -1)}}}
classSolution{funcsubsetXORSum(_ nums:[Int])->Int{var res =0funcbacktrack(_ i:Int,_ subset:inout[Int]){var xorr =0for num in subset {
xorr ^= num
}
res += xorr
for j in i..<nums.count {
subset.append(nums[j])backtrack(j +1,&subset)
subset.removeLast()}}var subset =[Int]()backtrack(0,&subset)return res
}}
Time & Space Complexity
Time complexity: O(n∗2n)
Space complexity: O(n)
2. Recursion
Intuition
A cleaner recursive approach avoids explicitly building subsets. For each element, we make a binary choice: include it in the XOR or skip it. We pass the running XOR total down the recursion tree. When we reach the end of the array, we return the accumulated XOR value. The sum of all returned values gives us the total.
Algorithm
Define a recursive function dfs(i, total) where i is the current index and total is the running XOR:
funcsubsetXORSum(nums []int)int{var dfs func(i, total int)int
dfs =func(i, total int)int{if i ==len(nums){return total
}returndfs(i+1, total^nums[i])+dfs(i+1, total)}returndfs(0,0)}
class Solution {funsubsetXORSum(nums: IntArray): Int {fundfs(i: Int, total: Int): Int {if(i == nums.size){return total
}returndfs(i +1, total xor nums[i])+dfs(i +1, total)}returndfs(0,0)}}
classSolution{funcsubsetXORSum(_ nums:[Int])->Int{funcdfs(_ i:Int,_ total:Int)->Int{if i == nums.count {return total
}returndfs(i +1, total ^ nums[i])+dfs(i +1, total)}returndfs(0,0)}}
Time & Space Complexity
Time complexity: O(2n)
Space complexity: O(n) for recursion stack.
3. Bit Manipulation
Intuition
Every subset can be represented by a bitmask where bit i indicates whether element i is included. With n elements, there are 2^n subsets corresponding to masks from 0 to 2^n - 1. We iterate through all masks, compute the XOR of selected elements for each mask, and sum them up.
Algorithm
Initialize res = 0.
For each mask from 0 to 2^n - 1:
Initialize xorr = 0.
For each bit position i from 0 to n - 1:
If bit i is set in the mask, XOR nums[i] into xorr.
classSolution:defsubsetXORSum(self, nums: List[int])->int:
n =len(nums)
res =0for mask inrange(1<< n):
xorr =0for i inrange(n):if mask &(1<< i):
xorr ^= nums[i]
res += xorr
return res
publicclassSolution{publicintsubsetXORSum(int[] nums){int n = nums.length;int res =0;for(int mask =0; mask <(1<< n); mask++){int xorr =0;for(int i =0; i < n; i++){if((mask &(1<< i))!=0){
xorr ^= nums[i];}}
res += xorr;}return res;}}
classSolution{public:intsubsetXORSum(vector<int>& nums){int n = nums.size();int res =0;for(int mask =0; mask <(1<< n); mask++){int xorr =0;for(int i =0; i < n; i++){if((mask &(1<< i))!=0){
xorr ^= nums[i];}}
res += xorr;}return res;}};
classSolution{/**
* @param {number[]} nums
* @return {number}
*/subsetXORSum(nums){const n = nums.length;let res =0;for(let mask =0; mask <1<< n; mask++){let xorr =0;for(let i =0; i < n; i++){if((mask &(1<< i))!==0){
xorr ^= nums[i];}}
res += xorr;}return res;}}
publicclassSolution{publicintSubsetXORSum(int[] nums){int n = nums.Length;int res =0;for(int mask =0; mask <(1<< n); mask++){int xorr =0;for(int i =0; i < n; i++){if((mask &(1<< i))!=0){
xorr ^= nums[i];}}
res += xorr;}return res;}}
funcsubsetXORSum(nums []int)int{
n :=len(nums)
res :=0for mask :=0; mask <(1<< n); mask++{
xorr :=0for i :=0; i < n; i++{if mask&(1<<i)!=0{
xorr ^= nums[i]}}
res += xorr
}return res
}
class Solution {funsubsetXORSum(nums: IntArray): Int {val n = nums.size
var res =0for(mask in0until(1shl n)){var xorr =0for(i in0 until n){if(mask and(1shl i)!=0){
xorr = xorr xor nums[i]}}
res += xorr
}return res
}}
classSolution{funcsubsetXORSum(_ nums:[Int])->Int{let n = nums.count
var res =0for mask in0..<(1<< n){var xorr =0for i in0..<n {if mask &(1<< i)!=0{
xorr ^= nums[i]}}
res += xorr
}return res
}}
Time & Space Complexity
Time complexity: O(n∗2n)
Space complexity: O(1) extra space.
4. Bit Manipulation (Optimal)
Intuition
Each bit position in any number contributes independently to the XOR totals. For any bit that is set in at least one number, exactly half of all subsets will have that bit set in their XOR result (because each element either flips the bit or not, and the combinations balance out). The OR of all numbers gives us all bits that appear in at least one element. Each such bit contributes its value multiplied by 2^(n-1) subsets.
Algorithm
Compute the OR of all elements in nums. This gives a number where each bit is set if and only if that bit is set in at least one element.
Left shift the result by n - 1 positions (multiply by 2^(n-1)).
classSolution:defsubsetXORSum(self, nums: List[int])->int:
res =0for num in nums:
res |= num
return res <<(len(nums)-1)
publicclassSolution{publicintsubsetXORSum(int[] nums){int res =0;for(int num : nums){
res |= num;}return res <<(nums.length -1);}}
classSolution{public:intsubsetXORSum(vector<int>& nums){int res =0;for(int& num : nums){
res |= num;}return res <<(nums.size()-1);}};
classSolution{/**
* @param {number[]} nums
* @return {number}
*/subsetXORSum(nums){let res =0;for(let num of nums){
res |= num;}return res <<(nums.length -1);}}
publicclassSolution{publicintSubsetXORSum(int[] nums){int res =0;foreach(int num in nums){
res |= num;}return res <<(nums.Length -1);}}
funcsubsetXORSum(nums []int)int{
res :=0for_, num :=range nums {
res |= num
}return res <<(len(nums)-1)}
class Solution {funsubsetXORSum(nums: IntArray): Int {var res =0for(num in nums){
res = res or num
}return res shl(nums.size -1)}}
classSolution{funcsubsetXORSum(_ nums:[Int])->Int{var res =0for num in nums {
res |= num
}return res <<(nums.count -1)}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(1) extra space.
Common Pitfalls
Forgetting the Empty Subset
The problem includes all subsets, including the empty subset which has an XOR value of 0. While this does not affect the sum, a common conceptual error is starting the subset generation from size 1 instead of size 0, or incorrectly counting the total number of subsets as 2^n - 1 instead of 2^n. This can lead to off-by-one issues in verification.
Misunderstanding XOR Properties
A frequent mistake is confusing XOR with addition or other operations. XOR has the property that a ^ a = 0 and a ^ 0 = a. When computing subset XOR totals, some assume that duplicate elements cancel out across all subsets, but each subset is computed independently. Also, the optimal solution relies on understanding that each bit appears in exactly half of all subsets, which requires grasping XOR's bit-level behavior.