title: Beautiful Arrangement II
slug: beautiful-arrangement-ii
difficulty: medium
leetcode_id: 667
leetcode_url: https://leetcode.com/problems/beautiful-arrangement-ii/
categories:
  - arrays
  - math
patterns:
  - greedy

description: |
  Given two integers `n` and `k`, construct a list `answer` that contains `n` different positive integers ranging from `1` to `n` and obeys the following requirement:

  Suppose this list is `answer = [a1, a2, a3, ..., an]`, then the list `[|a1 - a2|, |a2 - a3|, |a3 - a4|, ..., |an-1 - an|]` has exactly `k` distinct integers.

  Return *the list* `answer`. If there are multiple valid answers, return **any of them**.

constraints: |
  - `1 <= k < n <= 10^4`

examples:
  - input: "n = 3, k = 1"
    output: "[1, 2, 3]"
    explanation: "The array [1, 2, 3] has three different positive integers ranging from 1 to 3, and the differences [|1-2|, |2-3|] = [1, 1] has exactly 1 distinct integer: 1."
  - input: "n = 3, k = 2"
    output: "[1, 3, 2]"
    explanation: "The array [1, 3, 2] has three different positive integers ranging from 1 to 3, and the differences [|1-3|, |3-2|] = [2, 1] has exactly 2 distinct integers: 1 and 2."

explanation:
  intuition: |
    Think of this problem like arranging numbered tiles on a line, where you want to control how many *different gap sizes* appear between adjacent tiles.

    The key insight is understanding what happens with a simple sorted sequence versus an alternating one. If you arrange numbers as `[1, 2, 3, ..., n]`, every adjacent difference is exactly `1` — you get only **1 distinct difference**. But if you zigzag between the smallest and largest remaining numbers, like `[1, n, 2, n-1, 3, ...]`, you generate the maximum variety of differences: `n-1, n-2, n-3, ...`

    Here's the clever observation: with a sequence of `n` numbers, you can create anywhere from `1` to `n-1` distinct differences. To get exactly `k` distinct differences:

    1. Use the first `k+1` numbers (`1` to `k+1`) in an alternating pattern to generate `k` distinct differences
    2. Fill the rest with the remaining numbers in sorted order — these contribute only difference `1`, which we already have

    This works because the alternating pattern on `k+1` elements produces differences `k, k-1, k-2, ..., 1` (exactly `k` distinct values), and appending sorted numbers only adds more `1`s.

  approach: |
    We solve this using a **Greedy Construction Approach**:

    **Step 1: Initialise two pointers**

    - `low`: Start at `1` (smallest available number)
    - `high`: Start at `k + 1` (to create differences from `k` down to `1`)

    &nbsp;

    **Step 2: Build the alternating prefix**

    - Alternate between picking `low` and `high`
    - First pick `low`, then `high`, then `low + 1`, then `high - 1`, and so on
    - Continue until `low > high` — this uses exactly `k + 1` numbers
    - This produces differences: `k, k-1, k-2, ..., 1` (exactly `k` distinct values)

    &nbsp;

    **Step 3: Append the sorted suffix**

    - Append the remaining numbers `k + 2, k + 3, ..., n` in order
    - Each consecutive pair has difference `1`, which we already counted
    - This doesn't introduce any new distinct differences

    &nbsp;

    **Step 4: Return the result**

    - Return the constructed array

  common_pitfalls:
    - title: Overcomplicating the Construction
      description: |
        Many people try complex formulas or recursive approaches when a simple two-pointer alternation works perfectly.

        The key realisation is that you only need to create exactly `k` distinct differences, and the alternating pattern on the first `k + 1` numbers does exactly that. The rest is just padding with sorted numbers.
      wrong_approach: "Complex mathematical formulas or backtracking"
      correct_approach: "Simple alternating pattern for first k+1 elements, then sorted remainder"

    - title: Off-by-One Errors
      description: |
        It's easy to get confused about whether to use `k` or `k + 1` elements for the alternating part.

        Remember: to get `k` *distinct* differences, you need `k + 1` numbers (since `n` numbers produce `n - 1` differences). The alternating pattern on `[1, 2, ..., k+1]` produces differences `k, k-1, ..., 1`.
      wrong_approach: "Using k elements instead of k + 1"
      correct_approach: "Use first k + 1 numbers for alternating, rest sorted"

    - title: Not Handling the Full Range
      description: |
        The problem requires using all integers from `1` to `n`. If you only focus on getting `k` distinct differences but forget to include all numbers, your answer will be invalid.

        The two-phase approach (alternating prefix + sorted suffix) naturally uses every number exactly once.
      wrong_approach: "Forgetting to include numbers k+2 through n"
      correct_approach: "Append remaining numbers in sorted order after the alternating prefix"

  key_takeaways:
    - "**Constructive algorithms**: Sometimes the best approach is to directly build the answer rather than search for it"
    - "**Boundary analysis**: Understanding that `n` elements produce `n-1` differences helps identify that `k+1` elements can produce `k` distinct differences"
    - "**Greedy construction**: The alternating pattern greedily maximises variety when needed, then we switch to minimal variety"
    - "**Similar problems**: This technique of mixing high-variance and low-variance sections appears in problems like *Wiggle Sort* and other array construction tasks"

  time_complexity: "O(n). We iterate through the array once to construct the result."
  space_complexity: "O(n). We store the result array of size `n` (or O(1) if we don't count the output)."

