Open In App

How to print maximum number of A's using given four keys

Last Updated : 24 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

This is a famous interview question asked in Google and many other company interviews. Below is the problem statement.

Imagine you have a special keyboard with the following keys:
Key 1: Prints 'A' on screen
Key 2: (Ctrl-A): Select screen
Key 3: (Ctrl-C): Copy selection to buffer
Key 4: (Ctrl-V): Print buffer on screen appending it after what has already been printed.
If you can only press the keyboard for n times (with the above four keys), write a program to produce maximum numbers of A's on the screen.

Examples: 

Input: n = 3
Output: 3
Explanation: Press key 1 three times.

Input: n = 7
Output: 9
Explanation: The best key sequence is key 1, key 1, key 1, key 2, key 3, key4, key 4.

Below are few important points to note.
a) For n < 7, the output is n itself. 
b) Ctrl V can be used multiple times to print current buffer. The idea is to compute the optimal string length for n keystrokes by using a simple insight. The sequence of n keystrokes which produces an optimal string length will end with a suffix of Ctrl-A, a Ctrl-C, followed by only Ctrl-V's . (For n > 6)

[Naive Approach] Using Recursion - O(2 ^ n) time and O(n) space

  • The task is to find out the breakpoint after which we get the above suffix of keystrokes.
    Definition of a breakpoint is that instance after which we need to only press Ctrl-A, Ctrl-C once and then only Ctrl-V's afterward to generate the optimal length.
  • If we loop from n-3 to 1 and choose each of these values for the break-point, and compute that optimal string they would produce.
  • Once the loop ends, we will have the maximum of the optimal lengths for various breakpoints, thereby giving us the optimal length for n keystrokes.
C++
#include <iostream>
using namespace std;

int optimalKeys(int n) {
  
    // The optimal string length is n when n is smaller than 7
    if (n <= 6)
        return n;

    // Initialize result
    int max = 0;

    // Try all possible break-points 'b' after which we
    // will have Ctrl-A, Ctrl-C and then only Ctrl-V all the way.
    for (int b = n - 3; b >= 1; b--) {
        
        // If the breakpoint is b at b'th keystroke then the optimal
        // string would have length (n-b-1) * optimalKeys(b);
        int curr = (n - b - 1) * optimalKeys(b);
        if (curr > max)
            max = curr;
    }
    return max;
}

int main() {
    int n = 7;
    cout << optimalKeys(n) << endl;
}
Java
class GfG {

    static int optimalKeys(int n) {
        // The optimal string length is n when n is smaller than 7
        if (n <= 6)
            return n;

        // Initialize result
        int max = 0;

        // Try all possible break-points 'b' after which we
        // will have Ctrl-A, Ctrl-C and then only Ctrl-V all the way.
        for (int b = n - 3; b >= 1; b--) {
            
            // If the breakpoint is b at b'th keystroke then the optimal
            // string would have length (n - b - 1) * optimalKeys(b);
            int curr = (n - b - 1) * optimalKeys(b);
            if (curr > max)
                max = curr;
        }
        return max;
    }

    public static void main(String[] args) {
        int n = 7;
        System.out.println(optimalKeys(n));
    }
}
Python
def optimalKeys(n):
    # The optimal string length is n when n is smaller than 7
    if n <= 6:
        return n

    # Initialize result
    max_val = 0

    # Try all possible break-points 'b' after which we
    # will have Ctrl-A, Ctrl-C and then only Ctrl-V all the way.
    for b in range(n - 3, 0, -1):
        
        # If the breakpoint is b at b'th keystroke then the optimal
        # string would have length (n - b - 1) * optimalKeys(b);
        curr = (n - b - 1) * optimalKeys(b)
        if curr > max_val:
            max_val = curr
    return max_val
  
if __name__ == "__main__":
    n = 7
    print(optimalKeys(n))
C#
using System;

class GfG {
  
    static int optimalKeys(int n) {
        // The optimal string length is n when n is smaller than 7
        if (n <= 6)
            return n;

        // Initialize result
        int max = 0;

        // Try all possible break-points 'b' after which we
        // will have Ctrl-A, Ctrl-C and then only Ctrl-V all the way.
        for (int b = n - 3; b >= 1; b--) {
            
            // If the breakpoint is b at b'th keystroke then the 
            // optimal string would have length (n - b - 1) * optimalKeys(b);
            int curr = (n - b - 1) * optimalKeys(b);
            if (curr > max)
                max = curr;
        }
        return max;
    }

