Construct the Lexicographically Largest Valid Sequence
MEDIUMDescription
Given an integer n, find a sequence with elements in the range [1, n] that satisfies all of the following:
- The integer
1occurs once in the sequence. - Each integer between
2andnoccurs twice in the sequence. - For every integer
ibetween2andn, the distance between the two occurrences ofiis exactlyi.
The distance between two numbers on the sequence, a[i] and a[j], is the absolute difference of their indices, |j - i|.
Return the lexicographically largest sequence. It is guaranteed that under the given constraints, there is always a solution.
A sequence a is lexicographically larger than a sequence b (of the same length) if in the first position where a and b differ, sequence a has a number greater than the corresponding number in b. For example, [0,1,9,0] is lexicographically larger than [0,1,5,6] because the first position they differ is at the third number, and 9 is greater than 5.
Example 1:
Input: n = 3 Output: [3,1,2,3,2] Explanation: [2,3,2,1,3] is also a valid sequence, but [3,1,2,3,2] is the lexicographically largest valid sequence.
Example 2:
Input: n = 5 Output: [5,3,1,4,3,5,2,4,2]
Constraints:
1 <= n <= 20
Approaches
Checkout 2 different approaches to solve Construct the Lexicographically Largest Valid Sequence. Click on different approaches to view the approach and algorithm in detail.
Brute-Force Backtracking (Generate All Sequences)
This approach involves finding every possible valid sequence that satisfies the given conditions. We use a standard backtracking algorithm to explore all placement possibilities. After generating all valid sequences, we compare them to find the one that is lexicographically the largest.
Algorithm
- Create a recursive backtracking function, say
generateAll(index), to build the sequence. - Use a boolean array
usedto keep track of numbers from1tonthat have been placed in the sequence. - The recursive function will try to fill a
sequencearray of size2n - 1. - Base Case: If the
indexreaches the end of the sequence (2n - 1), a valid sequence has been found. Add a copy of it to a list of solutions. - Recursive Step:
- If the current position
sequence[index]is already filled, recurse on the next index:generateAll(index + 1). - Otherwise, iterate through numbers
ifrom1ton. - For each
ithat has not been used:- Try to place
iatsequence[index]. Ifi > 1, its second occurrence must be placed atindex + i. - If the placement is valid (i.e., the second position is within bounds and is empty), mark
ias used, update the sequence, and make a recursive call:generateAll(index + 1). - After the recursive call returns, backtrack by undoing the placement and unmarking
ias used.
- Try to place
- If the current position
- After the initial call
generateAll(0)completes, iterate through the list of all found solutions to find and return the lexicographically largest one.
The fundamental idea is to treat this as a permutation problem with constraints. We can build a sequence recursively. A helper function, say generateAll(index), attempts to fill the sequence from the given index. It tries placing each unused number i (from 1 to n) at the current position and, if i > 1, its corresponding pair at index + i. If a placement is valid, it recurses to the next position. When a full valid sequence is formed, it's stored in a list. This process continues until all possibilities are exhausted. Finally, the list of solutions is scanned to find the lexicographically greatest sequence.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class Solution {
List<int[]> solutions;
boolean[] used;
int n;
int[] currentSequence;
public int[] constructDistancedSequence(int n) {
this.n = n;
this.solutions = new ArrayList<>();
this.used = new boolean[n + 1];
this.currentSequence = new int[2 * n - 1];
generateAll(0);
// This part is inefficient as it requires finding all solutions first.
if (solutions.isEmpty()) return new int[0];
int[] largest = solutions.get(0);
for (int i = 1; i < solutions.size(); i++) {
if (isLexicographicallyLarger(solutions.get(i), largest)) {
largest = solutions.get(i);
}
}
return largest;
}
private void generateAll(int index) {
if (index == currentSequence.length) {
solutions.add(Arrays.copyOf(currentSequence, currentSequence.length));
return;
}
if (currentSequence[index] != 0) {
generateAll(index + 1);
return;
}
// Iterate through numbers in an arbitrary order (e.g., 1 to n)
for (int i = 1; i <= n; i++) {
if (used[i]) continue;
currentSequence[index] = i;
used[i] = true;
if (i == 1) {
generateAll(index + 1);
} else {
int secondPos = index + i;
if (secondPos < currentSequence.length && currentSequence[secondPos] == 0) {
currentSequence[secondPos] = i;
generateAll(index + 1);
currentSequence[secondPos] = 0; // Backtrack
}
}
currentSequence[index] = 0; // Backtrack
used[i] = false;
}
}
private boolean isLexicographicallyLarger(int[] a, int[] b) {
for (int i = 0; i < a.length; i++) {
if (a[i] > b[i]) return true;
if (a[i] < b[i]) return false;
}
return false;
}
}
Complexity Analysis
Pros and Cons
- It is a conceptually simple application of backtracking that guarantees finding the correct answer.
- Extremely inefficient in terms of time complexity as it explores the entire search space for all possible valid sequences.
- Requires a large amount of memory to store all the generated sequences, leading to poor space complexity.
Code Solutions
Checking out 3 solutions in different languages for Construct the Lexicographically Largest Valid Sequence. Click on different languages to view the code.
Video Solution
Watch the video walkthrough for Construct the Lexicographically Largest Valid Sequence
Similar Questions
5 related questions you might find useful
Patterns:
Data Structures:
Subscribe to Scale Engineer newsletter
Learn about System Design, Software Engineering, and interview experiences every week.
No spam, unsubscribe at any time.