LeetCode-371

Q1&Q4

100124. 找出强数对的最大异或值 II

给你一个下标从 0 开始的整数数组 nums 。如果一对整数 xy 满足以下条件,则称其为 强数对

  • |x - y| <= min(x, y)

你需要从 nums 中选出两个整数,且满足:这两个整数可以形成一个强数对,并且它们的按位异或(XOR)值是在该数组所有强数对中的 最大值

返回数组 nums 所有可能的强数对中的 最大 异或值。

注意,你可以选择同一个整数两次来形成一个强数对。

示例 1:

1
2
3
4
输入:nums = [1,2,3,4,5]
输出:7
解释:数组 nums 中有 11 个强数对:(1, 1), (1, 2), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (3, 5), (4, 4), (4, 5) 和 (5, 5) 。
这些强数对中的最大异或值是 3 XOR 4 = 7

示例 2:

1
2
3
4
输入:nums = [10,100]
输出:0
解释:数组 nums 中有 2 个强数对:(10, 10) 和 (100, 100) 。
这些强数对中的最大异或值是 10 XOR 10 = 0 ,数对 (100, 100) 的异或值也是 100 XOR 100 = 0

示例 3:

1
2
3
4
输入:nums = [500,520,2500,3000]
输出:1020
解释:数组 nums 中有 6 个强数对:(500, 500), (500, 520), (520, 520), (2500, 2500), (2500, 3000) (3000, 3000)
这些强数对中的最大异或值是 500 XOR 520 = 1020 ;另一个异或值非零的数对是 (5, 6) ,其异或值是 2500 XOR 3000 = 636

提示:

  • 1 <= nums.length <= 5 * 104
  • 1 <= nums[i] <= 220 - 1

根据条件|x - y| <= min(x, y),很容易想到双指针(滑动窗口)维护满足条件区间,那么就只剩下一个区间内求异或值最大的问题了,很明显可以使用01trie来实现,相较于平常的01trie,这个需要实现remove,其实也比较简单,参考正常的字典树,维护一个cnt即可。时间复杂度O(nlogn+nlogU)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Solution:
__slots__ = ['root']

class Node:

__slots__ = ['nodes', 'cnt']

def __init__(self):
self.nodes = [None, None]
self.cnt = 0

def __init__(self):
self.root = self.Node()

def add(self, x: int) -> None:
temp = self.root
for i in range(21, -1, -1):
v = ((x >> i) & 1) ^ 1
if temp.nodes[v] is None:
temp.nodes[v] = self.Node()
temp = temp.nodes[v]
temp.cnt += 1

def remove(self, x):
temp = self.root
for i in range(21, -1, -1):
v = ((x >> i) & 1) ^ 1
temp.nodes[v].cnt -= 1
if temp.nodes[v].cnt == 0:
temp.nodes[v] = None
return
temp = temp.nodes[v]

def get(self, x):
ans = 0
temp = self.root
for i in range(21, -1, -1):
v = (x >> i) & 1
if temp.nodes[v] is not None:
ans |= (1 << i)
temp = temp.nodes[v]
else:
temp = temp.nodes[v ^ 1]
return ans

def maximumStrongPairXor(self, nums):
ans = 0
nums.sort()
n = len(nums)
l = 0
for r in range(n):
self.add(nums[r])
while nums[r] - nums[l] > nums[l]:
self.remove(nums[l])
l += 1
ans = max(ans, self.get(nums[r]))
return ans

Q2

100128. 高访问员工

给你一个长度为 n 、下标从 0 开始的二维字符串数组 access_times 。对于每个 i0 <= i <= n - 1 ),access_times[i][0] 表示某位员工的姓名,access_times[i][1] 表示该员工的访问时间。access_times 中的所有条目都发生在同一天内。

访问时间用 四位 数字表示, 符合 24 小时制 ,例如 "0800""2250"

如果员工在 同一小时内 访问系统 三次或更多 ,则称其为 高访问 员工。

时间间隔正好相差一小时的时间 被视为同一小时内。例如,"0815""0915" 不属于同一小时内。

一天开始和结束时的访问时间不被计算为同一小时内。例如,"0005""2350" 不属于同一小时内。

以列表形式,按任意顺序,返回所有 高访问 员工的姓名。

示例 1:

1
2
3
4
5
输入:access_times = [["a","0549"],["b","0457"],["a","0532"],["a","0621"],["b","0540"]]
输出:["a"]
解释:"a" 在时间段 [05:32, 06:31] 内有三条访问记录,时间分别为 05:3205:4906:21
但是 "b" 的访问记录只有两条。
因此,答案是 ["a"] 。

示例 2:

1
2
3
4
5
输入:access_times = [["d","0002"],["c","0808"],["c","0829"],["e","0215"],["d","1508"],["d","1444"],["d","1410"],["c","0809"]]
输出:["c","d"]
解释:"c" 在时间段 [08:08, 09:07] 内有三条访问记录,时间分别为 08:0808:0908:29
"d" 在时间段 [14:10, 15:09] 内有三条访问记录,时间分别为 14:1014:4415:08
然而,"e" 只有一条访问记录,因此不能包含在答案中,最终答案是 ["c","d"] 。

示例 3:

1
2
3
4
5
输入:access_times = [["cd","1025"],["ab","1025"],["cd","1046"],["cd","1055"],["ab","1124"],["ab","1120"]]
输出:["ab","cd"]
解释:"ab"在时间段 [10:25, 11:24] 内有三条访问记录,时间分别为 10:2511:2011:24
"cd" 在时间段 [10:25, 11:24] 内有三条访问记录,时间分别为 10:2510:4610:55
因此,答案是 ["ab","cd"] 。