    static void Main() {
        int n = 7;
        Console.WriteLine(optimalKeys(n));
    }
}
JavaScript
function optimalKeys(n) {
    
    // The optimal string length is n
    // when n is smaller than 7
    if (n <= 6)
        return n;

    // Initialize result
    let max = 0;

    // Try all possible break-points 'b' after which we
    // will have Ctrl-A, Ctrl-C and then only Ctrl-V all the way.
    for(let b = n - 3; b >= 1; b--) {
        
        // If the breakpoint is b at b'th keystroke then the optimal
        // string would have length (n - b - 1) * optimalKeys(b);
        let curr = (n - b - 1) * optimalKeys(b);
        
        if (curr > max)
            max = curr;
    }
    return max;
}

let n = 7;
console.log(optimalKeys(n));

Output
9

[Better Approach] Using Dynamic Programming - O(n ^ 2) time and O(n) space

Below is a Dynamic Programming-based implementation where an auxiliary array screen[n] is used to store the results of subproblems. By solving smaller subproblems first and building upon them, the approach efficiently calculates the maximum number of 'A's for larger inputs, ensuring an scalable solution.

C++
#include <iostream>
using namespace std;

int optimalKeys(int n) {
    
    // The optimal string length is n when n is 
    // smaller than 7
    if (n <= 6)
        return n;

    int screen[n];

    // Initializing the optimal lengths array
    // for until 6 input strokes
    for (int i = 1; i <= 6; i++)
        screen[i - 1] = i;

    // Solve all subproblems in bottom manner
    for (int i = 7; i <= n; i++) {
        screen[i - 1] = 0;

        // For any keystroke n, we need to loop from n-3 keystrokes
        // back to 1 keystroke to find a breakpoint 'b' after which we
        // will have ctrl-a, ctrl-c and then only ctrl-v all the way.
        for (int b = i - 3; b >= 1; b--) {
            
            // If the breakpoint is at b'th keystroke then
            // the optimal string would have length
            // (i - b - 1) * screen[b - 1];
            int curr = (i - b - 1) * screen[b - 1];
            if (curr > screen[i - 1])
                screen[i - 1] = curr;
        }
    }

    return screen[n - 1];
}

int main() {
    int n = 7;
    cout << optimalKeys(n) << endl;
    return 0;
}
Java
import java.io.*;

class GfG {
    static int optimalKeys(int n) {
        // The optimal string length is n
        // when n is smaller than 7
        if (n <= 6)
            return n;

        int screen[] = new int[n];

        // Initializing the optimal lengths
        // array for until 6 input strokes
        for (int i = 1; i <= 6; i++)
            screen[i - 1] = i;

        // Solve all subproblems in bottom manner
        for (int i = 7; i <= n; i++) {
            
            // Initialize length of optimal
            // string for n keystrokes
            screen[i - 1] = 0;

            // For any keystroke n, we need
            // to loop from n-3 keystrokes
            // back to 1 keystroke to find
            // a breakpoint 'b' after which we
            // will have ctrl-a, ctrl-c and
            // then only ctrl-v all the way.
            for (int b = i - 3; b >= 1; b--) {
                // if the breakpoint is at b'th 
                // keystroke then the optimal string
                // would have length (i-b-1)*screen[b-1];
                int curr = (i - b - 1) * screen[b - 1];
                if (curr > screen[i - 1])
                    screen[i - 1] = curr;
            }
        }

        return screen[n - 1];
    }

    public static void main(String[] args) {
        int n = 7;
        System.out.println(optimalKeys(n));
    }
}
Python
def optimalKeys(n):

    # The optimal string length is
    # n when n is smaller than 7
    if (n <= 6):
        return n

    screen = [0] * n

    # Initializing the optimal lengths
    # array for until 6 input strokes.
    for i in range(1, 7):
        screen[i - 1] = i

    # Solve all subproblems in bottom manner
    for i in range(7, n + 1):

        # Initialize length of optimal
        # string for n keystrokes
        screen[i - 1] = 0

        # For any keystroke n, we need to loop from
        # n-3 keystrokes back to 1 keystroke to find a
        # breakpoint 'b' after which we will have ctrl-a,
        # ctrl-c and then only ctrl-v all the way.
        for b in range(i - 3, 0, -1):

            # if the breakpoint is at b'th keystroke then
            # the optimal string would have length
            # (i-b-1)*screen[b-1];
            curr = (i - b - 1) * screen[b - 1]
            if (curr > screen[i - 1]):
                screen[i - 1] = curr

    return screen[n - 1]


