Problem
There is only one character 'A'
on the screen of a notepad. You can perform one of two operations on this notepad for each step:
- Copy All: You can copy all the characters present on the screen (a partial copy is not allowed).
- Paste: You can paste the characters which are copied last time.
Given an integer n
, return the minimum number of operations to get the character 'A'
exactly n
times on the screen.
Examples
Example 1:
Input: n = 3
Output: 3
Explanation: Initially, we have one character 'A'.
In step 1, we use Copy All operation.
In step 2, we use Paste operation to get 'AA'.
In step 3, we use Paste operation to get 'AAA'.
Example 2:
Input: n = 1
Output: 0
Example 3:
Input: n = 6
Output: 5
Explanation: We have 2 options:
Option 1:
Copy All – this will copy ‘A’
Paste – output “AA”
Paste – output “AAA”
Paste – output “AAAA”
Paste – output “AAAAA”
Paste – output “AAAAAA”
Total operations – 6
Option 2:
Copy All – this will copy ‘A’
Paste – output “AA”
Paste – output “AAA”
Copy All
Paste – output “AAAAAA”
Total operations – 5
Since with option 2, the task is done in 5 operations. Minimum operations – 5
Solution
Video Explanation
Here is the video explanation discussing different solutions we have covered below:
Method 1 - Using factors
In worst case we need to copy the character and paste it n-1
times to get the desired result. Now, lets see how we can minimize it, with different number of operations.
- 2 operations ⇨ copy + paste ⇨ we get AA (i.e. double). The ratio of operations to size is
2:2
. - 3 operations ⇨ copy + paste + paste ⇨ we get AAA (i.e. triple). The ratio of operations to size is
3:3
. - 4 operations ⇨ copy + paste + paste + paste ⇨ AAAA (i.e. quadruple). The ratio is
4:4
. - 5 operations
- copy + 4 X paste ⇨ AAAAA (i.e. 5 times)
- but, combining the two and three operations sequences can multiply the number of lines by 6 for the same number of operations. i.e. copy + paste ⇨ AA + copy + 2X paste ⇨ AAAAAA
Since we want to reduce the number of operations we need to reduce the paste operations where ever it is possible which means perform the copy operation. Say If n = 50
then we print 25 A’s then by doing copy all and paste will print 50 characters. Now to reach 25, which is multiple of 5 so if we print 5 A’s then copy and paste it 4 times to get 25 A’s and now to print 5 A’s, copy the already printed A and paste it 4 times.
n = 50
Copy + 4 X Paste = AAAAA => 5 operations
Copy + 4 X Paste = AA...AA(25 As) => 5 operations, total operations = 10
Copy and paste – printed – AA...AAA (50 As) => 2 operations, total operations = 10 + 2 = 12
Code
Java
public class Solution {
public int minSteps(int n) {
int steps = 0;
int factor = 2;
while (n > 1) {
while (n % factor == 0) { // check if problem can be broken in smaller problems
steps += factor; //if yes then add no of smaller problems to result. If number = 25 i = 5 then 5*5 = 25 so add 5 to results
n /= factor; // create smaller problem
}
factor++;
}
return steps;
}
}
Complexity
- ⏰ Time complexity:
O(n)
- 🧺 Space complexity:
O(1)
Method 2 - Recursion
The key insight is that copying isn’t necessary every time; pasting multiple times after a copy is more efficient. For instance, to get 9 ‘A’s, we might:
- Start with ‘A’
- Copy All (clipboard: ‘A’)
- Paste (now ‘AA’)
- Copy All (clipboard: ‘AA’)
- Paste (now ‘AAAA’)
- Paste again (now ‘AAAAAA’)
- Copy All (clipboard: ‘AAAAAA’)
- Paste (now ‘AAAAAAAAAAAA’)
This example overshoots, highlighting the need for strategic copying and pasting. Thus, experimenting with different copy-paste combinations becomes vital, and recursion helps explore these combinations effectively.
Let’s define our function f(i,j)
more formally:
f(i,j)
represents the minimum number of operations needed to generaten
A’s, starting withi
A’s on the screen andj
A’s in the clipboard.
Our objective is to find ( f(1, 1) ), which means starting with one ‘A’ on the screen and one ‘A’ in the clipboard.
At each step, we have two options:
- Copy All and Paste:
- Takes 2 steps (1 Copy, 1 Paste).
- Transforms state from
(i,j)
to(2i, i)
. - Total operations:
2 + f(2i, i) )
- Paste Only:
- Takes 1 step.
- Transforms state from
(i,j)
to(i + j, j)
. - Total operations:
1 + f(i + j, j)
.
Thus, the recurrence relation is: $$ f(i, j) = \min(2 + f(2i, i), 1 + f(i + j, j)) $$
This relation captures the essence of choosing the minimum number of operations between the two options at each step.
Base cases:
- If ( i = n ), we’ve achieved our goal, so ( f(n, j) = 0 ) for any
j
. - If ( i > n ), we’ve overshot, so return a very large number (effectively infinity).
Code
Java
public class Solution {
private static final int INF = 1001; // Define a large number to denote invalid paths
public int minSteps(int n) {
if (n == 1) {
return 0; // We already have one 'A', so no operations needed
}
return 1 + findMinSteps(1, 1, n); // Start with one 'A' on screen and in clipboard
}
private int findMinSteps(int currLen, int clipboardLen, int n) {
if (currLen == n) {
return 0; // We've reached our goal, no more operations needed
}
if (currLen > n) {
return INF; // We've overshot, this path is invalid
}
// Try Copy All and Paste
int copyAndPaste = 2 + findMinSteps(currLen * 2, currLen, n);
// Try Paste only
int pasteOnly = 1 + findMinSteps(currLen + clipboardLen, clipboardLen, n);
// Return the minimum of the two options
return Math.min(copyAndPaste, pasteOnly);
}
}
Complexity
- ⏰ Time complexity:
O(2^n)
because at each step we have 2 options to choose from and then we take min. - 🧺 Space complexity:
O(n)
Method 3 - Top Down DP
Code
Java
public class Solution {
private static final int INF = 1001; // Define a large number to denote invalid paths
private int[][] cache;
public int minSteps(int n) {
if (n == 1) {
return 0; // We already have one 'A', so no operations needed
}
this.cache = new int[n + 1][n / 2 + 1];
return 1
+ findMinSteps(1, 1, n); // Start with one 'A' on screen and in clipboard
}
private int findMinSteps(int currLen, int clipboardLen, int n) {
if (currLen == n) {
return 0; // We've reached our goal, no more operations needed
}
if (currLen > n) {
return INF; // We've overshot, this path is invalid
}
if (cache[currLen][clipboardLen] != 0) {
return cache[currLen][clipboardLen];
}
// Try Copy All and Paste
int copyAndPaste = 2 + findMinSteps(currLen * 2, currLen, n);
// Try Paste only
int pasteOnly = 1 + findMinSteps(currLen + clipboardLen, clipboardLen, n);
// Return the minimum of the two options
int ans = Math.min(copyAndPaste, pasteOnly);
cache[currLen][clipboardLen] = ans;
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(n^2)
- In the worst case, we might need to fill out our entire cache. The cache has dimensions n × (n/2), where n is our target length. For each cell, we’re doing constant time operations. Therefore, our time complexity is O(n * n/2) = O(n^2).
- 🧺 Space complexity:
O(n^2)
assuming recursion stack and using cache
Method 4 - Bottom up DP
Code
Java
public class Solution {
private static final int INF = 1001;
public int minSteps(int n) {
if (n == 1) {
return 0; // We already have one 'A', so no operations needed
}
int[][] dp = new int[n + 1][n + 1];
// Initialize DP table with a large number to denote invalid paths
for (int i = 0; i <= n; i++) {
for (int j = 0; j <= n; j++) {
dp[i][j] = INF;
}
}
// Starting point
dp[1][0] = 0;
for (int i = 1; i < n; i++) {
for (int j = 0; j <= i; j++) {
// Paste Operation
if (i + j <= n) {
dp[i + j][j] = Math.min(dp[i + j][j], dp[i][j] + 1);
}
// Copy All and Paste Operation
if (i * 2 <= n) {
dp[i * 2][i] = Math.min(dp[i * 2][i], dp[i][j] + 2);
}
}
}
int minSteps = INF;
for (int i = 0; i <= n; i++) {
minSteps = Math.min(minSteps, dp[n][i]);
}
return minSteps;
}
}
Complexity
- ⏰ Time complexity:
O(n^2)
- 🧺 Space complexity:
O(n^2)
for usingdp
array
Method 5 - Optimized Bottom up DP
Code
Java
class Solution {
public int minSteps(int n) {
if (n == 1) {
return 0;
}
int[] dp = new int[n + 1];
dp[1] = 0;
for (int i = 2; i <= n; i++) {
dp[i] = i;
for (int j = i / 2; j >= 1; j--) {
if (i % j == 0) {
// steps to previous number + copy + paste
dp[i] = dp[j] + 1 + ((i / j) - 1);
break;
}
}
}
return dp[n];
}
}
Complexity
- ⏰ Time complexity:
O(n^2)
- 🧺 Space complexity:
O(n)