Leetcode刷題總結:650. 2 Keys Keyboard


題目: 求獲取n個A的最小操作步驟的數目minStep

Initially on a notepad only one character 'A' is present. You can perform two operations on this notepad for each step:

  1. Copy All: 只能全部復制,不能部分復制.
  2. Paste: 拷貝留在剪貼板上的字符

Given a number n. You have to get exactly n 'A' on the notepad by performing the minimum number of steps permitted. Output the minimum number of steps to get n 'A'.

題解:

1.首先手寫幾個答案,可以看到:

  n=1, minSteps=0;

  n=2, 步驟:cp,minSteps=2

  n=3, 步驟:cpp, minSteps=3

  n=4, 步驟: cppp或者 cpcp(復制S[2]並粘貼一次),minSteps=4

  n=5, 步驟:cpppp=c+p*4,minSteps=5

  n=6, 步驟:c+p*5 或者 cp(cpp) (復制S[2]並粘貼2次) 或者 cpp(cp)(復制S[3]並粘貼1次), minSteps=5

  。。。。。

  n=12, 步驟:c+p*11

         或者 先取得“AA”然后c+p*5(這里5=(12-2)/2),S[n] = S[n/2] + 1+(n-2)/2 = S[n/2] + n/2

                       或者 先取得 “AAA”然后c+p*3(這里3=(12-3)/3),S[n] = S[n/3] + 1+(n-3)/3 = S[n/3] + n/3

                       或者 先取得“AAAA”然后c+p*2(這里2=(12-4)/4),S[n] = S[n/4] + 1+(n-4)/4 = S[n/4] + n/4

2. 從上面可以看到

  S[n] = min(S[n/i]+n/i) 其中i為能被n整除的數

  所以得到第一個思路代碼如下:

class Solution {
public:
    int minSteps(int n) {
        std::vector<int> minSteps(n+1,0);
        for (int i = 2; i <= n; ++i) {
            minSteps[i] = i;
        }
        for (int i = 4; i <= n; ++i) {
            for (int j = 2; j < i; ++j) {
                if (i % j == 0) {
                    minSteps[i] = min(minSteps[i], minSteps[j]+i/j);
                }
            }
        }
        return minSteps[n];
    }
};

3. 提交審核通過,但是發現運行速度不行,看起來的復雜度是O(n*n),69ms,只打敗了11%,再來看看有什么可以優化的:

  發現不需要中間層的遍歷不需要j<i. 在j< i/2就可以了;再次提交運行,復雜度仍然還是O(n2), 62ms

4. 自己沒有想到有什么能優化的地方,看了一下前面運行時間短的,發現內層循環的時候,循環條件是這樣的:

for (int j = i/2; j >= 2 && j % i != 0; --j);

  分析一下可以得到原因:事實上不管n等於幾,都應該盡可能地復制最多的字符,然后粘貼若干次,比如n=25=5*5,最快的應該是得到5個A然后copy1次粘貼4次,n=100=50*2,應該得到50,然后cp一次,修改代碼如下:

class Solution {
public:
    int minSteps(int n) {
        std::vector<int> minSteps(n+1,0);
        for (int i = 2; i <= n; ++i) {
            minSteps[i] = i;
        }
        for (int i = 4; i <= n; ++i) {
            for (int j = i/2; j >= 2; --j) {
                if (i % j == 0) {
                    minSteps[i] = min(minSteps[i], minSteps[j]+i/j);
                    break;
                }
            }
        }
        return minSteps[n];
    }
};

復雜度基本上是O(n)

 

5. 還有更快的解答,看了一下用的是遞歸,分析了一下,快的原因是在這里使用遞歸,並沒有重復計算,而且還省去了不必要的計算,復雜度遠小於O(n),

比如n=100,我的方法,要計算100+,

這里用遞歸,只需要計算n=100,n=50,n=25,n=5

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM