0. 赛后总结
这一次的比赛算是中规中矩吧,花了四十来分钟,完成了3题,最后一题没能搞定。成绩上来说倒是不算差,国内181名,世界538名。大概因为做出最后一题的人确实不多吧。
总之,回头好好研究一下最后一题吧,总感觉思路还是有的,就差临门一脚的实现。
1. 题目一
给出题目一的试题链接如下:
1. 解题思路
这一题的本质就是遍历1~n,看是否有一个值i刚好满足有i个数大于它。因此,我们只首先需要对整个数组进行一次排序,而后依次搜索即可。
2. 代码实现
给出python代码实现如下:
class Solution:
def specialArray(self, nums: List[int]) -> int:
nums = sorted(nums)
n = len(nums)
if n <= nums[0]:
return n
for i in range(n-1):
_min = nums[i]
_max = nums[i+1]
if n-i-1 > _min and n-i-1 <= _max:
return n-i-1
return -1
提交代码后评测得到:耗时24ms,占用内存14.2MB。属于当前最优方案。
2. 题目二
给出题目二的试题链接如下:
1. 解题思路
这一题本质上来说就是一个二叉树的逐层遍历,唯一需要多做一步的就是对每一层按照奇偶性进行一次大小检查。因此就不需要多做展开了,应该都知道。
2. 代码实现
给出python代码实现如下:
class Solution:
def isEvenOddTree(self, root: TreeNode) -> bool:
queue = [root]
level = 0
while queue != []:
new_queue = []
node = queue.pop(0)
if node.val % 2 == level % 2:
return False
if node.left:
new_queue.append(node.left)
if node.right:
new_queue.append(node.right)
last_val = node.val
while queue != []:
node = queue.pop(0)
if node.val % 2 == level % 2:
return False
if level % 2 == 0 and node.val <= last_val:
return False
elif level % 2 == 1 and node.val >= last_val:
return False
if node.left:
new_queue.append(node.left)
if node.right:
new_queue.append(node.right)
last_val = node.val
queue = new_queue
level += 1
return True
提交代码评测得到:耗时504ms,占用内存41.1MB。
当前最优代码实现耗时336ms,但是看了一下思路上是大差不差的,因此也就不再多做展开了,有兴趣的读者可以自己去看一下。
3. 题目三
给出题目三的试题链接如下:
1. 解题思路
这一题的我的思路就是把每一个点的角度算出来,然后看一下以每个点为起点的逆时针 θ \theta θ角度里面有多少的点存在于其中。
需要注意的点有以下几点:
- 由于是一个圆,所以当小角度的 α α α可能会出现在接近360的视角起点的范围内,需要注意考察以下,不能遗漏也不要重复计算;
- 当点和观察者位置重合时,无论何种角度都能直接看到,因此需要特殊处理一下,不能够当成某个特定的角度来看待;
- 由于计算机是离散计算,需要注意精度问题,避免由于精度导致的角度计算不一致(事实上比赛的时候我就在这里挂了一次)。
2. 代码实现
给出python代码实现如下:
import math
class Solution:
def visiblePoints(self, points: List[List[int]], angle: int, location: List[int]) -> int:
delta = 1e-7
def cal_angle(x, y):
x0, y0 = location
xd, yd = x - x0, y-y0
if yd == 0:
return 0 if xd >= 0 else 180
elif xd == 0:
return 90 if yd >= 0 else 270
theta = 180 * math.acos(xd / math.sqrt(xd**2 + yd **2)) / math.pi
return theta if yd > 0 else 360 - theta
angle_list = []
always_seen = 0
for x, y in points:
if location[0] == x and location[1] == y:
always_seen += 1
else:
angle_list.append(cal_angle(x, y))
angle_list = sorted(angle_list)
n = len(points)
angle_list += [x+360 for x in angle_list if x + 360 <= angle_list[-1] + angle]
m = len(angle_list)
j = 0
ans = 0
for i in range(n):
while j < m and angle_list[j]-angle_list[i] <= angle + delta:
j += 1
ans = max(ans, min(j - i, n))
return ans + always_seen
提交代码之后评测得到:耗时1948ms,占用内存59.9MB。
当前最优的方案耗时仅708ms,但是看了一下它的代码,和我们的思路是几乎完全一致的,然后重新提交了一下他们的代码,发现评测耗时1704ms,和我们的实现并没有太过显著的差异,因此这里就不再展开了。
4. 题目四
给出题目四的试题链接如下:
1. 解题思路
这一题比赛的时候没能搞定,赛后想了好一阵子,后来做到是做出来了,但是其实也是手写了一堆结果之后整理得到的结论。
思路上大致来说肯定是递归没跑了,问题是递归公式怎么构建,我们整理得到:
- 从0到构建第i位为1,其他位全部为0的数需要的总步数为 2 i − 1 2^{i}-1 2i−1次,其间恰好会遍历一遍从1到 2 i 2^{i} 2i之间的所有数;
- 对任意一个数字k,从0构建k和从k变回0的过程是可逆的,即两者需要的步数完全相同。
因此,我们可以给出递归公式如下,对任意一个二进制数 x 1 x 2 . . . x n x_1x_2...x_n x1x2...xn,
- 如果 x 1 x_1 x1为0,那么需要的步数就是构建 x 2 . . . x n x_2...x_n x2...xn需要的步数;
- 如果 x 1 x_1 x1为1,那么需要的步数就是构建 10...0 10...0 10...0的步数(即 2 n − 1 2^n-1 2n−1)减去构建 x 2 . . . x n x_2...x_n x2...xn需要的步数。
2. 代码实现
我们给出python代码实现如下:
class Solution:
def minimumOneBitOperations(self, n: int) -> int:
digits = []
while n != 0:
digits.append(n & 1)
n = n >> 1
n = len(digits)
flag = 2
ones = []
for i in range(n):
ones.append(flag-1)
flag *= 2
def dp(idx):
if idx < 0:
return 0
if idx == 0:
return digits[idx]
if digits[idx] == 0:
return dp(idx-1)
else:
return ones[idx] - dp(idx-1)
return dp(n-1)
提交代码评测得到:耗时28ms,占用内存14.1MB。为当前最优实现方案。