if __name__ == "__main__":
        n = 7
        print(optimalKeys(n))
C#
using System;

class GfG {
    static int optimalKeys(int n) {
        // The optimal string length is n when n is smaller
        // than 7
        if (n <= 6)
            return n;

        int[] screen = new int[n];

        // Initialize the optimal lengths array for up to 6
        // keystrokes
        for (int i = 1; i <= 6; i++)
            screen[i - 1] = i;

        // Solve all subproblems in a bottom-up manner
        for (int i = 7; i <= n; i++) {
            
            // Initialize length of the optimal string for n
            // keystrokes
            screen[i - 1] = 0;

            // For any keystroke n, loop from n-3 keystrokes
            // back to 1 keystroke to find a breakpoint 'b'
            // after which we will have Ctrl-A, Ctrl-C, and
            // then only Ctrl-V all the way.
            for (int b = i - 3; b >= 1; b--) {
                // If the breakpoint is at b'th keystroke,
                // the optimal string would have length (i - 
                // b - 1) * screen[b - 1];
                int curr = (i - b - 1) * screen[b - 1];
                if (curr > screen[i - 1])
                    screen[i - 1] = curr;
            }
        }

        return screen[n - 1];
    }

     static void Main(string[] args) {
       int n = 7;
       Console.WriteLine(optimalKeys(n));
    }
}
JavaScript
function optimalKeys(n) {
    
    // The optimal string length is n when n is smaller than 7
    if (n <= 6)
        return n;

    let screen = new Array(n);
    for (let i = 0; i < n; i++) {
        screen[i] = 0;
    }

    // Initializing the optimal lengths
    // array for until 6 input strokes
    for (let i = 1; i <= 6; i++)
        screen[i - 1] = i;

    // Solve all subproblems in bottom manner
    for (let i = 7; i <= n; i++) {
        
        // Initialize length of optimal string for n keystrokes
        screen[i - 1] = 0;

        // For any keystroke n, we need to loop from 
        // n-3 keystrokes back to 1 keystroke to find
        // a breakpoint 'b' after which we will have 
        // ctrl-a, ctrl-c and then only ctrl-v all the way.
        for (let b = i - 3; b >= 1; b--) {

            // If the breakpoint is at b'th keystroke then
            // the optimal string would have length 
            // (i-b-1)*screen[b-1];
            let curr = (i - b - 1) * screen[b - 1];

            if (curr > screen[i - 1])
                screen[i - 1] = curr;
        }
    }
    return screen[n - 1];
}

let n = 7;
console.log(optimalKeys(n));

Output
9

[Expected Approach] Using Dynamic Programming (Optimized) - O(n) time and O(n) space

As the number of A's increases, the benefit of pressing Ctrl-V more than three times becomes negligible compared to simply starting the sequence of Ctrl-A, Ctrl-C, and Ctrl-V again. Therefore, the above approach can be optimized by limiting the check to pressing Ctrl-V only 1, 2, or 3 times.

C++
#include <iostream>

using namespace std;

int optimalKeys(int n) {
    // The optimal string length is n when n is smaller than 7
    if (n <= 6)
        return n;

    // An array to store result of subproblems
    int screen[n];

    // Initialize the optimal lengths array for up to 6 keystrokes
    for (int i = 1; i <= 6; i++)
        screen[i - 1] = i;

    // Solve all subproblems in a bottom-up manner
    for (int i = 7; i <= n; i++) {
        // For any keystroke n, calculate the maximum of:
        // 1. Pressing Ctrl-V once after copying the A's
        //    obtained by (n-3) keystrokes.
        // 2. Pressing Ctrl-V twice after copying the A's
        //    obtained by (n-4) keystrokes.
        // 3. Pressing Ctrl-V thrice after copying the A's
        //    obtained by (n-5) keystrokes.
        screen[i - 1] = max(2 * screen[i - 4], 
                            max(3 * screen[i - 5], 
                                4 * screen[i - 6]));
    }

    return screen[n - 1];
}

