记录 LeetCode 第 81 场双周赛
本次周赛 依旧只写出前三题,第四题动态规划转移方程想了很久没整出来 (明明很简单!) 。
战局详情
排名 | 用户名 | 得分 | 完成时间 | 题目1(3) | 题目2(5) | 题目3(5) | 题目4(6) |
---|---|---|---|---|---|---|---|
640 / 3847 | Juruoer | 13 | 0:39:05 | 0:02:51 | 0:20:14 | 0:39:05 |
题目及解答
统计星号
给你一个字符串 s
,每 两个 连续竖线 '|'
为 一对 。换言之,第一个和第二个 '|'
为一对,第三个和第四个 '|'
为一对,以此类推。
请你返回 不在 竖线对之间,s
中 '*'
的数目。
注意,每个竖线 '|'
都会 恰好 属于一个对。
提示:
1 <= s.length <= 1000
s
只包含小写英文字母,竖线'|'
和星号'*'
。s
包含 偶数 个竖线'|'
。
示例一:
输入:s = “l|*e*et|c**o|*de|”
输出:2
解释:不在竖线对之间的字符加粗加斜体后,得到字符串:“l|*e*et|c**o|*de|” 。
第一和第二条竖线 ‘|’ 之间的字符不计入答案。
同时,第三条和第四条竖线 ‘|’ 之间的字符也不计入答案。
不在竖线对之间总共有 2 个星号,所以我们返回 2 。
示例二:
输入:s = “iamprogrammer”
输出:0
解释:在这个例子中,s 中没有星号。所以返回 0 。
示例三:
输入:s = “yo|uar|e**|b|e***au|tifu|l”
输出:5
解释:需要考虑的字符加粗加斜体后:“yo|uar|e**|b|e***au|tifu|l” 。不在竖线对之间总共有 5 个星号。所以我们返回 5 。
解决方案:
模拟:
使用一个标记来判断当前字符是否在一对 '|'
之中。可以发现,每遇到一个 '|'
,标记取反。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度: 。 n
为 s
长度。
统计无向图中无法互相到达点对数
给你一个整数 n
,表示一张 无向图 中有 n
个节点,编号为 0
到 n - 1
。同时给你一个二维整数数组 edges
,其中 edges[i] = [ai, bi]
表示节点 ai
和 bi
之间有一条 无向 边。
请你返回 无法互相到达 的不同 点对数目 。
提示:
1 <= n <= 1e5
0 <= edges.length <= 2 * 1e5
edges[i].length == 2
0 <= ai, bi < n
ai != bi
- 不会有重复边。
示例一:
输入:n = 3, edges = [[0,1],[0,2],[1,2]]
输出:0
解释:所有点都能互相到达,意味着没有点对无法互相到达,所以我们返回 0 。
示例二:
输入:n = 7, edges = [[0,2],[0,5],[2,4],[1,6],[5,4]]
输出:14
解释:总共有 14 个点对互相无法到达:
[[0,1],[0,3],[0,6],[1,2],[1,3],[1,4],[1,5],[2,3],[2,6],[3,4],[3,5],[3,6],[4,6],[5,6]]
所以我们返回 14 。
解决方案:
并查集:
利用并查集计算出所有连通图的节点个数,根据数学的排列组合知识即可计算出无法相互到达的点对数。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度: 。n
为节点个数。
操作后的最大异或和
给你一个下标从 0 开始的整数数组 nums
。一次操作中,选择 任意 非负整数 x
和一个下标 i
,更新 nums[i]
为 nums[i] AND (nums[i] XOR x)
。
注意,AND
是逐位与运算,XOR
是逐位异或运算。
请你执行 任意次 更新操作,并返回 nums
中所有元素 最大 逐位异或和。
提示:
1 <= nums.length <= 1e5
0 <= nums[i] <= 1e8
示例一:
输入:nums = [3,2,4,6]
输出:7
解释:选择 x = 4 和 i = 3 进行操作,num[3] = 6 AND (6 XOR 4) = 6 AND 2 = 2 。
现在,nums = [3, 2, 4, 2] 且所有元素逐位异或得到 3 XOR 2 XOR 4 XOR 2 = 7 。
可知 7 是能得到的最大逐位异或和。
注意,其他操作可能也能得到逐位异或和 7 。
示例二:
输入:nums = [1,2,3,9,2]
输出:11
解释:执行 0 次操作。
所有元素的逐位异或和为 1 XOR 2 XOR 3 XOR 9 XOR 2 = 11 。
可知 11 是能得到的最大逐位异或和。
解决方案:
位运算 (脑筋急转弯) :
根据位运算的特点,我们可以发现:
- 对于一个已有的非负整数
num
和 任意一个 期望获得的非负整数target
,我们都可以选择出一个非负整数x
,使得num XOR x = target
。 - 对于一个已有的非负整数
num
,对于num
的二进制中 任意一个 为1
的位idx
,我们都可以选择出一个非负整数x
,进行操作num = num AND x
后,num
的二进制中第idx
位的1
变为0
,而不改变num
的二进制中其他位的值。
所以对于题设给出的操作,相当于选出 nums[i]
中的某个元素 num
,将 num
的二进制中的某个为 1
的位变为 0
。而要使得 nums
中所有元素的异或和最大,只需要将所有元素的二进制排列出来,若某一位,有至少一个元素的二进制在该位为 1
,则需要操作这些元素,使得该位为 1
的元素的个数为奇数,那么所有元素的异或和在该位即是 1
,最终异或和最大。
对于二进制的第 idx
位,若存在某一个元素该位为 1
,那么操作后最大的异或和在该位也为 1
,若所有元素的二进制在该位均为 0
,那么最大异或和在该位为 0
。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度:,c
为二进制的位数,本题数字范围限定 c
为 28
,n
为 nums
的长度。
位运算优化:
更进一步,我们发现遍历所有元素的二进制,并记录出存在 1
的位这件事本身不就是 按位或 运算吗?所以我们只需要将所有元素按位或即可得出答案!
代码:
1 | class Solution { |
时间复杂度: ;空间复杂度: 。
不同骰子序列的数目
给你一个整数 n
。你需要掷一个 6 面的骰子 n
次。请你在满足以下要求的前提下,求出 不同 骰子序列的数目:
- 序列中任意 相邻 数字的 最大公约数 为
1
。 - 序列中 相等 的值之间,至少有
2
个其他值的数字。正式地,如果第i
次掷骰子的值 等于 第j
次的值,那么abs(i - j) > 2
。
请你返回不同序列的 总数目 。由于答案可能很大,请你将答案对 1e9 + 7
取余 后返回。
如果两个序列中至少有一个元素不同,那么它们被视为不同的序列。
提示:
1 <= n <= 1e4
示例一:
输入:n = 4
输出:184
解释:一些可行的序列为 (1, 2, 3, 4) ,(6, 1, 2, 3) ,(1, 2, 3, 1) 等等。
一些不可行的序列为 (1, 2, 1, 3) ,(1, 2, 3, 6) 。
(1, 2, 1, 3) 是不可行的,因为第一个和第三个骰子值相等且 abs(1 - 3) = 2 (下标从 1 开始表示)。
(1, 2, 3, 6) i是不可行的,因为 3 和 6 的最大公约数是 3 。
总共有 184 个不同的可行序列,所以我们返回 184 。
示例二:
输入:n = 2
输出:22
解释:一些可行的序列为 (1, 2) ,(2, 1) ,(3, 2) 。
一些不可行的序列为 (3, 6) ,(2, 4) ,因为最大公约数不为 1 。
总共有 22 个不同的可行序列,所以我们返回 22 。
解决方案:
动态规划:
dp[k][i][j]
表示直到第 k
次投骰子,投到的是 i
,且前一次投骰子投到的是 j
的序列数,且仅当 i
和 j
互质时才有意义
按照题意很容易可以得出:
当
k == 2
时,在k = 1
次投骰子结果确定的情况下,仅有一种可能(感觉在说废话)。dp[2][i][j] = 1
(j
与i
互质)。当
k > 2
时,需要取出第k - 1
次投骰子结果为j
且第k - 2
次投骰子结果与i
不同是所有结果,dp[k][i][j] = Σ(dp[k - 1][j][r])
,r
从1
到6
,i
与j
互质,j
与r
互质,i != r
。
代码:
1 | class Solution |
时间复杂度: ; 空间复杂度:。其中 c
表示骰子点数范围,本题为 6
。