LeetCode笔记:Weekly Contest 209 比赛记录

本文记录了作者参加LeetCode Weekly Contest 209的赛后总结,包括四道题目的解题思路和Python代码实现。题目涉及数组特性值、奇偶树判断、可见点计算及最少操作次数问题。作者分别给出了详细解析,并分享了代码运行时间和内存占用情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 θ角度里面有多少的点存在于其中。

需要注意的点有以下几点:

  1. 由于是一个圆,所以当小角度的 α α α可能会出现在接近360的视角起点的范围内,需要注意考察以下,不能遗漏也不要重复计算;
  2. 当点和观察者位置重合时,无论何种角度都能直接看到,因此需要特殊处理一下,不能够当成某个特定的角度来看待;
  3. 由于计算机是离散计算,需要注意精度问题,避免由于精度导致的角度计算不一致(事实上比赛的时候我就在这里挂了一次)。

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. 解题思路

这一题比赛的时候没能搞定,赛后想了好一阵子,后来做到是做出来了,但是其实也是手写了一堆结果之后整理得到的结论。

思路上大致来说肯定是递归没跑了,问题是递归公式怎么构建,我们整理得到:

  1. 从0到构建第i位为1,其他位全部为0的数需要的总步数为 2 i − 1 2^{i}-1 2i1次,其间恰好会遍历一遍从1到 2 i 2^{i} 2i之间的所有数;
  2. 对任意一个数字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 2n1)减去构建 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。为当前最优实现方案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值