int main() {
    int n = 7;
    cout << optimalKeys(n) << endl;

    return 0;
}
Java
class GfG {
    static int optimalKeys(int n) {
        
        // The optimal string length is n when n is smaller than 7
        if (n <= 6)
            return n;

        // An array to store result of subproblems
        int[] screen = new int[n];
      
        // Initializing the optimal lengths array for 
        // until 6 input strokes
        for (int i = 1; i <= 6; i++)
            screen[i - 1] = i;

        // Solve all subproblems in bottom-up manner
        for (int i = 7; i <= n; i++) {
            
            // for any keystroke n, we will need to choose between:
            // 1. pressing Ctrl-V once after copying the 
            //    A's obtained by n-3 keystrokes.
            // 2. pressing Ctrl-V twice after copying the A's 
            //    obtained by n-4 keystrokes.
            // 3. pressing Ctrl-V thrice after copying the A's 
            //    obtained by n-5 keystrokes.
            screen[i - 1] = Math.max(2 * screen[i - 4],
                                     Math.max(3 * screen[i - 5],
                                              4 * screen[i - 6]));
        }
        return screen[n - 1];
    }

    public static void main(String[] args) {
        int n = 7;
        System.out.println(optimalKeys(n));
    }
}
Python
def optimalKeys(n):
    # The optimal string length is n when n is smaller than 7
    if n <= 6:
        return n

    # An array to store result of subproblems
    screen = [0] * n

    # Initializing the optimal lengths array for until 6 input strokes
    for i in range(1, 7):
        screen[i - 1] = i

    # Solve all subproblems in bottom manner
    for i in range(7, n + 1):
        # for any keystroke n, we will need to choose between:
        # 1. pressing Ctrl-V once after copying the A's 
        #    obtained by n-3 keystrokes.
        # 2. pressing Ctrl-V twice after copying the A's 
        #    obtained by n-4 keystrokes.
        # 3. pressing Ctrl-V thrice after copying the A's 
        #    obtained by n-5 keystrokes.
        screen[i - 1] = max(2 * screen[i - 4],
                            max(3 * screen[i - 5],
                                4 * screen[i - 6]))

    return screen[n - 1]


if __name__ == "__main__":
    n = 7
    print(optimalKeys(n))
C#
using System;

class GfG {
    static int optimalKeys(int n) {
        // The optimal string length is n when n is smaller than 7
        if (n <= 6)
            return n;

        // An array to store result of subproblems
        int[] screen = new int[n];

        // Initializing the optimal lengths array for until 6 input strokes
        for (int i = 1; i <= 6; i++)
            screen[i - 1] = i;

        // Solve all subproblems in a bottom-up manner
        for (int i = 7; i <= n; i++) {
            // for any keystroke n, we will need to choose between:
            // 1. pressing Ctrl-V once after copying the A's 
            //    obtained by n-3 keystrokes.
            // 2. pressing Ctrl-V twice after copying the A's 
            //    obtained by n-4 keystrokes.
            // 3. pressing Ctrl-V thrice after copying the A's 
            //    obtained by n-5 keystrokes.
            screen[i - 1] = Math.Max(2 * screen[i - 4], 
                                    Math.Max(3 * screen[i - 5], 
                                            4 * screen[i - 6]));
        }

        return screen[n - 1];
    }

    static void Main(String[] args) {
        int n = 7;
        Console.WriteLine(optimalKeys(n));
    }
}
JavaScript
function optimalKeys(n) {
    // The optimal string length is n when n is smaller than 7
    if (n <= 6)
        return n;

    // An array to store result of subproblems
    let screen = [];
    
    // Initializing the optimal lengths array for until 6 input strokes
    for (let i = 1; i <= 6; i++)
        screen[i - 1] = i;

    // Solve all subproblems in bottom-up manner
    for (let i = 7; i <= n; i++) {
        // for any keystroke n, we will need to choose between:
        // 1. pressing Ctrl-V once after copying the A's 
        //    obtained by n-3 keystrokes.
        // 2. pressing Ctrl-V twice after copying the A's 
        //    obtained by n-4 keystrokes.
        // 3. pressing Ctrl-V thrice after copying the A's 
        //    obtained by n-5 keystrokes.
        screen[i - 1] = Math.max(2 * screen[i - 4],
                                 Math.max(3 * screen[i - 5], 
                                          4 * screen[i - 6]));
    }
    return screen[n - 1];
}

let n = 7
console.log(optimalKeys(n));

Output
9


Next Article

Similar Reads