Facebook Pixel

651. 4 Keys Keyboard 🔒

Problem Description

You have a special keyboard with four possible operations:

  1. A: Print one 'A' on the screen
  2. Ctrl-A: Select all text currently on the screen
  3. Ctrl-C: Copy the selected text to a buffer
  4. Ctrl-V: Paste the buffer content to the screen (appending it after existing text)

Given an integer n representing the maximum number of key presses allowed, determine the maximum number of 'A' characters you can print on the screen.

Each operation counts as one key press. For example:

  • Pressing 'A' uses 1 key press and adds 1 'A'
  • The copy-paste sequence (Ctrl-A, Ctrl-C, Ctrl-V) uses 3 key presses total and doubles the current text
  • Multiple Ctrl-V operations can be performed after a single copy operation

The challenge is to find the optimal combination of direct printing ('A') and copy-paste operations to maximize the total number of 'A' characters within n key presses.

For instance, with n = 7 key presses, you could:

  • Press 'A' 7 times to get 7 'A's
  • Or press 'A' 3 times, then Ctrl-A, Ctrl-C, Ctrl-V, Ctrl-V to get 9 'A's (3 initial, then paste twice for 3+3+3)

The solution uses dynamic programming where dp[i] represents the maximum number of 'A's achievable with i key presses. For each position, it considers all possible points where a copy-paste sequence could start to maximize the output.

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

Intuition

The key insight is recognizing when copy-paste becomes more efficient than simply pressing 'A' repeatedly. For small values of n, pressing 'A' directly is optimal. However, as n grows, strategically using copy-paste operations can multiply our output.

Think about what happens when we perform a copy-paste sequence:

  • Ctrl-A, Ctrl-C, Ctrl-V takes 3 key presses minimum
  • This sequence doubles what we currently have on screen
  • We can continue pressing Ctrl-V to keep pasting (each additional paste costs only 1 key press)

The crucial observation is that once we decide to start a copy operation at some point, we should consider using all remaining key presses for pasting. If we have x 'A's on screen and perform Ctrl-A, Ctrl-C followed by k Ctrl-V operations, we get x * (k + 1) total 'A's.

This leads to a dynamic programming approach where for each position i, we ask: "What if I stopped pressing 'A' at some earlier point j and used the remaining key presses for copy-paste operations?"

Breaking down the math:

  • At position j-1, we have dp[j-1] 'A's on screen
  • Position j starts our Ctrl-A (select all)
  • Position j+1 is Ctrl-C (copy)
  • Positions j+2 through i are all Ctrl-V (paste)
  • Number of pastes: i - j - 1
  • Total copies of the original text: i - j (including the original)
  • Final result: dp[j-1] * (i - j)

By trying all possible "switch points" j where we transition from typing to copying, we can find the optimal strategy. The formula dp[i] = max(dp[i], dp[j-1] * (i-j)) captures this relationship, where we compare keeping the current value versus the result of starting a copy sequence at position j.

Learn more about Math and Dynamic Programming patterns.

Solution Approach

We use dynamic programming to solve this problem. The approach builds up the solution incrementally, determining the maximum number of 'A's achievable for each number of key presses from 1 to n.

Initialization:

  • Create a DP array dp where dp[i] represents the maximum number of 'A's achievable with exactly i key presses
  • Initialize dp[i] = i for all positions, representing the base case of pressing 'A' i times

Dynamic Programming Transition: For each position i from 3 to n:

  • We maintain the current value dp[i] (pressing 'A' directly i times)
  • For each potential copy starting point j from 2 to i-2:
    • Calculate the result if we start copying at position j
    • The formula is: dp[j-1] * (i - j)
    • Where dp[j-1] is the number of 'A's before starting the copy sequence
    • And (i - j) is the multiplication factor from the copy-paste operations
    • Update dp[i] with the maximum value

Why the loop bounds?

  • We start from i = 3 because we need at least 3 operations for a meaningful copy-paste sequence
  • For j, we use range (2, i-1):
    • j >= 2 ensures we have at least one 'A' to copy (at position j-1)
    • j < i-1 ensures we have at least 3 positions for Ctrl-A, Ctrl-C, and one Ctrl-V

