2. Ctrl+A
3. Ctrl+C
4. Ctrl+V
If you can only press the keyboard for N times (with the above four keys), please write a program to produce maximum numbers of A. If possible, please also print out the sequence of keys.
So the input parameter is N (No. of keys that you can press), the output is M (No. of As that you can produce).
-------------------------------------------------------------
We define dp[i] as the output give the input parameter i
Using Ctrl A + Ctrl C + Ctrl V + Ctrl V...the result is
dp[i] = max(dp[i-3]*1, dp[i-4]*2, ...dp[i-9]*7, dp[i-10]*8,.... )
Take Notice that Ctrl A + Ctrl C + Ctrl V won't double the sequence because the cursor doesn't move
While Using Ctrl A + Ctrl C + Ctrl V + Ctrl V + Ctrl A + Ctrl C + Ctrl V + Ctrl V ...
dp[i] = max(dp[i-4]*2, dp[i-8]*4, dp[i-12]*8, dp[i-16]*16...)
While Using Ctrl A + Ctrl C + Ctrl V + Ctrl V + Ctrl V + Ctrl A + Ctrl C + Ctrl V + Ctrl V + Ctrl V...
dp[i] = max(dp[i-5]*3, dp[i-10]*9, dp[i-15]*9...)
................
Pay attention to dp[i] = dp[i-9]*7 or dp[i-4]*2 && dp[i-5]*3, however, 7 > 2 * 3
But for dp[i] = dp[i-10]*8 or dp[i-5]*3 && dp[i-5]*3, 3*3 > 8
and dp[i] = dp[i-11]*9 or dp[i-5]*3 && dp[i-6]*4, 3*4 > 9
Divide a number num into x and y, (x - 2) * (y -2) arrives the maximum when x tends to y adequately.
So,
When num >= 10 , (x-2) * (y-2) is larger than num-2
Then
dp[i] = max(dp[i-3]*1, dp[i-4]*2, ...dp[i-9]*7 )
Here is the code:
#include <stdio.h>
#include <string>
#include <iostream>
#include <map>
#include <string.h>
#include <vector>
using namespace std;
class Node {
public:
int x,y;
Node(int x = 0, int y = 0):x(x),y(y) {}
};
int findMaxK(int n) {
int power = 2;
double max = 0.0;
int maxK = 0;
while (n > 0) {
n -= 2;
double t = (double)n/power;
double r = pow(t, (double)power);
if (r > max) {
maxK = power;
max = r;
}
power++;
}
return maxK;
}
unsigned int f(int n) {
if (n <= 7) return n;
int k = findMaxK(n);
int sum = n - 2*(k-1);
unsigned int mul = 1;
while (k > 0) {
int avg = sum/k;
mul *= avg;
k--;
sum -= avg;
}
return mul;
}
int g(int n) {
int size = max(n, 9), i, j;
vector<int> dp(n + 1, 0);
int arr[] = {0, 1, 2, 3, 4, 5, 6, 7, 9, 12};
for (i = 0; i <= 9; ++i)
dp[i] = arr[i];
if (n <= 9)
return dp[n];
for (i = 9; i <= n; ++i) {
dp[i] = dp[i - 3];
for (j = 4; j <= 9; ++j)
dp[i] = max(dp[i], dp[i - j] * (j - 2));
}
return dp[n];
}
int main() {
int res1 = f(90);
int res2 = g(90);
return 0;
}
The function f is another method from leetcode, but I don't like it..
This question seemed like a brand new interview question from Google. Someone posted this problem on adiscussion board, and it generated a lot of discussions, which unfortunately none of them is really helpful in solving this problem. Here, I discuss my approach and solution to this problem, and just like those other tricky questions from a typical Google interview — the common pitfalls you might fall into.
One common strategy in problem solving is to always begin with small examples.
It is trivial to notice that for N <= 6, M = N. But how about the case where N = 7? Here is where the most common pitfall that most people would fall into (myself included).
Most people reason that for N = 7, the answer is M = 8, because the sequence S = { A, A, A, A, CTRL+A, CTRL+C, CTRL+V } produces a total of 8 A’s.
Wait, the copied text is still in the buffer after a paste operation. We could have applied CTRL+V twice to double the previous text, sweet!
How about S = { A, A, A, CTRL+A, CTRL+C, CTRL+V, CTRL+V } which produces a total of 9 A’s?
Unfortunately, both of the above answers are incorrect, as the correct answer for N = 7 is M = 7. This is simply because the sequence of { CTRL+A, CTRL+C, CTRL+V } does not double the previous text. Why? Take a moment to let this to sink into your brain.
Answers for N up to 7 is easy, which is M = N. But how about N = 8?
For N = 8 the answer is M = 9, where S = { A, A, A, CTRL+A, CTRL+C, CTRL+V, CTRL+V, CTRL+V }.
For N = 9 the answer is M = 12, where S = { A, A, A, CTRL+A, CTRL+C, CTRL+V, CTRL+V, CTRL+V, CTRL+V }.
You might ask why all A’s are typed before the sequence of { CTRL+A, CTRL+C, CTRL+V } operations.
Assume that we could insert A’s at the back of some sequence of { CTRL+A, CTRL+C, CTRL+V } and yield a maximum sequence. If we take all the A’s from the back and insert it at the front, this modified sequence must yield a larger number of A’s, since the number of A’s is multipled from the beginning. Therefore, by contradiction, all A’s must always be inserted at the front to yield the maximum number of A’s. Similar for the case where A’s are inserted in the middle of the sequence.
Before we proceed further, we introduce the following notation:
- Define 4A as a sequence of { A, A, A, A }. Therefore, 5A would then mean { A, A, A, A, A }.
- Define 2D as a sequence of CTRL+A, CTRL+C, CTRL+V, CTRL+V, which simply means double the previous text. Note that 3D does not double the previous text, it actually triples the previous text.
With this notation in place, it is much easier to work with this problem. Using the above notation, we rewrite our answer for N = 8 and N = 9.
N = 8, S = { 3A3D }, M = 9.
N = 9, S = { 3A4D }, M = 12.
The value of M could be obtained simply by multiplying the numbers, isn’t that neat?
Working our way up:
N = 10, S = { 4A4D }, M = 16.
N = 11, S = { 5A4D }, M = 20.
As you can see, the pattern here is pretty obvious, let’s summarize as follow:
- The solution so far for N > 7 is to find integers a and b such that ab yields the largest product, subjected to the condition where a+b = N-2.
- Both a and b are easy to find, as the largest product is found when the difference of a and b is less than or equal to one.
Similarly,
N = 12, S = { 5A5D }, M = 25.
N = 13, S = { 5A6D }, M = 30.
N = 14, S = { 6A6D }, M = 36.
Be extra cautious for N = 15.
When N = 15, does the sequence { 6A7D } yields the maximum where M = 42?
Imagine if you have a very large number of keystrokes to enter, does pressing CTRL+V forever gives you the maximum sequence? Remember, you can redo the entire { CTRL+A, CTRL+C, CTRL+V } operations again and potentially maximizes the sequence.
For N = 15, the maximum sequence should be:
{ 3A4D4D }, which yields M = 48.
Similarly,
N = 16, S = { 4A4D4D }, M = 64.
…
N = 21, S = { 3A4D4D4D }, M = 192.
…
N = 25, S = { 4A5D5D5D }, M = 500.
N = 26, S = { 5A5D5D5D }, M = 625.
N = 27, S = { 3A4D4D4D4D }, M = 768.
Let’s generalize the above:
where
a1 + a2 + … + ak = n – 2(k-1)
To obtain M = MAX (a1 . a2 … ak),
it is necessary that the below condition must be met:
To obtain M, we can first divide a1 + a2 + … + ak by k to obtain the average as a reference, and the rest should be straightforward.
Now the final problem lies in how to obtain the value of k efficiently. I am pretty sure this could be solved easily using Number Theory, but so far, my best solution is to use a brute force method to obtain k.
Below is the C++ code for my solution. It is pretty straightforward to output the sequence S. Given N, the functionf() returns the maximum value of M.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include <iostream>
#include <cmath>
#include <cassert>
using
namespace
std
;
int
findMaxK
(
int
n
)
{
int
power
=
2
;
double
max
=
0.0
;
int
maxK
=
0
;
while
(
n
>
0
)
{
n
-
=
2
;
double
t
=
(
double
)
n
/
power
;
double
r
=
pow
(
t
,
(
double
)
power
)
;
if
(
r
>
max
)
{
maxK
=
power
;
max
=
r
;
}
power
++
;
}
return
maxK
;
}
unsigned
int
f
(
int
n
)
{
if
(
n
<=
7
)
return
n
;
int
k
=
findMaxK
(
n
)
;
int
sum
=
n
-
2
*
(
k
-
1
)
;
unsigned
int
mul
=
1
;
while
(
k
>
0
)
{
int
avg
=
sum
/
k
;
mul *
=
avg
;
k
--
;
sum
-
=
avg
;
}
assert
(
sum
==
0
)
;
return
mul
;
}
|