Facebook Pixel

1528. Shuffle String

Problem Description

You are given a string s and an integer array indices where both have the same length. Your task is to rearrange the characters of the string based on the positions specified in the indices array.

The shuffling works as follows: the character currently at position i in the original string s should be moved to position indices[i] in the final shuffled string.

For example, if s = "abc" and indices = [2, 0, 1]:

  • The character at position 0 ('a') moves to position indices[0] = 2
  • The character at position 1 ('b') moves to position indices[1] = 0
  • The character at position 2 ('c') moves to position indices[2] = 1
  • The resulting shuffled string would be "bca"

The solution creates an array ans of the same length as the input string. It then iterates through each character in the original string along with its index i. For each character c at position i, it places that character at position indices[i] in the answer array. Finally, it joins all characters in the answer array to form the shuffled string.

The time complexity is O(n) where n is the length of the string, as we iterate through the string once. The space complexity is also O(n) for storing the result array.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is to understand what the indices array is telling us. Each value indices[i] represents the destination position for the character at position i in the original string.

Instead of trying to track where each character comes from, we can directly place each character where it needs to go. Think of it like having a set of letters and an instruction manual that tells you exactly where to place each letter.

When we see that indices[i] = j, this means "take the character at position i and put it at position j in the result". This is a direct mapping relationship.

The natural approach is to:

  1. Create an empty result array of the same size as our string
  2. Go through each character in the original string one by one
  3. For each character at position i, look up where it should go (indices[i])
  4. Place that character directly at its destination position

