leetcode第155场周赛总结

leetcode第155场周赛总结

第一题:5197. 最小绝对差

给你个整数数组 arr,其中每个元素都 不相同。
请你找到所有具有最小绝对差的元素对,并且按升序的顺序返回。

示例1:

输入:arr = [4,2,1,3]
输出:[[1,2],[2,3],[3,4]]

示例2:

输入:arr = [1,3,6,10,15]
输出:[[1,3]]

示例3:

输入:arr = [3,8,-10,23,19,-4,-14,27]
输出:[[-14,-10],[19,23],[23,27]]

提示:

2 <= arr.length <= 10^5
-10^6 <= arr[i] <= 10^6

分析:
因为要求按升序的顺序返回答案,所以可先对原数组进行排序,接着先遍历一遍找出最小绝对差是多少,然后再遍历一遍把所有等于最小绝对差的元素对添加进答案中。由于我们是在排完序的基础上做的,所以遍历时只需考虑相邻元素对即可,若不相邻的两元素对,其绝对差必不为最小。
代码如下:

class Solution:
    def minimumAbsDifference(self, arr: List[int]) -> List[List[int]]:
        arr.sort()
        ans = []
        mins = float('inf')
        for i in range(len(arr)-1):
            mins = min(mins, arr[i+1] - arr[i])
        for i in range(len(arr)-1):
            if arr[i+1] - arr[i] == mins:
                ans.append([arr[i], arr[i+1]])
        return ans
第二题:5198. 丑数 III

请你帮忙设计一个程序,用来找出第 n 个丑数。
丑数是可以被 a 或 b 或 c 整除的 正整数。

示例1:

输入:n = 3, a = 2, b = 3, c = 5
输出:4
解释:丑数序列为 2, 3, 4, 5, 6, 8, 9, 10… 其中第 3 个是 4。

示例2:

输入:n = 4, a = 2, b = 3, c = 4
输出:6
解释:丑数序列为 2, 3, 4, 6, 8, 9, 12… 其中第 4 个是 6。

示例3:

输入:n = 5, a = 2, b = 11, c = 13
输出:10
解释:丑数序列为 2, 4, 6, 8, 10, 11, 12, 13… 其中第 5 个是 10。

示例4:

输入:n = 1000000000, a = 2, b = 217983653, c = 336916467
输出:1999999984

提示:

1 <= n, a, b, c <= 10^9
1 <= a * b * c <= 10^18
本题结果在 [1, 2 * 10^9] 的范围内

分析:
看提示中n的范围是1~10^9,所以n的取值可以很大,用O(n)复杂度也未必能满足时间复杂度的要求,事实上我试了一下,确实不行,超时了。所以看样子是要用O(logn)的时间复杂度才行,这就让我想到了二分法了。事实上,给定一个数我们是可以计算它是第几个丑数的,只需计算这个数能整除多少个a,b,c,并且根据容斥原理减去重复计算的和加上未计算的即可。具体分析可参考这位大神博主:具体分析
所以我们可以用二分法在可取值的范围内搜索这个数。
代码如下:

class Solution:
    def nthUglyNumber(self, n: int, a: int, b: int, c: int) -> int:
        l, r = 1, 2*10**9
        x, y, z = a * b // math.gcd(a, b), b * c // math.gcd(b, c), a * c // math.gcd(a, c)
        w = x * y // math.gcd(x, y)
        ans = 0
        while l <= r:
            mid = (l + r) // 2
            cnt = mid // a + mid // b + mid // c - mid // x - mid // y - mid // z + mid // w
            if cnt >= n:
                r = mid - 1
                if cnt == n:
                    ans = mid
            else:
                l = mid + 1
        return ans
第三题:5199. 交换字符串中的元素

给你一个字符串 s,以及该字符串中的一些「索引对」数组 pairs,其中 pairs[i] = [a, b] 表示字符串中的两个索引(编号从 0 开始)。
你可以 任意多次交换 在 pairs 中任意一对索引处的字符。
返回在经过若干次交换后,s 可以变成的按字典序最小的字符串。

示例1:

输入:s = “dcab”, pairs = [[0,3],[1,2]]
输出:“bacd”
解释:
交换 s[0] 和 s[3], s = “bcad”
交换 s[1] 和 s[2], s = “bacd”

示例2:

输入:s = “dcab”, pairs = [[0,3],[1,2],[0,2]]
输出:“abcd”
解释:
交换 s[0] 和 s[3], s = “bcad”
交换 s[0] 和 s[2], s = “acbd”
交换 s[1] 和 s[2], s = “abcd”

示例3:

输入:s = “cba”, pairs = [[0,1],[1,2]]
输出:“abc”
解释:
交换 s[0] 和 s[1], s = “bca”
交换 s[1] 和 s[2], s = “bac”
交换 s[0] 和 s[1], s = “abc”

提示:

