LeetCode Mock Review 2021-4-12
今天的Mock也很简单,是两道easy题且都是数学题。
292. Nim Game
292. Nim Game
一看到这道题我就想这不是dp问题吗。
d
p
[
i
]
=
{
t
u
r
e
i
⩽
3
!
d
p
[
i
−
1
]
∣
∣
!
d
p
[
i
−
2
]
∣
∣
!
d
p
[
i
−
3
]
o
t
h
e
r
w
i
s
e
dp[i]= \begin{cases} ture& i \leqslant 3\\ !dp[i-1] || !dp[i-2] ||!dp[i-3] &otherwise \end{cases}
dp[i]={ture!dp[i−1]∣∣!dp[i−2]∣∣!dp[i−3]i⩽3otherwise
当有n颗石子时,有三种选择:拿一个,拿两个,拿三个。拿完后会剩余n-1,n-2,n-3颗石子,这时候轮到对手拿。当对手在这三种情况全部必胜的时候,说明在n颗石子时,拿取的人必输。否则拿取的人必胜。
于是我写出了第一个dp版本,用空间换时间:
class Solution {
public boolean canWinNim(int n) {
if(n <= 3) return true;
boolean[] dp = new boolean[n+1];
dp[0] = dp[1] = dp[2] = dp[3] = true;
for(int i = 4; i <= n; i++){
dp[i] = !dp[i-1] || !dp[i-2] || !dp[i-3];
}
return dp[n];
}
}
然而Memory Limit Exceed了。
这时我注意剩n颗石子的情况只与n-1,n-2和n-3的情况有关(类似斐波那契数列的思维)。于是我写出了第二个dp版本:
class Solution{
public boolean canWinNim(int n){
if(n<=3) return true;
boolean p1 = true, p2 = true, p3 = true, p = false;
for(int i = 4; i <= n; i++){
p = !p1 || !p2 || !p3;
p1 = p2;
p2 = p3;
p3 = p;
}
return p;
}
}
这下我以为稳了,结果把之前超时的用例又跑了一次发现Time Limit Exceed。
这下我有点意识到不对了,既然这样超时,那么求解过程必然可以被优化,使得时间复杂度小于O(n)。然后我在纸上写了一下n
⩽
\leqslant
⩽ 8的情况。
i | 拿取几个最优 | 结果 |
---|---|---|
1 | 1 | T |
2 | 2 | T |
3 | 3 | T |
4 | F | |
5 | 1 | T |
6 | 2 | T |
7 | 3 | T |
8 | F |
写到8时我发现了其中的规律,于是最终版本出现,时间复杂度为O(1)。
class Solution {
public boolean canWinNim(int n) {
return n%4!=0;
}
}
461. Hamming Distance
461. Hamming Distance
看到题名我就想起了上计算机网络课时候学到的Hamming校验码哈哈。这道题是判断两个数的二进制表示中有多少位不一样。直接统计两数异或的结果然后求其中1的个数。
class Solution {
public int hammingDistance(int x, int y) {
int num = x ^ y;
int count = 0;
while(num != 0){
if(num % 2 == 1) count++;
num /= 2;
}
return count;
}
}
其中可以通过优化求1的个数的过程实现更高的效率,如先与1然后右移等。
总结:第一道题在超时后心态有点崩,先去做了第二道题。然后在思考优化过程的时候在纸上写了一下就找到了规律。有时候不能光想,边写边尝试可能更加高效。