Leetcode刷题总结:650. 2 Keys Keyboard
2017-08-27 17:04
281 查看
题目: 求获取n个A的最小操作步骤的数目minStep
Initially on a notepad only one character 'A' is present. You can perform two operations on this notepad for each step:
Given a number
题解:
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
= S[n/2] + 1+(n-2)/2 = S[n/2] + n/2
或者 先取得 “AAA”然后c+p*3(这里3=(12-3)/3),S
= S[n/3] + 1+(n-3)/3 = S[n/3] + n/3
或者 先取得“AAAA”然后c+p*2(这里2=(12-4)/4),S
= S[n/4] + 1+(n-4)/4 = S[n/4] + n/4
2. 从上面可以看到
S
= min(S[n/i]+n/i) 其中i为能被n整除的数
所以得到第一个思路代码如下:
3. 提交审核通过,但是发现运行速度不行,看起来的复杂度是O(n*n),69ms,只打败了11%,再来看看有什么可以优化的:
发现不需要中间层的遍历不需要j<i. 在j< i/2就可以了;再次提交运行,复杂度仍然还是O(n2), 62ms
4. 自己没有想到有什么能优化的地方,看了一下前面运行时间短的,发现内层循环的时候,循环条件是这样的:
分析一下可以得到原因:事实上不管n等于几,都应该尽可能地复制最多的字符,然后粘贴若干次,比如n=25=5*5,最快的应该是得到5个A然后copy1次粘贴4次,n=100=50*2,应该得到50,然后cp一次,修改代码如下:
复杂度基本上是O(n)
5. 还有更快的解答,看了一下用的是递归,分析了一下,快的原因是在这里使用递归,并没有重复计算,而且还省去了不必要的计算,复杂度远小于O(n),
比如n=100,我的方法,要计算100+,
这里用递归,只需要计算n=100,n=50,n=25,n=5
Initially on a notepad only one character 'A' is present. You can perform two operations on this notepad for each step:
Copy All: 只能全部复制,不能部分复制.
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
= S[n/2] + 1+(n-2)/2 = S[n/2] + n/2
或者 先取得 “AAA”然后c+p*3(这里3=(12-3)/3),S
= S[n/3] + 1+(n-3)/3 = S[n/3] + n/3
或者 先取得“AAAA”然后c+p*2(这里2=(12-4)/4),S
= S[n/4] + 1+(n-4)/4 = S[n/4] + n/4
2. 从上面可以看到
S
= 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 ; } };
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 ; } };
复杂度基本上是O(n)
5. 还有更快的解答,看了一下用的是递归,分析了一下,快的原因是在这里使用递归,并没有重复计算,而且还省去了不必要的计算,复杂度远小于O(n),
比如n=100,我的方法,要计算100+,
这里用递归,只需要计算n=100,n=50,n=25,n=5
相关文章推荐
- LeetCode - 650 - 2 Keys Keyboard
- LeetCode 650 - 2 Keys Keyboard
- LeetCode: -Dynamic Programming-2 Keys Keyboard[650]-复制粘贴问题
- Leetcode刷题:650. 2 Keys Keyboard
- leetcode650 2 Keys Keyboard
- LeetCode 650 2 Keys Keyboard - LeetCode Weekly Contest 43
- leetcode做题总结,题目Sort List 2013/11/16
- Leetcode: Longest Substring with At Most K Distinct Characters && Summary: Window做法两种思路总结
- leetcode刷题,总结,记录,备忘, 279
- leetcode做题总结,题目Merge Two Sorted Lists 2012/03/30
- leetcode刷题,总结,记录,备忘137
- Leetcode刷题总结:303. Range Sum Query - Immutable
- leetcode复习总结
- leetcode总结 -- 对于一个给定的matrix,每个元素是0 or 1
- Leetcode挑战题——2 Keys Keyboard
- leetcode刷题,总结,记录,备忘 268
- 650. 2 Keys Keyboard
- leetcode 651. 4 Keys Keyboard
- leetcode刷题,总结,记录,备忘70
- leetcode做题总结,题目Remove Nth Node From End of List 2012/01/27