6319. 奇偶位数
题目描述
给定一个整数 n
,返回一个长度为 2
的数组 ans
,其中 ans[0]
表示 n
的二进制表示中奇数位上 1
的个数,ans[1]
表示 n
的二进制表示中偶数位上 1
的个数。
注意:数组下标从 0
开始计数,即最低位为第 0
位。
思路分析
按照题意模拟即可。我们可以用位运算来判断每一位是否为 1
,并且根据位的奇偶性来更新答案数组。具体地,我们可以从低到高遍历 n
的每一位,用 (n >> i) & 1
来得到第 i
位的值,如果为 1
,则根据 i & 1
来判断是奇数位还是偶数位,并且对应地增加 ans[0]
或 ans[1]
的值。由于题目保证 n < 2^11
,所以我们只需要遍历 11
位即可。
代码实现
class Solution:
def evenOddBit(self, n: int) -> List[int]:
ans = [0, 0] # 初始化答案数组
for i in range(11): # 遍历每一位
if (n >> i) & 1: # 如果第 i 位为 1
if i & 1: # 如果 i 是奇数
ans[0] += 1 # 增加奇数位上 1 的个数
else: # 如果 i 是偶数
ans[1] += 1 # 增加偶数位上 1 的个数
return ans # 返回答案数组
6322. 检查骑士巡视方案
题目描述
给定一个大小为 n x n
的棋盘和一个二维数组 grid
,其中每个元素表示该位置的步数。如果骑士从 (0, 0)
出发,并且按照步数从小到大的顺序走完所有位置,返回 true
,否则返回 false
。骑士只能按照国际象棋中的规则移动,即每次只能走 “日” 字形。
注意:输入保证步数不重复。
思路分析
输入保证步数不重复,因此直接按步数排序,判断相邻的步数是可以走到的即可。注意要求骑士从 (0, 0)
开始,注意判断。
具体地,我们可以用一个列表 a
来存储所有位置的步数和坐标,然后对 a
按照步数进行排序。然后我们遍历 a
的每一对相邻元素,判断它们是否满足骑士的移动规则,即横坐标之差的绝对值和纵坐标之差的绝对值是否分别为 1
和 2
或者 2
和 1
。如果有任何一对不满足,就返回 false
。最后,还要检查 a
的第一个元素是否是 (0, 0, 0)
,即起点位置的步数是否为 0
。如果是,就返回 true
,否则返回 false
。
代码实现
class Solution:
def checkValidGrid(self, grid: List[List[int]]) -> bool:
n = len(grid) # 获取棋盘大小
a = [] # 初始化存储步数和坐标的列表
for i, row in enumerate(grid): # 遍历每一行
for j, v in enumerate(row): # 遍历每一列
a.append((v, i, j)) # 将步数和坐标加入列表
a.sort() # 按照步数排序
def ok(x, y, j, k): # 定义一个函数判断两个位置是否满足骑士的移动规则
if abs(x - j) == 1 and abs(y - k) == 2: # 如果横坐标之差为 1 ,纵坐标之差为 2
return True # 返回 True
if abs(x - j) == 2 and abs(y - k) == 1: # 如果横坐标之差为 2 ,纵坐标之差为 1
return True # 返回 True
return False # 否则返回 False
for i in range(1, n * n): # 遍历每一对相邻元素
(_, x, y), (_, j, k) = a[i - 1], a[i] # 获取它们的步数和坐标
if not ok(x, y, j, k): # 如果不满足骑士的移动规则
return False # 返回 False
return a[0] == (0, 0, 0) # 返回起点位置的步数是否为 0
6352. 美丽子集的数目
题目描述
给定一个长度为 n
的正整数数组 nums
和一个正整数 k
,定义一个子集 s
是美丽的,当且仅当 s
中的任意两个元素都满足它们的差不等于 k
。返回数组 nums
中所有美丽子集的数目。由于答案可能很大,返回它对 10^9 + 7
取模后的结果。
注意:子集可以为空,但不能包含重复元素。
思路分析
这是一道深度优先搜索(DFS)的题目。我们可以从小到大遍历数组中的每个元素,对于每个元素,我们有两种选择:加入当前子集或者不加入。如果加入当前子集,我们需要判断是否会导致子集不美丽,即是否存在与当前元素差为 k
的元素已经在子集中。如果不会,我们就可以继续搜索下一个元素;如果会,我们就需要剪枝,即放弃这个选择。如果不加入当前子集,我们也可以继续搜索下一个元素。当我们遍历完所有元素后,我们就得到了一个美丽子集,可以将答案加一。
为了方便判断是否存在与当前元素差为 k
的元素已经在子集中,我们可以用一个哈希表来记录子集中的每个元素出现的次数。每当我们加入一个元素时,就将其在哈希表中的值加一;每当我们移除一个元素时,就将其在哈希表中的值减一。这样,我们只需要查询哈希表中是否存在 nums[i] - k
或者 nums[i] + k
的键即可。
另外,为了避免重复计算相同的子集,我们可以先对数组进行排序,然后保证每次搜索时只考虑当前元素及其之后的元素。
代码实现
class Solution:
def beautifulSubsets(self, nums: List[int], k: int) -> int:
nums.sort() # 对数组进行排序
n = len(nums) # 获取数组长度
ans = 0 # 初始化答案
s = Counter() # 初始化哈希表
def dfs(i): # 定义一个深度优先搜索的函数
nonlocal ans # 声明答案为非局部变量
if i == n: # 如果遍历完所有元素
ans += 1 # 将答案加一
return # 返回
v = nums[i] # 获取当前元素
if s[v - k] == 0 and s[v + k] == 0: # 如果不存在与当前元素差为 k 的元素已经在子集中
s[v] += 1 # 将当前元素加入哈希表
dfs(i + 1) # 搜索下一个元素
s[v] -= 1 # 将当前元素移除哈希表
dfs(i + 1) # 不加入当前元素,搜索下一个元素
dfs(0) # 从第一个元素开始搜索
return (ans - 1) % (10**9 + 7) # 返回答案对 10^9 + 7 取模后的结果,减一是因为空集不算美丽子集
6321. 执行操作后的最大 MEX
题目描述
给定一个长度为 n
的正整数数组 nums
和一个正整数 value
,定义一个操作如下:从数组中任意选择一个元素,将其加上或减去 value
。你可以执行任意次数的操作,返回执行操作后的数组中的最大 MEX 值。MEX 值是指从 0
开始,第一个不存在于数组中的正整数。
思路分析
在可以任意次数加减 value
的情况下,每个数 x
都可以变成 x + y * value
,其中 y
是任意整数,value
相当于一个模数。那么从 0
开始向大遍历,看看这个数能否从已知里来,显然需要同余的数里来。把所有同余的数计数到一起即可。
具体地,我们可以用一个哈希表来记录数组中每个元素对 value
取模后的出现次数。然后我们从 0
开始遍历每个正整数,如果它对 value
取模后在哈希表中有对应的值,说明它可以由数组中的某个元素经过操作得到,那么我们就将哈希表中的值减一,并且继续遍历下一个正整数。如果它对 value
取模后在哈希表中没有对应的值,说明它不能由数组中的任何元素经过操作得到,那么我们就找到了最大 MEX 值,返回即可。
代码实现
class Solution:
def findSmallestInteger(self, nums: List[int], value: int) -> int:
n = len(nums) # 获取数组长度
cnt = Counter() # 初始化哈希表
for v in nums: # 遍历每个元素
cnt[v % value] += 1 # 将其对 value 取模后加入哈希表
ans = 0 # 初始化答案
while cnt[ans % value] > 0: # 如果当前正整数对 value 取模后在哈希表中有对应的值
cnt[ans % value] -= 1 # 将哈希表中的值减一
ans += 1 # 将答案加一
return ans # 返回答案