title: Build Array from Permutation
slug: build-array-from-permutation
difficulty: easy
leetcode_id: 1920
leetcode_url: https://leetcode.com/problems/build-array-from-permutation/
categories:
  - arrays
patterns:
  - matrix-traversal

function_signature: "def build_array(nums: list[int]) -> list[int]:"

test_cases:
  visible:
    - input: { nums: [0, 2, 1, 5, 3, 4] }
      expected: [0, 1, 2, 4, 5, 3]
    - input: { nums: [5, 0, 1, 2, 3, 4] }
      expected: [4, 5, 0, 1, 2, 3]
  hidden:
    - input: { nums: [0] }
      expected: [0]
    - input: { nums: [1, 0] }
      expected: [0, 1]
    - input: { nums: [0, 1, 2, 3, 4] }
      expected: [0, 1, 2, 3, 4]
    - input: { nums: [4, 3, 2, 1, 0] }
      expected: [0, 1, 2, 3, 4]
    - input: { nums: [2, 0, 1] }
      expected: [1, 2, 0]
    - input: { nums: [3, 0, 2, 1] }
      expected: [1, 3, 2, 0]

description: |
  Given a **zero-based permutation** `nums` (**0-indexed**), build an array `ans` of the **same length** where `ans[i] = nums[nums[i]]` for each `0 <= i < nums.length` and return it.

  A **zero-based permutation** `nums` is an array of **distinct** integers from `0` to `nums.length - 1` (**inclusive**).

constraints: |
  - `1 <= nums.length <= 1000`
  - `0 <= nums[i] < nums.length`
  - The elements in `nums` are **distinct**

examples:
  - input: "nums = [0,2,1,5,3,4]"
    output: "[0,1,2,4,5,3]"
    explanation: "ans[i] = nums[nums[i]]. For i=0: nums[nums[0]] = nums[0] = 0. For i=1: nums[nums[1]] = nums[2] = 1. And so on."
  - input: "nums = [5,0,1,2,3,4]"
    output: "[4,5,0,1,2,3]"
    explanation: "For i=0: nums[nums[0]] = nums[5] = 4. For i=1: nums[nums[1]] = nums[0] = 5. And so on."

