1720. Decode XORed Array
Problem Description
You have a hidden integer array arr
containing n
non-negative integers. This array has been encoded into another array called encoded
with length n - 1
.
The encoding works as follows: each element encoded[i]
is calculated by taking the XOR of two consecutive elements from the original array: encoded[i] = arr[i] XOR arr[i + 1]
.
For example, if the original array is arr = [1,0,2,1]
, then the encoded array would be encoded = [1,2,3]
because:
encoded[0] = 1 XOR 0 = 1
encoded[1] = 0 XOR 2 = 2
encoded[2] = 2 XOR 1 = 3
You are given:
- The
encoded
array - An integer
first
, which is the first element of the original array (arr[0]
)
Your task is to reconstruct and return the original array arr
.
The key insight is that if you know arr[i]
and encoded[i]
, you can find arr[i+1]
using the XOR property. Since encoded[i] = arr[i] XOR arr[i+1]
, you can rearrange this to get arr[i+1] = arr[i] XOR encoded[i]
. This works because XOR has the property that a XOR a = 0
and 0 XOR b = b
.
Starting with first
as arr[0]
, you can sequentially compute each subsequent element of the original array by XORing the current element with the corresponding encoded value.
Intuition
The key to solving this problem lies in understanding the properties of the XOR operation. XOR has a special characteristic: it's its own inverse operation. This means if a XOR b = c
, then a XOR c = b
and b XOR c = a
.
Let's think about what we know:
- We have
encoded[i] = arr[i] XOR arr[i+1]
- We know
arr[0]
(which isfirst
) - We need to find all elements of
arr
Since we know arr[0]
and encoded[0]
, can we find arr[1]
? Let's manipulate the equation:
If encoded[0] = arr[0] XOR arr[1]
, and we XOR both sides with arr[0]
:
- Left side:
arr[0] XOR encoded[0]
- Right side:
arr[0] XOR (arr[0] XOR arr[1])
The right side simplifies because arr[0] XOR arr[0] = 0
, and 0 XOR arr[1] = arr[1]
.
So we get: arr[1] = arr[0] XOR encoded[0]
This pattern continues! Once we have arr[1]
, we can find arr[2]
using arr[2] = arr[1] XOR encoded[1]
, and so on.
It's like a chain reaction - each element of the original array can be recovered by XORing the previous element with the corresponding encoded value. We start with the given first element and propagate forward through the entire array, decoding one element at a time.
This works because XOR essentially "locks" two values together in the encoded array, and knowing one value allows us to "unlock" the other using the same XOR operation.
Solution Approach
Based on our intuition, we can implement the solution by iteratively applying the XOR operation to decode each element of the original array.
The mathematical relationship we derived is:
arr[i + 1] = arr[i] XOR encoded[i]
Here's how we implement this step by step:
-
Initialize the result array: Start with an array containing just the first element, since
arr[0] = first
is given. -
Iterate through the encoded array: For each element
x
inencoded
, we calculate the next element of the original array. -
Apply the XOR operation: For each
encoded[i]
, computearr[i + 1] = arr[i] XOR encoded[i]
. In the code, this is done withans[-1] ^ x
, where:ans[-1]
is the last element we've decoded (equivalent toarr[i]
)x
is the current encoded value (equivalent toencoded[i]
)- The XOR operation
^
gives us the next element
-
Build the array incrementally: Append each newly decoded element to our result array.
The implementation is straightforward:
ans = [first] # Start with arr[0] for x in encoded: ans.append(ans[-1] ^ x) # arr[i+1] = arr[i] XOR encoded[i] return ans
This approach has:
- Time Complexity:
O(n)
wheren
is the length of the encoded array, as we iterate through it once - Space Complexity:
O(n)
for storing the decoded array (which is the required output)
The solution leverages the self-inverse property of XOR to reverse the encoding process, reconstructing the original array element by element from left to right.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to see how the solution works.
Given:
encoded = [3, 1, 4, 2]
first = 5
We need to reconstruct the original array arr
.
Step-by-step reconstruction:
-
Initialize: Start with
arr = [5]
(sincefirst = 5
) -
Decode arr[1]:
- We know:
encoded[0] = arr[0] XOR arr[1] = 3
- Therefore:
arr[1] = arr[0] XOR encoded[0] = 5 XOR 3
- Binary:
5 = 101
,3 = 011
- XOR:
101 XOR 011 = 110 = 6
- Update:
arr = [5, 6]
- We know:
-
Decode arr[2]:
- We know:
encoded[1] = arr[1] XOR arr[2] = 1
- Therefore:
arr[2] = arr[1] XOR encoded[1] = 6 XOR 1
- Binary:
6 = 110
,1 = 001
- XOR:
110 XOR 001 = 111 = 7
- Update:
arr = [5, 6, 7]
- We know:
-
Decode arr[3]:
- We know:
encoded[2] = arr[2] XOR arr[3] = 4
- Therefore:
arr[3] = arr[2] XOR encoded[2] = 7 XOR 4
- Binary:
7 = 111
,4 = 100
- XOR:
111 XOR 100 = 011 = 3
- Update:
arr = [5, 6, 7, 3]
- We know:
-
Decode arr[4]:
- We know:
encoded[3] = arr[3] XOR arr[4] = 2
- Therefore:
arr[4] = arr[3] XOR encoded[3] = 3 XOR 2
- Binary:
3 = 011
,2 = 010
- XOR:
011 XOR 010 = 001 = 1
- Final:
arr = [5, 6, 7, 3, 1]
- We know:
Verification: Let's verify our answer by encoding it back:
5 XOR 6 = 101 XOR 110 = 011 = 3
✓6 XOR 7 = 110 XOR 111 = 001 = 1
✓7 XOR 3 = 111 XOR 011 = 100 = 4
✓3 XOR 1 = 011 XOR 001 = 010 = 2
✓
The decoded array [5, 6, 7, 3, 1]
correctly produces the encoded array [3, 1, 4, 2]
when we apply the XOR operation to consecutive elements.
Solution Implementation
1class Solution:
2 def decode(self, encoded: List[int], first: int) -> List[int]:
3 """
4 Decodes an array where each element in 'encoded' represents
5 the XOR of consecutive elements in the original array.
6
7 Args:
8 encoded: List of integers where encoded[i] = original[i] XOR original[i+1]
9 first: The first element of the original array
10
11 Returns:
12 The original array before encoding
13 """
14 # Initialize result array with the first element
15 result = [first]
16
17 # Iterate through each encoded value
18 for encoded_value in encoded:
19 # Calculate next original value using XOR property:
20 # If encoded[i] = original[i] XOR original[i+1]
21 # Then original[i+1] = original[i] XOR encoded[i]
22 next_value = result[-1] ^ encoded_value
23 result.append(next_value)
24
25 return result
26
1class Solution {
2 /**
3 * Decodes an XOR-encoded array given the first element of the original array.
4 *
5 * The encoding rule is: encoded[i] = original[i] XOR original[i + 1]
6 * Therefore, to decode: original[i + 1] = original[i] XOR encoded[i]
7 *
8 * @param encoded The XOR-encoded array
9 * @param first The first element of the original array
10 * @return The decoded original array
11 */
12 public int[] decode(int[] encoded, int first) {
13 // Get the length of the encoded array
14 int encodedLength = encoded.length;
15
16 // Initialize result array with size encodedLength + 1
17 // (since original array has one more element than encoded array)
18 int[] decodedArray = new int[encodedLength + 1];
19
20 // Set the first element of the decoded array
21 decodedArray[0] = first;
22
23 // Decode each subsequent element using XOR operation
24 // Since encoded[i] = original[i] XOR original[i + 1],
25 // we can get original[i + 1] = original[i] XOR encoded[i]
26 for (int i = 0; i < encodedLength; i++) {
27 decodedArray[i + 1] = decodedArray[i] ^ encoded[i];
28 }
29
30 // Return the fully decoded array
31 return decodedArray;
32 }
33}
34
1class Solution {
2public:
3 vector<int> decode(vector<int>& encoded, int first) {
4 // Initialize result array with the first element
5 vector<int> result = {first};
6
7 // Decode each element by XORing with the previous decoded value
8 // Since encoded[i] = arr[i] XOR arr[i+1], we have:
9 // arr[i+1] = encoded[i] XOR arr[i]
10 for (int encodedValue : encoded) {
11 // Get the last decoded value and XOR with current encoded value
12 int nextDecodedValue = result.back() ^ encodedValue;
13 result.push_back(nextDecodedValue);
14 }
15
16 return result;
17 }
18};
19
1/**
2 * Decodes an array of XOR-encoded numbers given the first element of the original array.
3 * Each encoded element represents the XOR of consecutive elements in the original array.
4 *
5 * @param encoded - Array of XOR-encoded values where encoded[i] = original[i] ^ original[i+1]
6 * @param first - The first element of the original array
7 * @returns The decoded original array
8 */
9function decode(encoded: number[], first: number): number[] {
10 // Initialize result array with the first element
11 const decodedArray: number[] = [first];
12
13 // Iterate through each encoded value
14 for (const encodedValue of encoded) {
15 // Decode the next element by XORing the last decoded element with the current encoded value
16 // Since encoded[i] = original[i] ^ original[i+1], we can get original[i+1] = original[i] ^ encoded[i]
17 const lastDecodedElement: number = decodedArray[decodedArray.length - 1];
18 const nextDecodedElement: number = lastDecodedElement ^ encodedValue;
19 decodedArray.push(nextDecodedElement);
20 }
21
22 return decodedArray;
23}
24
Time and Space Complexity
Time Complexity: O(n)
The algorithm iterates through the encoded
list exactly once using a for loop. In each iteration, it performs a constant-time XOR operation (ans[-1] ^ x
) and appends the result to the ans
list. Since appending to a list in Python is amortized O(1)
and we perform n
iterations where n
is the length of the encoded
array, the overall time complexity is O(n)
.
Space Complexity: O(n)
The algorithm creates a new list ans
to store the decoded result. This list starts with one element (first
) and grows by one element for each element in the encoded
array. The final size of ans
will be n + 1
where n
is the length of the encoded
array. Therefore, the space complexity is O(n)
for storing the output array. The only additional space used is for the loop variable x
, which is O(1)
, so the overall space complexity remains O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding XOR Properties
Many developers struggle with the XOR operation's reversibility. A common mistake is trying to "undo" XOR using subtraction or other operations instead of applying XOR again.
Incorrect approach:
# Wrong: Trying to reverse XOR with subtraction result.append(encoded_value - result[-1])
Correct approach:
# Right: XOR is its own inverse result.append(result[-1] ^ encoded_value)
2. Off-by-One Errors with Array Lengths
The encoded array has length n-1
while the original array has length n
. Developers often create arrays of incorrect size or loop the wrong number of times.
Incorrect approach:
# Wrong: Pre-allocating wrong size
result = [0] * len(encoded) # Missing one element!
result[0] = first
for i in range(1, len(encoded)):
result[i] = result[i-1] ^ encoded[i-1]
# This will miss the last element
Correct approach:
# Right: Account for n vs n-1 relationship result = [first] for encoded_value in encoded: result.append(result[-1] ^ encoded_value) # Final array will have len(encoded) + 1 elements
3. Modifying Input While Iterating
Some developers try to modify the encoded array in place or use it to store intermediate results, which can lead to incorrect calculations.
Incorrect approach:
# Wrong: Modifying encoded array
encoded.insert(0, first)
for i in range(1, len(encoded)):
encoded[i] = encoded[i-1] ^ encoded[i]
return encoded # This corrupts the input and gives wrong results
Correct approach:
# Right: Create a new array for results result = [first] for encoded_value in encoded: result.append(result[-1] ^ encoded_value) return result
4. Incorrect Index Management
When using index-based iteration, it's easy to confuse which indices correspond to the encoded array versus the original array.
Incorrect approach:
# Wrong: Confusing indices between arrays
result = [first]
for i in range(len(encoded)):
result.append(result[i+1] ^ encoded[i]) # IndexError!
Correct approach:
# Right: Careful index management
result = [first]
for i in range(len(encoded)):
result.append(result[i] ^ encoded[i])
5. Not Handling Edge Cases
Failing to consider empty encoded arrays or validate inputs can cause runtime errors.
Better approach with validation:
def decode(self, encoded: List[int], first: int) -> List[int]:
if not encoded: # Handle empty encoded array
return [first]
result = [first]
for encoded_value in encoded:
result.append(result[-1] ^ encoded_value)
return result
Depth first search is equivalent to which of the tree traversal order?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!