第一题: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。(项目和小组都是从零开始编号的)
请你帮忙按要求安排这些项目的进度,并返回排序后的项目列表:
结果要求:
如果存在多个解决方案,只需要返回其中任意一个即可。
如果没有合适的解决方案,就请返回一个 空列表。
输入: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