This works because the indices array guarantees that each position from 0 to n-1 appears exactly once (it's a permutation), ensuring every position in our result will be filled with exactly one character.

The beauty of this solution is its simplicity - we don't need to reverse any mappings or perform complex swaps. We simply read the instructions and place each character exactly where it belongs in a single pass through the string.

Solution Approach

The implementation follows a straightforward direct placement strategy:

  1. Initialize Result Array: Create an array ans of the same length as the input string s. Initially, we can fill it with any placeholder values (here using 0), as all positions will be overwritten.

    ans = [0] * len(s)
  2. Iterate and Place Characters: Use enumerate() to iterate through the string s, which gives us both the index i and the character c at that position.

    for i, c in enumerate(s):
  3. Direct Placement: For each character c at position i, place it directly at its destination position indices[i] in the result array.

    ans[indices[i]] = c

    This is the core operation - we're using indices[i] as the index to determine where character c should go in the final arrangement.

  4. Convert to String: After all characters have been placed in their correct positions, join the array elements to form the final string.

    return ''.join(ans)

Example Walkthrough: If s = "codeleet" and indices = [4,5,6,7,0,2,1,3]:

  • Character 'c' at position 0 goes to position 4: ans[4] = 'c'
  • Character 'o' at position 1 goes to position 5: ans[5] = 'o'
  • Character 'd' at position 2 goes to position 6: ans[6] = 'd'
  • And so on...

After processing all characters, ans = ['l','e','e','t','c','o','d','e'], which joins to form "leetcode".

The algorithm uses an array as the primary data structure for efficient O(1) access when placing characters at specific positions. The pattern here is index mapping - using one array's values as indices for another array.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a small example with s = "cab" and indices = [2, 0, 1].

Step 1: Initialize Result Array

  • Create an array ans with length 3 (same as string length)
  • ans = [_, _, _] (placeholders shown as underscores)

Step 2: Process Each Character

Iteration 1 (i=0):

  • Current character: c at position 0
  • Destination: indices[0] = 2
  • Place 'c' at position 2: ans[2] = 'c'
  • Result: ans = [_, _, 'c']

Iteration 2 (i=1):

  • Current character: a at position 1
  • Destination: indices[1] = 0
  • Place 'a' at position 0: ans[0] = 'a'
  • Result: ans = ['a', _, 'c']

Iteration 3 (i=2):

  • Current character: b at position 2
  • Destination: indices[2] = 1
  • Place 'b' at position 1: ans[1] = 'b'
  • Result: ans = ['a', 'b', 'c']

Step 3: Convert to String

  • Join the array: ''.join(['a', 'b', 'c'])
  • Final result: "abc"

The key insight: each indices[i] value tells us exactly where the character at position i should go in the final string. We simply follow these instructions directly, placing each character at its designated spot.

Solution Implementation

1class Solution:
2    def restoreString(self, s: str, indices: List[int]) -> str:
3        """
4        Restores a shuffled string to its original order based on given indices.
5      
6        Args:
7            s: The shuffled string to be restored
8            indices: List where indices[i] indicates the position where s[i] should be placed
9      
10        Returns:
11            The restored string with characters in their correct positions
12        """
13        # Initialize a result list with the same length as the input string
14        result = [''] * len(s)
15      
16        # Iterate through each character and its index in the original string
17        for current_index, character in enumerate(s):
18            # Place the character at its target position specified by indices array
19            target_position = indices[current_index]
20            result[target_position] = character
21      
22        # Join all characters in the result list to form the final string
23        return ''.join(result)
24
1class Solution {
2    /**
3     * Restores a shuffled string to its original order based on given indices.
4     * Each character at position i in the input string should be placed at position indices[i] in the result.
5     * 
6     * @param s       The shuffled input string
7     * @param indices Array where indices[i] indicates the target position for character s[i]
8     * @return        The restored string with characters rearranged according to indices
9     */
10    public String restoreString(String s, int[] indices) {
11        // Get the length of the input string
12        int length = s.length();
13      
14        // Create a character array to build the result string
15        char[] resultArray = new char[length];
16      
17        // Iterate through each character in the input string
18        for (int i = 0; i < length; i++) {
19            // Place the character at position i into its target position
20            // indices[i] tells us where character s.charAt(i) should go
21            resultArray[indices[i]] = s.charAt(i);
22        }
23      
24        // Convert the character array to a String and return
25        return String.valueOf(resultArray);
26    }
27}
28
1class Solution {
2public:
3    string restoreString(string s, vector<int>& indices) {
4        // Get the length of the input string
5        int n = s.size();
6      
7        // Initialize result string with n characters (using space character as placeholder)
8        string result(n, ' ');
9      
10        // Iterate through each character in the original string
11        for (int i = 0; i < n; ++i) {
12            // Place character s[i] at its target position indices[i]
13            // indices[i] tells us where character s[i] should go in the result
14            result[indices[i]] = s[i];
15        }
16      
17        // Return the restored string
18        return result;
19    }
20};
21
1/**
2 * Restores a shuffled string to its original order based on given indices
3 * @param s - The shuffled string to restore
4 * @param indices - Array where indices[i] indicates the position where s[i] should be placed
5 * @returns The restored string with characters in their correct positions
6 */
7function restoreString(s: string, indices: number[]): string {
8    // Initialize an array to hold characters in their restored positions
9    const restoredArray: string[] = [];
10  
11    // Iterate through each character in the input string
12    for (let i = 0; i < s.length; i++) {
13        // Place the character at position i into its target position specified by indices[i]
14        restoredArray[indices[i]] = s[i];
15    }
16  
17    // Join the array elements to form the final restored string
18    return restoredArray.join('');
19}
20

Time and Space Complexity

Time Complexity: O(n) where n is the length of the string s.

  • The code iterates through the string once using enumerate(s), which takes O(n) time
  • Each iteration performs a constant time operation of assigning a character to a specific index in the ans array
  • The ''.join(ans) operation at the end also takes O(n) time to concatenate all characters
  • Total: O(n) + O(n) = O(n)

Space Complexity: O(n) where n is the length of the string s.

  • The ans list is created with size n to store the rearranged characters, requiring O(n) space
  • The output string created by ''.join(ans) also requires O(n) space, but this is typically considered part of the output and not counted as auxiliary space
  • No other significant auxiliary space is used
  • Total auxiliary space: O(n)

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Confusing the Direction of Index Mapping

The most common mistake is misunderstanding which way the index mapping works. Many people initially think that indices[i] tells us where to get the character FROM, rather than where to PUT the character TO.

Incorrect Understanding:

# WRONG: This treats indices[i] as the source position
result[i] = s[indices[i]]  # This would be incorrect!

Correct Understanding:

# RIGHT: indices[i] tells us the destination for s[i]
result[indices[i]] = s[i]

Example to Illustrate the Difference:

  • Given s = "abc" and indices = [2, 0, 1]
  • Wrong approach would produce: result[0] = s[2] = 'c', result[1] = s[0] = 'a', result[2] = s[1] = 'b' → "cab"
  • Correct approach produces: result[2] = s[0] = 'a', result[0] = s[1] = 'b', result[1] = s[2] = 'c' → "bca"

2. Using String Concatenation Instead of List

Building the result using string concatenation is inefficient and can lead to errors when trying to assign to specific indices:

Inefficient/Error-prone:

result = ""
for i, c in enumerate(s):
    result[indices[i]] = c  # ERROR: strings are immutable!

Better Approach:

result = [''] * len(s)  # Use a list for O(1) index assignment
for i, c in enumerate(s):
    result[indices[i]] = c
return ''.join(result)

3. Not Handling Edge Cases

While the problem typically guarantees valid input, in real scenarios you might want to validate:

  • Empty string or empty indices array
  • Mismatched lengths between s and indices
  • Invalid indices (duplicates or out of range)

Robust Solution with Validation:

def restoreString(self, s: str, indices: List[int]) -> str:
    # Validate input
    if not s or not indices:
        return s
  
    if len(s) != len(indices):
        raise ValueError("String and indices must have the same length")
  
    # Check for valid indices (optional validation)
    if len(set(indices)) != len(indices) or min(indices) < 0 or max(indices) >= len(s):
        raise ValueError("Invalid indices array")
  
    result = [''] * len(s)
    for i, c in enumerate(s):
        result[indices[i]] = c
  
    return ''.join(result)
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What's the output of running the following function using input 56?

1KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12def letter_combinations_of_phone_number(digits):
13    def dfs(path, res):
14        if len(path) == len(digits):
15            res.append(''.join(path))
16            return
17
18        next_number = digits[len(path)]
19        for letter in KEYBOARD[next_number]:
20            path.append(letter)
21            dfs(path, res)
22            path.pop()
23
24    res = []
25    dfs([], res)
26    return res
27
1private static final Map<Character, char[]> KEYBOARD = Map.of(
2    '2', "abc".toCharArray(),
3    '3', "def".toCharArray(),
4    '4', "ghi".toCharArray(),
5    '5', "jkl".toCharArray(),
6    '6', "mno".toCharArray(),
7    '7', "pqrs".toCharArray(),
8    '8', "tuv".toCharArray(),
9    '9', "wxyz".toCharArray()
10);
11
12public static List<String> letterCombinationsOfPhoneNumber(String digits) {
13    List<String> res = new ArrayList<>();
14    dfs(new StringBuilder(), res, digits.toCharArray());
15    return res;
16}
17
18private static void dfs(StringBuilder path, List<String> res, char[] digits) {
19    if (path.length() == digits.length) {
20        res.add(path.toString());
21        return;
22    }
23    char next_digit = digits[path.length()];
24    for (char letter : KEYBOARD.get(next_digit)) {
25        path.append(letter);
26        dfs(path, res, digits);
27        path.deleteCharAt(path.length() - 1);
28    }
29}
30
1const KEYBOARD = {
2    '2': 'abc',
3    '3': 'def',
4    '4': 'ghi',
5    '5': 'jkl',
6    '6': 'mno',
7    '7': 'pqrs',
8    '8': 'tuv',
9    '9': 'wxyz',
10}
11
12function letter_combinations_of_phone_number(digits) {
13    let res = [];
14    dfs(digits, [], res);
15    return res;
16}
17
18function dfs(digits, path, res) {
19    if (path.length === digits.length) {
20        res.push(path.join(''));
21        return;
22    }
23    let next_number = digits.charAt(path.length);
24    for (let letter of KEYBOARD[next_number]) {
25        path.push(letter);
26        dfs(digits, path, res);
27        path.pop();
28    }
29}
30

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More