Imagine you have a special keyboard with the following keys:
Key 1: (A)
: Print one 'A' on screen.
Key 2: (Ctrl-A)
: Select the whole 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.
Now, you can only press the keyboard for N times (with the above four keys), find out the maximum numbers of 'A' you can print on screen.
Example 1:
Input: N = 3 Output: 3 Explanation: We can at most get 3 A's on screen by pressing following key sequence: A, A, A
Example 2:
Input: N = 7 Output: 9 Explanation: We can at most get 9 A's on screen by pressing following key sequence: A, A, A, Ctrl A, Ctrl C, Ctrl V, Ctrl V
Note:
- 1 <= N <= 50
- Answers will be in the range of 32-bit signed integer.
這道題給了我們四個操作,分別是打印A,全選,復制,粘貼。每個操作都算一個步驟,給了我們一個數字N,問我們N個操作最多能輸出多個A。我們可以分析題目中的例子可以發現,N步最少都能打印N個A出來,因為我們可以每步都是打印A。那么能超過N的情況肯定就是使用了復制粘貼,這里由於全選和復制要占用兩步,所以能增加A的個數的操作其實只有N-2步,那么我們如何確定打印幾個A,剩下都是粘貼呢,其實是個trade off,A打印的太多或太少,都不會得到最大結果,所以打印A和粘貼的次數要接近,最簡單的方法就是遍歷所有的情況然后取最大值,打印A的次數在[1, N-3]之間,粘貼的次數為N-2-i,加上打印出的部分,就是N-1-i了,參見代碼如下:
解法一:
class Solution { public: int maxA(int N) { int res = N; for (int i = 1; i < N - 2; ++i) { res = max(res, maxA(i) * (N - 1 - i)); } return res; } };
這道題也可以用DP來做,我們用一個一維數組dp,其中dp[i]表示步驟總數為i時,能打印出的最多A的個數,初始化為N+1個,然后我們來想遞推公式怎么求。對於dp[i]來說,求法其實跟上面的方法一樣,還是要遍歷所有打印A的個數,然后乘以粘貼的次數加1,用來更新dp[i],參見代碼如下:
解法二:
class Solution { public: int maxA(int N) { vector<int> dp(N + 1, 0); for (int i = 0; i <= N; ++i) { dp[i] = i; for (int j = 1; j < i - 2; ++j) { dp[i] = max(dp[i], dp[j] * (i - j - 1)); } } return dp[N]; } };
這道題還有個O(1)時間復雜度的解法,好像利用了數學知識,不過博主貌似沒太理解,參見這個帖子,哪位大神給博主講解一下?
類似題目:
參考資料:
https://discuss.leetcode.com/topic/97764/o-1-time-o-1-space-c-solution-possibly-shortest-and-fastest