Time Complexity: O(n²) due to the nested loops Space Complexity: O(n) for the DP array

The algorithm effectively considers all possible strategies:

  1. Never copy (just press 'A' n times)
  2. Copy at various points and use remaining presses for pasting

By comparing all these strategies, we find the optimal number of 'A's achievable with n key presses, which is stored in dp[n] or dp[-1].

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

Let's walk through the solution with n = 7 key presses to find the maximum number of 'A's we can print.

Step 1: Initialize DP array

dp = [0, 1, 2, 3, 4, 5, 6, 7]

Each dp[i] initially represents pressing 'A' directly i times.

Step 2: Process each position starting from i = 3

When i = 3:

  • Current: dp[3] = 3 (pressing 'A' three times)
  • Try j = 2:
    • At position 1, we have dp[1] = 1 'A'
    • Operations: position 2 (Ctrl-A), position 3 (Ctrl-C)
    • No room for Ctrl-V, so this doesn't improve our result
  • Result: dp[3] = 3

When i = 4:

  • Current: dp[4] = 4
  • Try j = 2:
    • dp[1] * (4-2) = 1 * 2 = 2 (not better than 4)
  • Result: dp[4] = 4

When i = 5:

  • Current: dp[5] = 5
  • Try j = 2:
    • dp[1] * (5-2) = 1 * 3 = 3 (not better)
  • Try j = 3:
    • dp[2] * (5-3) = 2 * 2 = 4 (not better)
  • Result: dp[5] = 5

When i = 6:

  • Current: dp[6] = 6
  • Try j = 2:
    • dp[1] * (6-2) = 1 * 4 = 4 (not better)
  • Try j = 3:
    • dp[2] * (6-3) = 2 * 3 = 6 (equal, keep 6)
  • Try j = 4:
    • dp[3] * (6-4) = 3 * 2 = 6 (equal, keep 6)
  • Result: dp[6] = 6

When i = 7:

  • Current: dp[7] = 7
  • Try j = 2:
    • dp[1] * (7-2) = 1 * 5 = 5 (not better)
  • Try j = 3:
    • dp[2] * (7-3) = 2 * 4 = 8 ✓ (better!)
    • This means: Press 'A' twice (2 'A's), then Ctrl-A, Ctrl-C, Ctrl-V, Ctrl-V, Ctrl-V
    • Result: 2 + 2 + 2 + 2 = 8 'A's
  • Try j = 4:
    • dp[3] * (7-4) = 3 * 3 = 9 ✓ (even better!)
    • This means: Press 'A' three times (3 'A's), then Ctrl-A, Ctrl-C, Ctrl-V, Ctrl-V
    • Result: 3 + 3 + 3 = 9 'A's
  • Try j = 5:
    • dp[4] * (7-5) = 4 * 2 = 8 (not better than 9)
  • Result: dp[7] = 9

Final DP array:

dp = [0, 1, 2, 3, 4, 5, 6, 9]

The maximum number of 'A's with 7 key presses is 9, achieved by pressing 'A' three times, then copying and pasting that text twice.

Solution Implementation

