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`)   **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)   **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   **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.