1 <= s.length <= 10^5
0 <= pairs.length <= 10^5
0 <= pairs[i][0], pairs[i][1] < s.length
s 中只含有小写英文字母

分析:
并查集的题,主要还是要分析好题意啊,这个太重要了!参考:大神解析
代码如下:

import numpy as np
class Solution:
    def smallestStringWithSwaps(self, s: str, pairs: List[List[int]]) -> str:
        def find(a):
            if a == pre[a]:
                return a
            f = find(pre[a])
            pre[a] = f
            return f
        def union(a, b):
            a = find(a)
            b = find(b)
            pre[a] = b
        
        n = len(s)
        pre = [i for i in range(n)]
        for a, b in pairs:
            union(a, b)
        for i in range(n):
            find(i)
        unique_pre = list(set(pre))
        pre_str = {x:'' for x in unique_pre}
        for i in range(n):
            pre_str[pre[i]] += s[i]
        for x in unique_pre:
            pre_str[x] = sorted(pre_str[x])
        pre_cnt = {x:0 for x in unique_pre}
        ans = ''
        for i in range(n):
            c = pre[i]
            ans += pre_str[c][pre_cnt[c]]
            pre_cnt[c] += 1
        return ans
第四题:5200. 项目管理

公司共有 n 个项目和 m 个小组,每个项目要不没有归属,要不就由其中的一个小组负责。
我们用 group[i] 代表第 i 个项目所属的小组,如果这个项目目前无人接手,那么 group[i] 就等于 -1。(项目和小组都是从零开始编号的)
请你帮忙按要求安排这些项目的进度,并返回排序后的项目列表:

  1. 同一小组的项目,排序后在列表中彼此相邻。
  2. 项目之间存在一定的依赖关系,我们用一个列表 beforeItems 来表示,其中beforeItems[i] 表示在进行第 i 个项目前(位于第 i 个项目左侧)应该完成的所有项目。

结果要求:
如果存在多个解决方案,只需要返回其中任意一个即可。
如果没有合适的解决方案,就请返回一个 空列表。

示例1:
在这里插入图片描述

输入:n = 8, m = 2, group = [-1,-1,1,0,0,1,0,-1], beforeItems = [[],[6],[5],[6],[3,6],[],[],[]]
输出:[6,3,4,1,5,2,0,7]

示例2:

输入:n = 8, m = 2, group = [-1,-1,1,0,0,1,0,-1], beforeItems = [[],[6],[5],[6],[3],[],[4],[]]
输出:[]
解释:与示例 1 大致相同,但是在排序后的列表中,4 必须放在 6 的前面。

提示:

1 <= m <= n <= 3*10^4
group.length == beforeItems.length == n
-1 <= group[i] <= m-1
0 <= beforeItems[i].length <= n-1
0 <= beforeItems[i][j] <= n-1
i != beforeItems[i][j]

分析:
这是一道拓扑排序的问题,但是稍微复杂了一点,因为得分为组内和组间来分别进行拓扑排序。
代码如下:

import queue
import numpy as np
class Solution:
    def sortItems(self, n: int, m: int, group: List[int], beforeItems: List[List[int]]) -> List[int]:
        # 组内拓扑排序
        def get_group_ans(points, edges):
            # 组内建图
            graph = {point:[] for point in points}
            degree = {point:0 for point in points}
            for x, y in edges:
                graph[y].append(x)
                degree[x] += 1
            q = queue.Queue()
            for point in points:
                if degree[point] == 0:
                    q.put(point)
            res = []
            while not q.empty():
                x = q.get()
                res.append(x)
                for y in graph[x]:
                    degree[y] -= 1
                    if degree[y] == 0:
                        q.put(y)
            if len(res) != len(points):
                return None
            return res
        
        
        # 组级别建图
        for i in range(n):
            if group[i] == -1:
                group[i] = m
                m += 1
        group_ids = [i for i in range(m)]
        graph = {group_id:[] for group_id in group_ids}
        degree = {group_id:0 for group_id in group_ids}
        group_points = {group_id:[] for group_id in group_ids}
        group_inner_edges = {group_id:[] for group_id in group_ids}
        for i in range(n):
            groupa = group[i]
            group_points[groupa].append(i)
            for j in beforeItems[i]:
                groupb = group[j]
                if groupa == groupb:
                    group_inner_edges[groupa].append([i, j])
                    continue
                graph[groupb].append(groupa)
                degree[groupa] += 1
        # 组级别拓扑排序
        q = queue.Queue()
        for group_id in group_ids:
            if degree[group_id] == 0:
                q.put(group_id)
        group_res = []
        while not q.empty():
            x = q.get()
            group_res.append(x)
            for y in graph[x]:
                degree[y] -= 1
                if degree[y] == 0:
                    q.put(y)
        if len(group_res) != len(group_ids):
            return []
        ans = []
        for group_id in group_res:
            temp = get_group_ans(group_points[group_id], group_inner_edges[group_id])
            if temp is None:
                return []
            ans += temp
        return ans
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值