explanation:
  intuition: |
    Think of this problem as following a chain of pointers. Each element in the array tells you "go look at this index," and then you report what you find there.

    Imagine the array as a treasure map where each location contains coordinates to another location. For each position `i`, you first look at `nums[i]` to get a new location, then you go to that location and record what you find. The result is your answer for position `i`.

    The key insight is that since `nums` is a permutation of `0` to `n-1`, every index is valid and every value appears exactly once. This guarantees that `nums[nums[i]]` will never go out of bounds — every value in the array is a valid index.

    For the follow-up challenge of O(1) space, we can encode two values in each position using the mathematical property that for any value `a` and `b` where both are less than `n`, we can store `a + n * b` and later extract `a` as `value % n` and `b` as `value // n`.

  approach: |
    We solve this using **direct simulation**:

    **Step 1: Create a result array**

    - Initialise an empty array `ans` of the same length as `nums`
    - We'll fill each position with the required value

    &nbsp;

    **Step 2: Apply the transformation**

    - For each index `i` from `0` to `n-1`:
    - Look up `nums[i]` to get the intermediate index
    - Look up `nums[nums[i]]` to get the final value
    - Store this value in `ans[i]`

    &nbsp;

    **Step 3: Return the result**

    - Return the completed `ans` array

    &nbsp;

    For the **O(1) space** solution, we use a clever encoding trick:

    **Step 1: Encode both values in each position**

    - For each index `i`, we want to store both the original `nums[i]` and the new `nums[nums[i]]`
    - Use the formula: `nums[i] = nums[i] + n * (nums[nums[i]] % n)`
    - The `% n` is crucial because some positions may already have been encoded

    &nbsp;

    **Step 2: Decode to get final values**

    - For each index `i`, extract the encoded value using integer division: `nums[i] = nums[i] // n`

  common_pitfalls:
    - title: Modifying Array While Reading
      description: |
        In the O(1) space approach, if you simply set `nums[i] = nums[nums[i]]`, you corrupt the array for later indices that need to read the original values.

        For example, with `nums = [0, 2, 1]`, if you set `nums[0] = nums[nums[0]] = nums[0] = 0`, then when computing `nums[1]`, you need `nums[nums[1]] = nums[2] = 1`, which is still correct. But consider `nums = [1, 0]`: setting `nums[0] = nums[1] = 0` means when computing `nums[1]`, you need `nums[nums[1]] = nums[0]`, but `nums[0]` is now `0` instead of `1`.
      wrong_approach: "Overwriting values directly in the input array"
      correct_approach: "Either use a separate result array or encode both values together"

    - title: Forgetting Modulo When Encoding
      description: |
        When using the encoding trick, the value at `nums[i]` might already be encoded (contains both old and new values). Reading `nums[nums[i]]` directly would give the wrong result.

        Always use `nums[nums[i] % n]` to extract the original value, since `original_value = encoded_value % n`.
      wrong_approach: "nums[i] += n * nums[nums[i]]"
      correct_approach: "nums[i] += n * (nums[nums[i]] % n)"

    - title: Integer Overflow Concerns
      description: |
        In some languages, `nums[i] + n * encoded_value` could overflow if `n` is large. With the constraint `n <= 1000`, the maximum encoded value is `999 + 1000 * 999 = 999,999`, which fits comfortably in a 32-bit integer.

        In Python, integers have arbitrary precision, so this isn't a concern, but be mindful in languages like C++ or Java.

  key_takeaways:
    - "**Index chaining**: When array values represent indices, you can follow chains with `arr[arr[i]]`"
    - "**Encoding two values**: The formula `a + n * b` stores two values `< n` in one integer, extractable via `% n` and `// n`"
    - "**Permutation properties**: A permutation of `0` to `n-1` guarantees all indices are valid and all values are distinct"
    - "**In-place modification**: When modifying an array in-place, ensure you can still recover original values when needed"

  time_complexity: "O(n). We iterate through the array once (or twice for the O(1) space solution)."
  space_complexity: "O(n) for the straightforward solution using a result array. O(1) for the encoding approach that modifies the input in-place."

solutions:
  - approach_name: Direct Simulation
    is_optimal: true
    code: |
      def buildArray(nums: list[int]) -> list[int]:
          n = len(nums)
          # Create result array with the same length
          ans = [0] * n

          # For each index, follow the chain: i -> nums[i] -> nums[nums[i]]
          for i in range(n):
              ans[i] = nums[nums[i]]

          return ans
    explanation: |
      **Time Complexity:** O(n) — Single pass through the array.

      **Space Complexity:** O(n) — We create a new array of size n.

      This is the most straightforward approach: create a new array and fill each position by following the index chain. Clean, readable, and efficient.

  - approach_name: In-Place with Encoding
    is_optimal: false
    code: |
      def buildArray(nums: list[int]) -> list[int]:
          n = len(nums)

          # First pass: encode both old and new values
          # nums[i] = old_value + n * new_value
          for i in range(n):
              # Use % n to get original value (in case already encoded)
              new_value = nums[nums[i] % n] % n
              nums[i] = nums[i] + n * new_value

          # Second pass: decode to get only the new values
          for i in range(n):
              nums[i] = nums[i] // n

          return nums
    explanation: |
      **Time Complexity:** O(n) — Two passes through the array.

      **Space Complexity:** O(1) — Only modifies the input array in-place.

      This clever approach stores two values in each position using the encoding `old + n * new`. The first pass encodes, the second pass decodes. While it achieves O(1) space, it's harder to understand and modifies the input, which may not always be desirable.