提示:

  • 1 <= access_times.length <= 100
  • access_times[i].length == 2
  • 1 <= access_times[i][0].length <= 10
  • access_times[i][0] 仅由小写英文字母组成。
  • access_times[i][1].length == 4
  • access_times[i][1] 采用24小时制表示时间。
  • access_times[i][1] 仅由数字 '0''9' 组成。

根据每个人分组,排序时间,滑动窗口即可,如果有一个小时内超过三次的,就添加到ans当中。时间复杂度O(Lnlogn)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution:
def findHighAccessEmployees(self, access_times: List[List[str]]) -> List[str]:
mp = {}
ans = []
for x, y in access_times:
if x not in mp:
mp[x] = []
mp[x].append(y)

def check(s1: str, s2: str) -> bool:
h1 = int(s1[:2])
m1 = int(s1[2:])
h2 = int(s2[:2])
m2 = int(s2[2:])
diff = m1 - m2 + (h1 - h2) * 60
return diff < 60

for x, v in mp.items():
v.sort()
n = len(v)
if n < 3: continue
for i in range(2, n):
s1, s2 = v[i], v[i - 2]
if check(s1, s2):
ans.append(x)
break

return ans

Q3

100117. 最大化数组末位元素的最少操作次数

给你两个下标从 0 开始的整数数组 nums1nums2 ,这两个数组的长度都是 n

你可以执行一系列 操作(可能不执行)

在每次操作中,你可以选择一个在范围 [0, n - 1] 内的下标 i ,并交换 nums1[i]nums2[i] 的值。

你的任务是找到满足以下条件所需的 最小 操作次数:

  • nums1[n - 1] 等于 nums1 中所有元素的 最大值 ,即 nums1[n - 1] = max(nums1[0], nums1[1], ..., nums1[n - 1])
  • nums2[n - 1] 等于 nums2 中所有元素的 最大值 ,即 nums2[n - 1] = max(nums2[0], nums2[1], ..., nums2[n - 1])

以整数形式,表示并返回满足上述 全部 条件所需的 最小 操作次数,如果无法同时满足两个条件,则返回 -1

示例 1:

1
2
3
4
5
6
7
输入:nums1 = [1,2,7],nums2 = [4,5,3]
输出:1
解释:在这个示例中,可以选择下标 i = 2 执行一次操作。
交换 nums1[2] 和 nums2[2] 的值,nums1 变为 [1,2,3] ,nums2 变为 [4,5,7]
同时满足两个条件。
可以证明,需要执行的最小操作次数为 1
因此,答案是 1

示例 2:

1
2
3
4
5
6
7
8
9
10
输入:nums1 = [2,3,4,5,9],nums2 = [8,8,4,4,4]
输出:2
解释:在这个示例中,可以执行以下操作:
首先,选择下标 i = 4 执行操作。
交换 nums1[4] 和 nums2[4] 的值,nums1 变为 [2,3,4,5,4] ,nums2 变为 [8,8,4,4,9]
然后,选择下标 i = 3 执行操作。
交换 nums1[3] 和 nums2[3] 的值,nums1 变为 [2,3,4,4,4] ,nums2 变为 [8,8,4,5,9]
同时满足两个条件。
可以证明,需要执行的最小操作次数为 2
因此,答案是 2

示例 3:

1
2
3
4
输入:nums1 = [1,5,4],nums2 = [2,5,3]
输出:-1
解释:在这个示例中,无法同时满足两个条件。
因此,答案是 -1

提示:

  • 1 <= n == nums1.length == nums2.length <= 1000
  • 1 <= nums1[i] <= 109
  • 1 <= nums2[i] <= 109

显然,如果两个数组中的最大值不位于nums1[n - 1]nums2[n - 1],一定不符合要求,那么结果就只有两种可能了,第一种是不交换最后一对,计算需要交换多少次,另一个就是交换最后一对需要计算多少次,取最小值即可,如果中间有不符合的情况直接返回-1即可。时间复杂度O(n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
lass Solution:
def minOperations(self, nums1: List[int], nums2: List[int]) -> int:
n1 = copy.deepcopy(nums1)
n2 = copy.deepcopy(nums2)
mx1, mx2 = max(nums1), max(nums2)
mx = max(mx1, mx2)
if mx != nums1[-1] and mx != nums2[-1]:
return -1

# 不交换最后一个
ans = 0
n = len(nums2)
for i in range(n - 2, -1, -1):
if nums1[i] <= nums1[-1] and nums2[i] <= nums2[-1]:
continue
else:
nums2[i], nums1[i] = nums1[i], nums2[i]
ans += 1
if nums1[i] > nums1[-1] or nums2[i] > nums2[-1]:
return -1

# 交换最后一个
nums1 = copy.deepcopy(n1)
nums2 = copy.deepcopy(n2)
ans1 = 1
nums1[-1], nums2[-1] = nums2[-1], nums1[-1]
for i in range(n - 2, -1, -1):
if nums1[i] <= nums1[-1] and nums2[i] <= nums2[-1]:
continue
else:
nums2[i], nums1[i] = nums1[i], nums2[i]
ans1 += 1
if nums1[i] > nums1[-1] or nums2[i] > nums2[-1]:
return -1
return min(ans, ans1)

LeetCode-371
http://example.com/2023/11/12/LeetCode-371/
作者
ykexc
发布于
2023年11月12日
许可协议