solutions:
  - approach_name: Two Pointers (Alternating Construction)
    is_optimal: true
    code: |
      def construct_array(n: int, k: int) -> list[int]:
          result = []
          low, high = 1, k + 1

          # Alternate between low and high to create k distinct differences
          while low <= high:
              result.append(low)
              low += 1
              if low <= high:
                  result.append(high)
                  high -= 1

          # Append remaining numbers in sorted order (only adds difference of 1)
          for num in range(k + 2, n + 1):
              result.append(num)

          return result
    explanation: |
      **Time Complexity:** O(n) — Single pass to build the array.

      **Space Complexity:** O(n) — The result array of size `n`.

      The alternating phase creates the sequence `[1, k+1, 2, k, 3, k-1, ...]` which has differences `[k, k-1, k-2, ..., 1]`. The sorted suffix `[k+2, k+3, ..., n]` adds only difference `1` (already present), giving exactly `k` distinct differences.

  - approach_name: Direct Formula Construction
    is_optimal: true
    code: |
      def construct_array(n: int, k: int) -> list[int]:
          result = []

          # Build the alternating prefix using a toggle
          toggle = True
          low, high = 1, k + 1

          for _ in range(k + 1):
              if toggle:
                  result.append(low)
                  low += 1
              else:
                  result.append(high)
                  high -= 1
              toggle = not toggle

          # Append the sorted suffix
          result.extend(range(k + 2, n + 1))

          return result
    explanation: |
      **Time Complexity:** O(n) — Linear construction.

      **Space Complexity:** O(n) — The result array.

      This is an alternative formulation using an explicit toggle flag. The logic is identical: alternate between smallest and largest within `[1, k+1]`, then append `[k+2, n]` in order. Some find the toggle pattern more readable than the nested while loop.

  - approach_name: Reverse Segment Approach
    is_optimal: true
    code: |
      def construct_array(n: int, k: int) -> list[int]:
          # Start with sorted array [1, 2, 3, ..., n]
          result = list(range(1, n + 1))

          # Reverse the first k+1 elements in a zigzag pattern
          # Each reversal introduces one new distinct difference
          for i in range(1, k + 1):
              # Reverse from index i to index k
              result[i:k+1] = result[i:k+1][::-1]

          return result
    explanation: |
      **Time Complexity:** O(n * k) — Multiple reversals, but can be optimised.

      **Space Complexity:** O(n) — The result array.

      This approach starts with `[1, 2, ..., n]` (1 distinct difference) and repeatedly reverses suffixes to introduce new differences one at a time. While conceptually interesting, it's less efficient than the direct construction. Included to show an alternative way of thinking about the problem.