1class Solution:
2    def maxA(self, n: int) -> int:
3        # dp[i] represents the maximum number of 'A's that can be produced with i keystrokes
4        dp = list(range(n + 1))  # Initialize: dp[i] = i (typing 'A' i times)
5      
6        # For each number of keystrokes from 3 to n
7        for i in range(3, n + 1):
8            # Try different positions to perform Ctrl+A, Ctrl+C, then multiple Ctrl+V
9            # j represents the position after which we start the copy-paste sequence
10            for j in range(2, i - 1):
11                # dp[j - 1]: max 'A's before starting copy operation
12                # (i - j): number of times we can paste after copy
13                # We need 2 keystrokes for Ctrl+A and Ctrl+C, then (i - j - 1) for pastes
14                # This gives us dp[j - 1] * (i - j) total 'A's
15                dp[i] = max(dp[i], dp[j - 1] * (i - j))
16      
17        # Return the maximum number of 'A's achievable with n keystrokes
18        return dp[-1]
19
1class Solution {
2    /**
3     * Finds the maximum number of 'A's that can be printed using n keystrokes.
4     * Available operations:
5     * 1. Print 'A' (1 keystroke)
6     * 2. Ctrl-A: Select all (1 keystroke)
7     * 3. Ctrl-C: Copy (1 keystroke)
8     * 4. Ctrl-V: Paste (1 keystroke)
9     * 
10     * @param n The total number of keystrokes allowed
11     * @return The maximum number of 'A's that can be printed
12     */
13    public int maxA(int n) {
14        // dp[i] represents the maximum number of 'A's achievable with i keystrokes
15        int[] dp = new int[n + 1];
16      
17        // Base case: with i keystrokes, we can print at most i 'A's directly
18        for (int i = 0; i <= n; i++) {
19            dp[i] = i;
20        }
21      
22        // For each number of keystrokes from 3 to n
23        for (int i = 3; i <= n; i++) {
24            // Try different positions to start the copy-paste sequence
25            // j represents the position after which we do Ctrl-A, Ctrl-C
26            for (int j = 2; j < i - 1; j++) {
27                // dp[j - 1]: number of 'A's before starting copy sequence
28                // After position j-1, we use 2 keystrokes for Ctrl-A and Ctrl-C
29                // Remaining keystrokes (i - j - 1) are used for Ctrl-V
30                // Total pastes: (i - j - 1), plus the original makes (i - j) copies
31                dp[i] = Math.max(dp[i], dp[j - 1] * (i - j));
32            }
33        }
34      
35        return dp[n];
36    }
37}
38
1class Solution {
2public:
3    int maxA(int n) {
4        // dp[i] represents the maximum number of 'A's that can be printed with i key presses
5        vector<int> dp(n + 1);
6      
7        // Initialize dp array: with i key presses, we can print at most i 'A's by pressing 'A' i times
8        iota(dp.begin(), dp.end(), 0);
9      
10        // For each number of key presses from 3 to n
11        for (int i = 3; i <= n; ++i) {
12            // Try different positions to start the copy-paste sequence
13            // j represents the position after which we perform Ctrl-A, Ctrl-C, then paste multiple times
14            for (int j = 2; j < i - 1; ++j) {
15                // dp[j - 1]: maximum 'A's we can get with (j - 1) key presses
16                // After position (j - 1), we use 2 keys for Ctrl-A and Ctrl-C
17                // Then we have (i - j - 1) key presses left for Ctrl-V (paste)
18                // Each paste multiplies the copied content, so total multiplier is (i - j)
19                dp[i] = max(dp[i], dp[j - 1] * (i - j));
20            }
21        }
22      
23        // Return the maximum number of 'A's that can be printed with n key presses
24        return dp[n];
25    }
26};
27
1function maxA(n: number): number {
2    // dp[i] represents the maximum number of 'A's that can be printed with i key presses
3    const dp: number[] = new Array(n + 1);
4  
5    // Initialize dp array: with i key presses, we can print at most i 'A's by pressing 'A' i times
6    for (let i = 0; i <= n; i++) {
7        dp[i] = i;
8    }
9  
10    // For each number of key presses from 3 to n
11    for (let i = 3; i <= n; i++) {
12        // Try different positions to start the copy-paste sequence
13        // j represents the position after which we perform Ctrl-A, Ctrl-C, then paste multiple times
14        for (let j = 2; j < i - 1; j++) {
15            // dp[j - 1]: maximum 'A's we can get with (j - 1) key presses
16            // After position (j - 1), we use 2 keys for Ctrl-A and Ctrl-C
17            // Then we have (i - j - 1) key presses left for Ctrl-V (paste)
18            // Each paste multiplies the copied content, so total multiplier is (i - j)
19            dp[i] = Math.max(dp[i], dp[j - 1] * (i - j));
20        }
21    }
22  
23    // Return the maximum number of 'A's that can be printed with n key presses
24    return dp[n];
25}
26

