LeetCode笔记:Weekly Contest 231 比赛记录

  • LeetCode笔记:Weekly Contest 231
    • 0. 赛后总结
    • 1. 题目一
      • 1. 解题思路
      • 2. 代码实现
    • 2. 题目二
      • 1. 解题思路
      • 2. 代码实现
    • 3. 题目三
      • 1. 解题思路
      • 2. 代码实现
    • 4. 题目四
      • 1. 解题思路
      • 2. 代码实现

0. 赛后总结

这次的比赛和昨晚也差不多,不过第三题傻逼了,一个低级错误导致连错了4次,然后就啥都就不回来了,看了一下国内排名大约被拉了100名吧,唉,要不肯定能进前5%的……

1. 题目一

给出题目一的试题链接如下:

  • 5697. 检查二进制字符串字段

1. 解题思路

这次的第一题实在是不想多说什么,难点完全在于理解题意,说白了就是所有的1事实上都要连在一起,然后只要有1个就算连续……

所以代码其实就很好写,问题就是你题目是否能一次性理解了……

2. 代码实现

给出python代码实现如下:

class Solution:
    def checkOnesSegment(self, s: str) -> bool:
        res = 0
        n = len(s)
        cnt = 0
        for c in s:
            if c == '0':
                if cnt > 0:
                    res += 1
                cnt = 0
            else:
                cnt += 1
        if cnt > 0:
            res += 1
        return res <= 1

提交代码评测得到:耗时28ms,占用内存14MB。

2. 题目二

给出题目二的试题链接如下:

  • 5698. 构成特定和需要添加的最少元素

1. 解题思路

这一题其实是我感觉的这次比赛当中最为简单的一道题,只要先算出与目标的差值,然后尽可能快速地填充就行了。

由于能够用于填充的数的绝对值有上限,因此事实上就是不断地用最大值进行填充直至可以覆盖就行了。

2. 代码实现

给出python代码实现如下:

class Solution:
    def minElements(self, nums: List[int], limit: int, goal: int) -> int:
        delta = abs(sum(nums) - goal)
        return (delta-1) // limit + 1

提交代码评测得到:耗时724ms,占用内存26.9MB。

3. 题目三

给出题目三的试题链接如下:

  • 5699. 从第一个节点出发到最后一个节点的受限路径数

1. 解题思路

这一题坦率地说思路上虽然感觉有点复杂,但是挺顺利成章的,只可惜比赛的时候我犯了一个傻逼错误,然后就导致连错了4次,真的是累感不爱,但是有一说一,确实还是挺直接的。

思路上而言,感觉就是:

  1. 找到每个点到终点的最小距离;
  2. 使用动态规划的方法找到所有的受限路径;

其中,对于第一步,我们可以采用逐步遍历的方式进行搜索,而对于第二步,就是一个动态规划的问题……

2. 代码实现

我们给出python代码实现如下:

class Solution:
    def countRestrictedPaths(self, n: int, edges: List[List[int]]) -> int:
        MOD = 10**9 + 7
        edgelist = {
     }
        graph = defaultdict(set)
        for u, v, d in edges:
            graph[u].add(v)
            graph[v].add(u)
            u, v = (u, v) if u < v else (v, u)
            if (u, v) not in edgelist:
                edgelist[(u, v)] = d
            else:
                edgelist[(u, v)] = min(d, edgelist[(u, v)])
            
        distance = [-1 for _ in range(n+1)]
        q = [(0, n)]
        while q:
            dis, u = heapq.heappop(q)
            if distance[u] != -1:
                continue
            distance[u] = dis
            for v in graph[u]:
                if distance[v] == -1:
                    uu, vv = (u, v) if u < v else (v, u)
                    heapq.heappush(q, (dis + edgelist[(uu, vv)], v))
        
        @lru_cache(None)
        def dp(u):
            if u == n:
                return 1
            res = 0
            for v in graph[u]:
                if distance[v] < distance[u]:
                    res += dp(v) % MOD
            return res % MOD
        
        return dp(1)

提交代码评测得到:耗时1744ms,占用内存63MB。

4. 题目四

给出题目四的试题链接如下:

  • 5700. 使所有区间的异或结果为零

1. 解题思路

这一题现在想来其实感觉挺坑的,比赛的时候没能做出来,然后赛后看了一下答案之后发现还是一样的思路,然后重写了一下之后这次就过了……

果然是比赛的时候脑子太乱了的关系吧,或许,大概……

话不多说,这道题核心就是在于想明白最终的答案一定满足条件:

  • i i i个数一定等于第 i + k i+k i+k个数。

因此,事实上我们就是先将所有对k余数相同的的数组成一个集合进行考察,统计其中数据的分布。

对于最终的答案,可以想见的是,他一定满足:

  • 最多只有一个一堆其中所有的数转变为的目标值不是其中频数最大的数(称该余数对应位置的堆为补充值)。

因此,我们只要分别考察每一个余数下的堆作为补充值的情况就可以了。

不过需要注意的是,由于对于某一个确定的余数位置,它的可用候选值可能有多个(比如1和2的频数均为3,那么这个位置下的数即可以选1也可以选2),因此,我们可以使用一个迭代算法来处理这个问题。

借用缓存机制,这就可以转换为一个动态规划的算法。

不过,即便如此,该算法还是会出现超时问题,因此,我们还需要对其来做一下剪枝。

2. 代码实现

给出最终的算法实现如下:

class Solution:
    def minChanges(self, nums: List[int], k: int) -> int:
        cnt = [defaultdict(int) for _ in range(k)]
        for i, x in enumerate(nums):
            cnt[i % k][x] += 1
            
        def get_max(counter):
            _max = max(counter.values())
            return [x for x in counter if counter[x] == _max]
        
        cand = [get_max(c) for c in cnt]
        tot = sum([c[x[0]] for c, x in zip(cnt, cand)])
        n = len(nums)
        res = n-k+1
        
        @lru_cache(None)
        def dp(i, idx, s):
            nonlocal res
            if i == k:
                if idx != -1:
                    res = min(res, n - (tot - cnt[idx][cand[idx][0]] + cnt[idx][s]))
                    # print(f"update res to {res}")
                return
            if idx == -1:
                dp(i+1, i, s)
            else:
                if n - (tot - cnt[idx][cand[idx][0]]) >= res:
                    return
            for c in cand[i]:
                dp(i+1, idx, s^c)
            return
        
        dp(0, -1, 0)
        return res

提交代码评测得到:耗时5792ms,占用内存343.1MB。

你可能感兴趣的:(leetcode笔记,算法,数据结构,python)