DEV Community

Cover image for Solution: Decode XORed Permutation
seanpgallivan
seanpgallivan

Posted on

1 1

Solution: Decode XORed Permutation

This is part of a series of Leetcode solution explanations (index). If you liked this solution or found it useful, please like this post and/or upvote my solution post on Leetcode's forums.


Leetcode Problem #1734 (Medium): Decode XORed Permutation


Description:

There is an integer array perm that is a permutation of the first n positive integers, where n is always odd.

It was encoded into another integer array encoded of length n - 1, such that encoded[i] = perm[i] XOR perm[i + 1]. For example, if perm = [1,3,2], then encoded = [2,1].

Given the encoded array, return the original array perm. It is guaranteed that the answer exists and is unique.


Examples:

Example 1:
Input: encoded = [3,1]
Output: [1,2,3]
Explanation: If perm = [1,2,3], then
encoded = [1 XOR 2,2 XOR 3] = [3,1]
Example 2:
Input: encoded = [6,5,4,6]
Output: [2,4,1,5,3]

Constraints:

  • 3 <= n < 10^5
  • n is odd.
  • encoded.length == n - 1

Idea:

The trick to this problem is realizing that a bitwise XOR ( ^ ) operation is both associative and its own inverse function.

if:  a ^ b ^ c = d                    // XOR is associative: the order of operations
 :  c ^ b ^ a = d                    // for consecutive XOR's does not matter

if:  x ^ y = z                        // XOR is its own inverse function:
 :  z ^ y = x                        // You can undo the equation from the answer
 :  x ^ y ^ y = x                    // Two same operations cancel each other out
Enter fullscreen mode Exit fullscreen mode

This, plus the fact that the numbers in the encoded array E are formed by XOR'ing consecutive elements of perm, plus the fact that we know the numbers that make up the whole perm array, plus the fact that the length of the perm array must be odd, mean that we can easily deduce the first element of perm:

if:  perm = [ a, b, c, d, e ]             // This is true regardless of the order of
 :  a^b^c^d^e = 1^2^3^4^5                // #s in perm, b/c XOR is associative

if:  E[1] = b^c                           // By the encoding definition
if:  E[3] = d^e

 :  (1^2^3^4^5) ^ E[1] ^ E[3]            // Therefore, if we XOR all #s from
   = (a^b^c^d^e) ^ (b^c) ^ (d^e)          // 1 to N along w/ odd elements of E
   = a ^ (b^b) ^ (c^c) ^ (d^d) ^ (e^e)    // then rearrange terms via association
   = a ^ 0 ^ 0 ^ 0 ^ 0                    // then most of the terms will cancel out
   = a                                    // leaving us with just a, or perm[0]
Enter fullscreen mode Exit fullscreen mode

(Note: Had we used **E[0]* and E[3] in the example above, we could have isolated perm[2], or E[0] and E[2] would yield perm[4]; any odd element of perm can be deduced this way, as long as the length of perm is odd.*)

Conveniently, the XOR of all values between 1 and N can be determined mathematically for all odd values of N. Because an even number and the odd number that follows only vary in the 0th bit, when they are XOR'd the rest of the bits will always cancel out, leaving only a 1. With this, we can see that for all odd values of N, this will simplify to alternating 0s and 1s:

if:  even ^ (even+1) = 1
 :  1 ^ 2 ^ 3 ^ 4 ^ 5                  :  1 ^ 2 ^ 3 ^ 4 ^ 5 ^ 6 ^ 7 
   = 1 ^ (2^3) ^ (4^5)                     = 1 ^ (2^3) ^ (4^5) ^ (6^7)
   = 1 ^ 1 ^ 1                             = 1 ^ 1 ^ 1 ^ 1
   = 1                                     = 0
Enter fullscreen mode Exit fullscreen mode

Thus we can simplify the equation for the XOR of all numbers from 1 to N for all odd values of N to (N + 1 >> 1) % 2.

Also, since XOR is its own inverse function, we can work the encoding equation backwards:

if:  E[i] = perm[i] ^ perm[i+1]           // By the encoding definition
 :  perm[i+1] = E[i] ^ perm[i]           // Inverted to solve for perm[i+1]
Enter fullscreen mode Exit fullscreen mode

With perm[0] and this equation, we can quickly build out the rest of perm before returning it.


Javascript Code:

var decode = function(E) {
    let len = E.length, first = (len + 2 >> 1) % 2
    for (let i = 1; i < len; i += 2) first ^= E[i]
    let perm = [first]
    for (let i = 0; i < len; i++) ans[i+1] = ans[i] ^ E[i]
    return perm
};
Enter fullscreen mode Exit fullscreen mode

Python Code:

class Solution(object):
    def decode(self, E):
        L = len(E)
        first = (L + 2 >> 1) % 2
        for i in range(1,L,2):
            first ^= E[i]
        perm = [first]
        for el in E:
            ans.append(perm[-1] ^ el)
        return perm
Enter fullscreen mode Exit fullscreen mode

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

Image of Stellar post

How a Hackathon Win Led to My Startup Getting Funded

In this episode, you'll see:

  • The hackathon wins that sparked the journey.
  • The moment José and Joseph decided to go all-in.
  • Building a working prototype on Stellar.
  • Using the PassKeys feature of Soroban.
  • Getting funded via the Stellar Community Fund.

Watch the video 🎥

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, cherished by the supportive DEV Community. Coders of every background are encouraged to bring their perspectives and bolster our collective wisdom.

A sincere “thank you” often brightens someone’s day—share yours in the comments below!

On DEV, the act of sharing knowledge eases our journey and forges stronger community ties. Found value in this? A quick thank-you to the author can make a world of difference.

Okay