Time and Space Complexity

Time Complexity: O(n²)

The code uses a nested loop structure:

  • The outer loop runs from i = 3 to n, which is O(n) iterations
  • The inner loop runs from j = 2 to i - 1, which in the worst case (when i = n) runs approximately n - 2 times
  • Inside the inner loop, we perform constant time operations (max comparison and multiplication)
  • Therefore, the total time complexity is O(n) * O(n) * O(1) = O(n²)

Space Complexity: O(n)

The space complexity is determined by:

  • The dp array which stores n + 1 elements, requiring O(n) space
  • Only a constant amount of additional variables (i, j) are used
  • Therefore, the total space complexity is O(n)

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

Common Pitfalls

1. Incorrect Understanding of Copy-Paste Multiplication

Pitfall: A common mistake is misunderstanding how the copy-paste sequence multiplies the text. Some might think that after Ctrl-A, Ctrl-C, each Ctrl-V adds the copied content once, resulting in a formula like dp[j-1] * (i - j - 2 + 1) or similar incorrect calculations.

Why it happens: The confusion arises from not recognizing that:

  • Ctrl-A, Ctrl-C takes 2 operations
  • After copying, we have (i - j - 1) operations left for pasting
  • Each paste adds the original content, so with k pastes, we get (k+1) times the original content

Correct Understanding:

  • At position j-1: We have dp[j-1] A's
  • Operations j and j+1: Ctrl-A and Ctrl-C (select all and copy)
  • Operations j+2 to i: We have (i - j - 1) paste operations
  • Total A's = original + (number of pastes × original) = dp[j-1] * (i - j)

2. Off-by-One Errors in Loop Boundaries

Pitfall: Using incorrect loop boundaries like for j in range(1, i) or for j in range(2, i) instead of for j in range(2, i-1).

Why it matters:

  • If j is too small (j=1): We'd be trying to copy when we have 0 A's
  • If j is too large (j=i-1): We'd only have room for Ctrl-A, Ctrl-C with no paste operation
  • If j=i: We'd have no operations left after starting at position j

Solution: Ensure j ranges from 2 to i-2 (inclusive), which in Python is range(2, i-1). This guarantees:

  • At least one 'A' exists before copying (j-1 >= 1)
  • At least three operations remain for the copy-paste sequence (i - j >= 2)

3. Not Considering the Base Case Properly

Pitfall: Forgetting that for small values of n (n < 3), the optimal strategy is always to just press 'A' n times. Some implementations might try to apply copy-paste logic even when n is too small.

Solution: Initialize the DP array properly with dp[i] = i and start the optimization loop from i=3. This ensures:

  • dp[0] = 0 (no keystrokes = no A's)
  • dp[1] = 1 (one keystroke = one A)
  • dp[2] = 2 (two keystrokes = two A's)

4. Integer Overflow in Large Test Cases

Pitfall: For large values of n, the number of A's can grow exponentially through repeated copy-paste operations, potentially causing integer overflow in languages with fixed-size integers.

Solution:

  • In Python, this is generally not an issue due to arbitrary precision integers
  • In other languages, consider using appropriate data types (long long in C++, BigInteger in Java)
  • Add validation if the problem has constraints on the maximum output value

Example Trace to Avoid Confusion:

For n=7, let's trace through j=4 (copy after 3 A's):

  • Positions 1-3: Press 'A' three times → "AAA"
  • Position 4: Ctrl-A (select all)
  • Position 5: Ctrl-C (copy "AAA")
  • Position 6: Ctrl-V (paste) → "AAAAAA" (6 A's)
  • Position 7: Ctrl-V (paste) → "AAAAAAAAA" (9 A's)

The formula gives: dp[3] * (7 - 4) = 3 * 3 = 9 ✓

Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which data structure is used to implement priority queue?


Recommended Readings

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

Load More