Construct the Lexicographically Largest Valid Sequence

medium backtracking pruning

Problem

Given an integer n, build a sequence of length 2n − 1 in which the number 1 appears exactly once and every value i from 2 to n appears exactly twice, with the extra rule that the two copies of each i must sit exactly i indices apart. A valid arrangement always exists for 1 ≤ n ≤ 20; among all of them, return the lexicographically largest sequence.

The winning strategy is greedy backtracking: fill the leftmost empty slot with the biggest unused number whose mirror slot (i positions to the right) is still free, and undo the choice whenever the search gets stuck further on.

Inputn = 5
Output[5, 3, 1, 4, 3, 5, 2, 4, 2]
The two 5s are 5 apart (indices 0 and 5), the 3s are 3 apart, the 4s 4 apart, the 2s 2 apart, and the single 1 fills the remaining slot — no valid sequence starts with anything bigger.

def construct_distanced_sequence(n):
    size = 2 * n - 1
    seq = [0] * size
    used = [False] * (n + 1)

    def backtrack(pos):
        if pos == size:
            return True
        if seq[pos] != 0:
            return backtrack(pos + 1)
        for num in range(n, 0, -1):      # largest first
            if used[num]:
                continue
            mirror = pos if num == 1 else pos + num
            if mirror >= size or seq[mirror] != 0:
                continue                 # prune: mirror slot blocked
            seq[pos] = seq[mirror] = num
            used[num] = True
            if backtrack(pos + 1):
                return True              # first full sequence wins
            seq[pos] = seq[mirror] = 0   # undo, try smaller
            used[num] = False
        return False

    backtrack(0)
    return seq
function constructDistancedSequence(n) {
  const size = 2 * n - 1;
  const seq = new Array(size).fill(0);
  const used = new Array(n + 1).fill(false);
  function backtrack(pos) {
    if (pos === size) return true;
    if (seq[pos] !== 0) return backtrack(pos + 1);
    for (let num = n; num >= 1; num--) {   // largest first
      if (used[num]) continue;
      const mirror = num === 1 ? pos : pos + num;
      if (mirror >= size || seq[mirror] !== 0) continue;
      seq[pos] = num; seq[mirror] = num;
      used[num] = true;
      if (backtrack(pos + 1)) return true; // first hit wins
      seq[pos] = 0; seq[mirror] = 0;       // undo, try smaller
      used[num] = false;
    }
    return false;
  }
  backtrack(0);
  return seq;
}
class Solution {
    public int[] constructDistancedSequence(int n) {
        int size = 2 * n - 1;
        int[] seq = new int[size];
        boolean[] used = new boolean[n + 1];
        backtrack(seq, used, 0, n);
        return seq;
    }
    boolean backtrack(int[] seq, boolean[] used, int pos, int n) {
        if (pos == seq.length) return true;
        if (seq[pos] != 0) return backtrack(seq, used, pos + 1, n);
        for (int num = n; num >= 1; num--) {   // largest first
            if (used[num]) continue;
            int mirror = num == 1 ? pos : pos + num;
            if (mirror >= seq.length || seq[mirror] != 0) continue;
            seq[pos] = num; seq[mirror] = num;
            used[num] = true;
            if (backtrack(seq, used, pos + 1, n)) return true;
            seq[pos] = 0; seq[mirror] = 0;     // undo, try smaller
            used[num] = false;
        }
        return false;
    }
}
class Solution {
public:
    vector<int> constructDistancedSequence(int n) {
        int size = 2 * n - 1;
        vector<int> seq(size, 0);
        vector<bool> used(n + 1, false);
        backtrack(seq, used, 0, n);
        return seq;
    }
    bool backtrack(vector<int>& seq, vector<bool>& used, int pos, int n) {
        if (pos == (int)seq.size()) return true;
        if (seq[pos] != 0) return backtrack(seq, used, pos + 1, n);
        for (int num = n; num >= 1; num--) {   // largest first
            if (used[num]) continue;
            int mirror = num == 1 ? pos : pos + num;
            if (mirror >= (int)seq.size() || seq[mirror] != 0) continue;
            seq[pos] = num; seq[mirror] = num;
            used[num] = true;
            if (backtrack(seq, used, pos + 1, n)) return true;
            seq[pos] = 0; seq[mirror] = 0;     // undo, try smaller
            used[num] = false;
        }
        return false;
    }
};
Time: O(n!) Space: O(n)