medium Queries on a Permutation With Key
Problem Statement
You are given a list called queries, containing positive integers between 1 and m. You need to process each number in queries according to the following rules:
- Start with a sequence
Pwhich is[1, 2, 3, ..., m]. - For each number in
querieslist, find its current position inP(0-based index), then move this number to the front ofP. Notice that the position ofqueries[i]inPis the result forqueries[i].
Return a list of results in the order corresponding to the numbers in queries.
Examples
Example 1:
- Input: queries =
[4, 3, 2, 7, 5], m =7 - Output:
[3,3,3,6,5] - Explanation:
- Initially,
P = [1, 2, 3, 4, 5, 6, 7]. - For
4, position is3, move4to front,P = [4, 1, 2, 3, 5, 6, 7]. - For
3, position is3, move3to front,P = [3, 4, 1, 2, 5, 6, 7]. - For
2, position is3, move2to front,P = [2, 3, 4, 1, 5, 6, 7]. - For
7, position is6, move7to front,P = [7, 2, 3, 4, 1, 5, 6]. - For
5, position is5, move5to front,P = [5, 7, 2, 3, 4, 1, 6].
- Initially,
Example 2:
- Input: queries =
[1, 6, 3, 6], m =6 - Output:
[0, 5, 3, 1] - Explanation:
- Initially,
P = [1, 2, 3, 4, 5, 6]. - For
1, position is0, move1to front,P = [1, 2, 3, 4, 5, 6]. - For
6, position is5, move6to front,P = [6, 1, 2, 3, 4, 5]. - For
3, position is3, move3to front,P = [3, 6, 1, 2, 4, 5]. - For
6, position is1, move6to front,P = [6, 3, 1, 2, 4, 5].
- Initially,
Example 3:
- Input: queries =
[5, 1, 2, 4, 1], m =5 - Output:
[4,1,2,4,2] - Explanation:
- Initially,
P = [1, 2, 3, 4, 5]. - For
5, position is4, move5to front,P = [5, 1, 2, 3, 4]. - For
1, position is1, move1to front,P = [1, 5, 2, 3, 4]. - For
2, position is2, move2to front,P = [2, 1, 5, 3, 4]. - For
4, position is4, move4to front,P = [4, 2, 1, 5, 3]. - For
1, position is2, move1to front,P = [1, 4, 2, 5, 3].
- Initially,
Constraints:
- 1 <= m <= 103
- 1 <= queries.length <= m
- 1 <= queries[i] <= m
Try it yourself
Try solving this question here:
✅ Solution Queries on a Permutation With Key
Problem Statement
You are given a list called queries, containing positive integers between 1 and m. You need to process each number in queries according to the following rules:
- Start with a sequence
Pwhich is[1, 2, 3, ..., m]. - For each number in
querieslist, find its current position inP(0-based index), then move this number to the front ofP. Notice that the position ofqueries[i]inPis the result forqueries[i].
Return a list of results in the order corresponding to the numbers in queries.
Examples
Example 1:
- Input: queries =
[4, 3, 2, 7, 5], m =7 - Output:
[3,3,3,6,5] - Explanation:
- Initially,
P = [1, 2, 3, 4, 5, 6, 7]. - For
4, position is3, move4to front,P = [4, 1, 2, 3, 5, 6, 7]. - For
3, position is3, move3to front,P = [3, 4, 1, 2, 5, 6, 7]. - For
2, position is3, move2to front,P = [2, 3, 4, 1, 5, 6, 7]. - For
7, position is6, move7to front,P = [7, 2, 3, 4, 1, 5, 6]. - For
5, position is5, move5to front,P = [5, 7, 2, 3, 4, 1, 6].
- Initially,
Example 2:
- Input: queries =
[1, 6, 3, 6], m =6 - Output:
[0, 5, 3, 1] - Explanation:
- Initially,
P = [1, 2, 3, 4, 5, 6]. - For
1, position is0, move1to front,P = [1, 2, 3, 4, 5, 6]. - For
6, position is5, move6to front,P = [6, 1, 2, 3, 4, 5]. - For
3, position is3, move3to front,P = [3, 6, 1, 2, 4, 5]. - For
6, position is1, move6to front,P = [6, 3, 1, 2, 4, 5].
- Initially,
Example 3:
- Input: queries =
[5, 1, 2, 4, 1], m =5 - Output:
[4,1,2,4,2] - Explanation:
- Initially,
P = [1, 2, 3, 4, 5]. - For
5, position is4, move5to front,P = [5, 1, 2, 3, 4]. - For
1, position is1, move1to front,P = [1, 5, 2, 3, 4]. - For
2, position is2, move2to front,P = [2, 1, 5, 3, 4]. - For
4, position is4, move4to front,P = [4, 2, 1, 5, 3]. - For
1, position is2, move1to front,P = [1, 4, 2, 5, 3].
- Initially,
Constraints:
- 1 <= m <= 103
- 1 <= queries.length <= m
- 1 <= queries[i] <= m
Solution
To solve the problem using the Binary Indexed Tree (BIT), we begin by initializing an array that holds the position of each element in the permutation. We also create a BIT array with a size of (m + n + 1), where (m) is the size of the permutation and (n) is the length of the queries. The BIT allows us to efficiently calculate prefix sums and update values, which helps in finding the current position of any element in the permutation and moving it to the front of the list.
The solution works by iterating through each query, using the BIT to find the current position of the queried element. After identifying its position, we update the BIT to remove the element from its current position and move it to the front. This is achieved by decrementing the value at the element's current position in the BIT and incrementing the value at the front of the permutation in the BIT. We then adjust the position of the element in the position array to reflect its new position at the front of the permutation. The process is repeated for each query, and the results are stored in a list.
Step-by-Step Algorithm
-
Initialization of Arrays:
- Create an array
positionof sizem + 1. This array is used to store the current position of each element in the permutationP. We add 1 to the size because we're indexing elements from 1 tominstead of 0. - Create a Binary Indexed Tree (BIT) array of size
m + n + 1. The sizem + n + 1is chosen to accommodate both the elements in the permutation and the queries. The BIT is used for efficient prefix sum calculations and updates.
- Create an array
-
Build the Initial BIT:
- Loop through each element from 1 to
m:- For each element
i, setposition[i] = n + i. This places the elements ofPafter all the queries in the BIT. For example, ifn = 4andm = 7, the positions will be set as[5, 6, 7, 8, 9, 10, 11]. - Call the
updateBITmethod with the indexn + iand the value1. This step initializes the BIT by adding 1 to the affected nodes in the BIT array. The update propagates this change through the tree, ensuring that the BIT correctly represents the presence of each element in the permutation.
- For each element
- Loop through each element from 1 to
-
Processing Each Query:
- For each query element
qin thequeriesarray:-
Find the Current Position:
- Call the
getPrefixSummethod withposition[q] - 1to calculate the number of elements before the current position ofq. This method sums up the values in the BIT from the start up toposition[q] - 1, effectively determining the 0-based index ofqin the current permutation. - The result from
getPrefixSumis added to the result list, which represents the index ofqbefore it is moved to the front.
- Call the
-
Update the BIT for Removal:
- Call the
updateBITmethod withposition[q]and-1as arguments. This operation subtracts 1 from the BIT at the current position ofq, effectively "removing" the element from its current spot in the permutation. This is necessary becauseqwill be moved to the front, and the BIT must reflect this change.
- Call the
-
Move the Element to the Front:
- Call the
updateBITmethod withnand1as arguments. This operation adds 1 to the BIT at the indexn, indicating that the elementqis now placed at the front of the permutation. - Update the
position[q]ton, and then decrementnby 1. This step assigns the new front position toqand preparesnfor the next query. Decreasingnensures that subsequent elements are placed at the correct positions closer to the front.
- Call the
-
- For each query element
-
Return the Result:
- Once all queries are processed, the result list containing the positions of the queried elements before they were moved is returned.
Explanation of Methods:
-
updateBIT Method:
- This method updates the BIT at a specific index by a given value (
val). It iteratively adds the value to the BIT and propagates the update to the affected nodes in the tree structure, ensuring that future prefix sum queries correctly account for this change. - The reason for passing
1as the value during the initialization is to incrementally build the BIT structure, indicating the presence of each element in the permutation. When-1is passed, it effectively "removes" the element from its current position by decrementing the relevant nodes in the BIT.
- This method updates the BIT at a specific index by a given value (
-
getPrefixSum Method:
- The
getPrefixSummethod calculates the sum of values in the BIT up to a specific index. This sum represents the number of elements in the permutation that precede the queried element. By summing the values, the method efficiently determines the position of the element in the current permutation.
- The
-
Position Update:
- The line
position[q] = n--;updates the position of the queried elementqto the front of the permutation. The decrementn--ensures that the next queried element will be placed in the next available position closer to the front. This maintains the correct ordering of elements as they are moved to the front in sequence.
- The line
Algorithm Walkthrough
Let's walk through the algorithm with queries = [4, 3, 2, 7, 5] and m = 7. We'll explain each step in detail, especially for the first two queries.
1. Initialization:
- We start by initializing the
positionarray and theBITarray. - The
positionarray is initialized as follows, with elements indexed from 1 to 7 (sincem = 7):position = [ , 6, 7, 8, 9, 10, 11, 12]- The positions start from
n + 1(wheren = 5, the length of thequeriesarray), soposition[i] = n + i.
2. Build Initial BIT:
-
We initialize the
BITarray by iterating over each element in the permutation (ifrom 1 tom). We call theupdateBITmethod for eachposition[i]with the value1to build the initial BIT. -
Step-by-step update for each
i:-
For
i = 1:position[1] = 6updateBIT(BIT, 6, 1)updates the BIT array.- Affected nodes:
index = 6: Add1toBIT[6]→BIT[6] = 1.index = 8: Add1toBIT[8]→BIT[8] = 1.index = 16: Out of range, stop.
-
For
i = 2:position[2] = 7updateBIT(BIT, 7, 1)updates the BIT array.- Affected nodes:
index = 7: Add1toBIT[7]→BIT[7] = 1.index = 8: Add1toBIT[8]→BIT[8] = 2.index = 16: Out of range, stop.
-
For
i = 3:position[3] = 8updateBIT(BIT, 8, 1)updates the BIT array.- Affected nodes:
index = 8: Add1toBIT[8]→BIT[8] = 3.index = 16: Out of range, stop.
-
For
i = 4:position[4] = 9updateBIT(BIT, 9, 1)updates the BIT array.- Affected nodes:
index = 9: Add1toBIT[9]→BIT[9] = 1.index = 10: Add1toBIT[10]→BIT[10] = 1.index = 12: Add1toBIT[12]→BIT[12] = 1.index = 16: Out of range, stop.
-
For
i = 5:position[5] = 10updateBIT(BIT, 10, 1)updates the BIT array.- Affected nodes:
index = 10: Add1toBIT[10]→BIT[10] = 2.index = 12: Add1toBIT[12]→BIT[12] = 2.index = 16: Out of range, stop.
-
For
i = 6:position[6] = 11updateBIT(BIT, 11, 1)updates the BIT array.- Affected nodes:
index = 11: Add1toBIT[11]→BIT[11] = 1.index = 12: Add1toBIT[12]→BIT[12] = 3.index = 16: Out of range, stop.
-
For
i = 7:position[7] = 12updateBIT(BIT, 12, 1)updates the BIT array.- Affected nodes:
index = 12: Add1toBIT[12]→BIT[12] = 4.index = 16: Out of range, stop.
-
-
Final BIT array after initialization:
[0, 0, 0, 0, 0, 0, 1, 1, 3, 1, 2, 1, 4]
Processing Each Query
Now, let's process each query step-by-step. We'll go into detail for the first two queries.
Query 1: q = 4
-
Find the Current Position:
- Call
getPrefixSum(BIT, position[4] - 1). - Here,
position[4] = 9, so we callgetPrefixSum(BIT, 8). - getPrefixSum Execution:
- Start at
index = 8:- Add
BIT[8] = 3tosum→sum = 3. - Update
index = 8 - (8 & -8) = 0. index = 0, out of range, stop.
- Add
- The result of
getPrefixSumis3, so the position of4is3(0-based).
- Start at
- Call
-
Update BIT for Removal of
4:- Call
updateBIT(BIT, position[4], -1). - Here,
position[4] = 9. - updateBIT Execution:
- Start at
index = 9:- Subtract
1fromBIT[9]→BIT[9] = 0. - Update
index = 9 + (9 & -9) = 10.
- Subtract
- At
index = 10:- Subtract
1fromBIT[10]→BIT[10] = 1. - Update
index = 12.
- Subtract
- At
index = 12:- Subtract
1fromBIT[12]→BIT[12] = 3. - Update
index = 16. index = 16, out of range, stop.
- Subtract
- Start at
- BIT array after removal of
4:[0, 0, 0, 0, 0, 0, 1, 1, 3, 0, 1, 1, 3]
- Call
-
Move
4to the Front:- Call
updateBIT(BIT, n, 1)to move4to the front. - Here,
n = 5. - updateBIT Execution:
- Start at
index = 5:- Add
1toBIT[5]→BIT[5] = 1. - Update
index = 6.
- Add
- At
index = 6:- Add
1toBIT[6]→BIT[6] = 2. - Update
index = 8.
- Add
- At
index = 8:- Add
1toBIT[8]→BIT[8] = 4. - Update
index = 16. index = 16, out of range, stop.
- Add
- Start at
- BIT array after moving
4to the front:[0, 0, 0, 0, 0, 1, 2, 1, 4, 0, 1, 1, 3] - Update
position[4] = n(setposition[4] = 5), then decrementnto4.
- Call
Query 2: q = 3
-
Find the Current Position:
- Call
getPrefixSum(BIT, position[3] - 1). - Here,
position[3] = 8, so we callgetPrefixSum(BIT, 7). - getPrefixSum Execution:
- Start at
index = 7:- Add
BIT[7] = 1tosum→sum = 1. - Update
index = 6.
- Add
- At
index = 6:- Add
BIT[6] = 2tosum→sum = 3. - Update
index = 4. index = 4, out of range, stop.
- Add
- The result of
getPrefixSumis3, so the position of3is3(0-based).
- Start at
- Call
-
Update BIT for Removal of
3:- Call
updateBIT(BIT, position[3], -1). - Here,
position[3] = 8. - updateBIT Execution:
- Start at
index = 8:- Subtract
1fromBIT[8]→BIT[8] = 3. - Update
index = 16. index = 16, out of range, stop.
- Subtract
- Start at
- BIT array after removal of
3:[0, 0, 0, 0, 0, 1, 2, 1, 3, 0, 1, 1, 3]
- Call
-
Move
3to the Front:- Call
updateBIT(BIT, n, 1)to move3to the front. - Here,
n = 4. - updateBIT Execution:
- Start at
index = 4:- Add
1toBIT[4]→BIT[4] = 1. - Update
index = 8.
- Add
- At
index = 8:- Add
1toBIT[8]→BIT[8] = 4. - Update
index = 16. index = 16, out of range, stop.
- Add
- Start at
- BIT array after moving
3to the front:[0, 0, 0, 0, 1, 1, 2, 1, 4, 0, 1, 1, 3] - Update
position[3] = n(setposition[3] = 4), then decrementnto3.
- Call
This way process all queries and you will get [3, 3, 3, 6, 5] as a result array.
Code
import java.util.ArrayList;
import java.util.List;
class Solution {
// Method to calculate the prefix sum up to index 'index' using BIT
private int getPrefixSum(int[] BIT, int index) {
int sum = 0;
// Traverse the BIT array backward to calculate the sum
for (; index > 0; index -= (index & -index)) {
sum += BIT[index];
}
return sum;
}
// Method to update the BIT array at index 'index' with a value val
private void updateBIT(int[] BIT, int index, int val) {
// Traverse the BIT array forward to update the values
for (; index < BIT.length; index += (index & -index)) {
BIT[index] += val;
}
}
// Main method to process the queries
public List<Integer> processQueries(int[] queries, int m) {
int n = queries.length;
List<Integer> result = new ArrayList<>(); // List to store the final result
int[] BIT = new int[m + n + 1]; // Binary Indexed Tree with size m + n + 1
int[] position = new int[m + 1]; // Array to store the position of each element
// Initialize the position array and build the initial BIT
for (int i = 1; i <= m; i++) {
position[i] = n + i; // Position starts after the queries array
updateBIT(BIT, n + i, 1); // Build the BIT by adding initial elements
}
// Process each query
for (int q : queries) {
// Get the current position of the query element
result.add(getPrefixSum(BIT, position[q] - 1));
// Update the BIT to remove the element from its current position
updateBIT(BIT, position[q], -1);
// Update the BIT to move the element to the front
updateBIT(BIT, n, 1);
// Update the position of the element to the new position (front)
position[q] = n--;
}
return result; // Return the result list
}
public static void main(String[] args) {
Solution solution = new Solution();
// Example 1
int[] queries1 = { 4, 3, 2, 7, 5 };
int m1 = 7;
List<Integer> result1 = solution.processQueries(queries1, m1);
System.out.println(result1); // Output: [3, 3, 3, 6, 5]
// Example 2
int[] queries2 = { 1, 6, 3, 6 };
int m2 = 6;
List<Integer> result2 = solution.processQueries(queries2, m2);
System.out.println(result2); // Output: [0, 5, 3, 1]
// Example 3
int[] queries3 = { 5, 1, 2, 4, 1 };
int m3 = 5;
List<Integer> result3 = solution.processQueries(queries3, m3);
System.out.println(result3); // Output: [4, 1, 2, 4, 2]
}
}
Updated Complexity Analysis
Time Complexity
-
Initialization:
- Initializing the
positionarray and building the initial BIT takestime, where (m) is the size of the permutation. - The BIT array is initialized with a size of
, where (n) is the length of the queries array. The complexity for building the BIT is because each update operation to the BIT takes time.
- Initializing the
-
Processing Queries:
- For each query, finding the position using
getPrefixSuminvolves querying the BIT, which takestime. - Updating the BIT (both removal and insertion) also takes
for each operation. - Given that there are (n) queries, the overall time complexity for processing the queries is
.
- For each query, finding the position using
Thus, the overall time complexity of the solution is:
Space Complexity
- The space complexity is determined by the BIT and position arrays.
- The BIT array requires
space. - The position array requires
space.
- The BIT array requires
Thus, the overall space complexity is:
🤖 Don't fully get this? Learn it with Claude
Stuck on Queries on a Permutation With Key? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Queries on a Permutation With Key** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Queries on a Permutation With Key** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Queries on a Permutation With Key**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Queries on a Permutation With Key**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.