Bird
Raised Fist0
Interview Prepgreedy-algorithmsmediumAmazonGoogleFacebook

Reorganize String (No Two Adjacent Same)

Choose your preparation mode4 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Steps
setup

Count character frequencies

Count the frequency of each character in the input string 'aab'. The counts are: 'a' -> 2, 'b' -> 1.

💡 Knowing character frequencies is essential to prioritize which character to place next to avoid adjacency conflicts.
Line:freq = Counter(s)
💡 Frequency counts determine the initial priorities for the heap.
📊
Reorganize String (No Two Adjacent Same) - Watch the Algorithm Execute, Step by Step
Watching each heap operation and character selection step reveals how the greedy approach ensures no two adjacent characters are the same.
Step 1/15
·Active fillAnswer cell
setupmax-heap
empty heap
heapifymax-heap
-2
0
-1
1
setupmax-heap
-2
0
-1
1
extract_maxmax-heap
-1
0
Added: "a"
insertmax-heap
-1
0
Added: "a"
insertmax-heap
-1
0
setupmax-heap
-1
0
extract_maxmax-heap
empty heap
Added: "b"
insertmax-heap
empty heap
Added: "b"
insertmax-heap
-1
0
setupmax-heap
-1
0
extract_maxmax-heap
empty heap
Added: "a"
insertmax-heap
empty heap
Added: "a"
insertmax-heap
empty heap
peekmax-heap
empty heap
Added: "aba"

Key Takeaways

The max heap prioritizes characters by frequency, ensuring the most frequent character is placed first.

This insight is hard to see from code alone because the heap operations are abstract; visualization shows the priority clearly.

Holding and reinserting the previous character prevents placing the same character twice consecutively.

This mechanism is subtle in code but critical; visualization reveals how the algorithm avoids adjacency conflicts.

The algorithm terminates successfully only if the result length matches the input length, confirming a valid rearrangement.

This final check is easy to overlook in code but essential to detect impossible cases.

Practice

(1/5)
1. Given the following Python code for assigning cookies to children, what is the final returned value when g = [1, 2, 3] and s = [1, 1]?
easy
A. 0
B. 1
C. 2
D. 3

Solution

  1. Step 1: Trace first iteration

    g and s sorted: g=[1,2,3], s=[1,1]. i=0, j=0, count=0. s[0]=1 ≥ g[0]=1 -> count=1, i=1, j=1.
  2. Step 2: Trace second iteration

    i=1, j=1, count=1. s[1]=1 < g[1]=2 -> j=2. Loop ends as j=2 equals len(s).
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Only one cookie satisfies a child's greed [OK]
Hint: Trace pointer increments carefully [OK]
Common Mistakes:
  • Counting cookies not sufficient for greed
  • Off-by-one in loop conditions
  • Ignoring pointer increments
2. Given the following code snippet implementing the optimal candy distribution algorithm, what is the final returned value when input ratings = [1, 0, 2]?
easy
A. 3
B. 5
C. 4
D. 6

Solution

  1. Step 1: Trace left-to-right pass

    ratings = [1,0,2], candies init = [1,1,1] - i=1: ratings[1]=0 < ratings[0]=1, no change - i=2: ratings[2]=2 > ratings[1]=0, candies[2] = candies[1]+1 = 2 candies after pass: [1,1,2]
  2. Step 2: Trace right-to-left pass

    i=1: ratings[1]=0 < ratings[2]=2, no change i=0: ratings[0]=1 > ratings[1]=0 and candies[0]=1 <= candies[1]=1, update candies[0] = candies[1]+1 = 2 candies after pass: [2,1,2] Sum = 2+1+2 = 5
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Sum matches expected output 5 [OK]
Hint: Sum candies after two passes for final answer [OK]
Common Mistakes:
  • Forgetting to update candies in right-to-left pass
  • Off-by-one errors in loops
  • Misreading comparison operators
3. Consider the following buggy code for candy distribution. Which line contains the subtle bug that can cause incorrect candy counts?
medium
A. Line 3: candies initialized with zeros instead of ones
B. Line 5: loop starts from 1 instead of 0
C. Line 7: candies[i] updated without checking if greater than candies[i-1]
D. Line 9: condition candies[i] <= candies[i + 1] missing

Solution

  1. Step 1: Check initialization of candies array

    Line 3 initializes candies with zeros, violating the problem requirement that each child must have at least one candy.
  2. Step 2: Understand impact of zero initialization

    Zero candies can cause incorrect comparisons and final sums, failing test cases where minimum is 1 per child.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Initialization must be at least 1 per child [OK]
Hint: Candies must start at 1, not 0 [OK]
Common Mistakes:
  • Forgetting minimum candy per child
  • Incorrect loop boundaries
  • Missing update conditions
4. Identify the bug in the following code snippet for the Minimum Domino Rotations problem:
def minDominoRotations(A, B):
    def check(x):
        rotations_a = rotations_b = 0
        for i in range(len(A)):
            if A[i] != x and B[i] != x:
                return 0  # Bug here
            elif A[i] != x:
                rotations_a += 1
            elif B[i] != x:
                rotations_b += 1
        return min(rotations_a, rotations_b)

    rotations = check(A[0])
    if rotations != -1:
        return rotations
    else:
        return check(B[0])
medium
A. Incorrect initialization of rotations_a and rotations_b
B. Not incrementing rotations when both sides equal x
C. Returning rotations without checking both candidates
D. The return value 0 instead of -1 when no domino can be rotated to x

Solution

  1. Step 1: Analyze early return condition

    If neither side matches candidate x, the function should return -1 to indicate failure, not 0.
  2. Step 2: Impact of returning 0

    Returning 0 falsely indicates zero rotations needed, causing incorrect positive results.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Returning -1 signals no solution; 0 misleads caller [OK]
Hint: Return -1 on failure, not 0 [OK]
Common Mistakes:
  • Returning 0 instead of -1 on failure
  • Overcounting rotations when both sides equal candidate
5. Suppose the problem is modified: instead of finding the largest monotone increasing digits number ≤ n, you want the largest monotone increasing digits number ≤ n that can reuse digits any number of times (digits can be repeated arbitrarily). Which approach correctly adapts the algorithm?
hard
A. Use the original greedy algorithm but allow digits after marker to be any digit less than or equal to the digit at marker-1
B. Sort the digits of n and build the largest monotone number by repeating the smallest digit as many times as needed
C. Use a backtracking approach to generate all monotone numbers with digits ≤ those in n, allowing reuse, and pick the largest ≤ n
D. Modify the greedy algorithm to decrement digits and set trailing digits to the digit at marker-1 instead of 9

Solution

  1. Step 1: Understand digit reuse changes problem nature

    Allowing reuse means digits can be repeated arbitrarily, so greedy digit decrement and trailing 9 assignment no longer guarantee largest monotone number ≤ n.
  2. Step 2: Backtracking enumerates all monotone numbers with digit reuse

    Backtracking can generate all monotone numbers with digits ≤ those in n, allowing reuse, then pick the largest ≤ n.
  3. Step 3: Other options fail to handle reuse or produce incorrect numbers

    Sorting digits or modifying trailing digits to marker-1 digit does not guarantee largest monotone number with reuse.
  4. Final Answer:

    Option C -> Option C
  5. Quick Check:

    Backtracking correctly handles reuse and monotonicity constraints [OK]
Hint: Digit reuse breaks greedy; backtracking needed for correctness [OK]
Common Mistakes:
  • Trying to adapt greedy without full enumeration
  • Assuming trailing digits can be set to 9 or marker digit
  • Ignoring exponential complexity of reuse