记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
7/20 1260. 二维网格迁移
mn 对于gridij 标记为i n+j
每个数移动k次 找到移动后的标记位
python
def shiftGrid(grid, k):
"""
:type grid: List[List[int]]
:type k: int
:rtype: List[List[int]]
"""
m,n = len(grid),len(grid[0])
ans = [[0]*n for _ in range(m)]
total = m*n
for i in range(m):
for j in range(n):
loc = (i*n+j+k)%total
x = loc//n
y = loc%n
ans[x][y] = grid[i][j]
return ans
7/21 3499. 操作后最大活跃区段数 I
一次交易等价于:删掉夹在两段 0 中间的一段 1,再把合并后的那整段 0 全部变成 1。
因此最终活跃段数等于原串中 1 的个数,再加上某两段相邻 0 段长度之和的最大值。
扫描连续相同字符段,累计所有 1 的个数,并用前一段 0 与当前段 0 更新相邻两段 0 的最大长度和。
若无法形成合法交易,额外增益为 0。
python
def maxActiveSectionsAfterTrade(s):
"""
:type s: str
:rtype: int
"""
n = len(s)
ans = 0
pre = float("-inf")
mx = 0
i = 0
while i < n:
j = i + 1
while j < n and s[j] == s[i]:
j += 1
cur = j - i
if s[i] == "1":
ans += cur
else:
mx = max(mx, pre + cur)
pre = cur
i = j
return ans + mx
7/22 3501. 操作后最大活跃区段数 II
与3499相同,一次交易的收益等于某两段相邻 0 段长度之和。
整串最终活跃数等于原串 1 的个数加上区间内最大收益;无法交易时收益为 0。
预处理所有 0 段,并把相邻两段长度和建成稀疏表做区间最大值查询。
对每个查询 l,r,需要单独处理被端点截断的 0 段,以及完全落在区间内的相邻 0 段对。
python
def maxActiveSectionsAfterTrade(s, queries):
"""
:type s: str
:type queries: List[List[int]]
:rtype: List[int]
"""
n = len(s)
ones = 0
groups = [] # (start, length)
lookup = [0] * n
for i, c in enumerate(s):
if c == "0":
if i > 0 and s[i - 1] == "0":
st, ln = groups[-1]
groups[-1] = (st, ln + 1)
else:
groups.append((i, 1))
else:
ones += 1
lookup[i] = len(groups) - 1
if not groups:
return [ones] * len(queries)
merges = [groups[i][1] + groups[i + 1][1] for i in range(len(groups) - 1)]
class SparseTable:
def __init__(self, arr):
self.n = len(arr)
if self.n == 0:
self.st = []
return
k = self.n.bit_length()
self.st = [arr[:] for _ in range(k)]
for i in range(1, k):
step = 1 << (i - 1)
row = self.st[i]
prev = self.st[i - 1]
for j in range(self.n - (1 << i) + 1):
row[j] = max(prev[j], prev[j + step])
def query(self, l, r):
i = (r - l + 1).bit_length() - 1
return max(self.st[i][l], self.st[i][r - (1 << i) + 1])
st = SparseTable(merges)
ans = []
for l, r in queries:
res = ones
left_gi = lookup[l]
right_gi = lookup[r]
left = left_gi + 1
right = right_gi - (1 if s[r] == "0" else 0)
left_cnt = -1
if left_gi != -1:
gs, gl = groups[left_gi]
left_cnt = gl - (l - gs)
right_cnt = -1
if right_gi != -1:
gs, _ = groups[right_gi]
right_cnt = r - gs + 1
if left <= right - 1:
res = max(res, ones + st.query(left, right - 1))
if s[l] == "0" and s[r] == "0" and left_gi + 1 == right_gi:
res = max(res, ones + left_cnt + right_cnt)
if s[l] == "0" and left_gi + 1 <= right:
res = max(res, ones + left_cnt + groups[left_gi + 1][1])
if s[r] == "0" and left <= right_gi - 1:
res = max(res, ones + right_cnt + groups[right_gi - 1][1])
ans.append(res)
return ans
7/23 3513. 不同 XOR 三元组的数目 I
nums 是 1...n 的排列,答案只与 n 有关。
允许下标重复取,因此每个数都可以单独出现为 a XOR a XOR a = a。
当 n < 3 时,能得到的不同 XOR 值恰好有 n 个。
当 n >= 3 时,可以证明所有三元组 XOR 恰好覆盖 [0, 2^k) 中的全部整数,其中 2^k 是大于等于 n 的下一个 2 的幂(n 本身是 2 的幂时取 2n)。
因此答案为 1 << n.bit_length()。
python
def uniqueXorTriplets(nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
if n < 3:
return n
return 1 << n.bit_length()
7/24 3514. 不同 XOR 三元组的数目 II
允许下标重复,且 XOR 可交换,因此答案等于数组中任取三个元素(可重复)得到的不同 XOR 值个数。
先对 nums 去重。枚举所有二元 XOR 值 a XOR b,再用布尔数组标记;再枚举这些值与第三个元素 c 的 XOR,标记最终结果。
最后统计标记个数即可。
python
def uniqueXorTriplets(nums):
"""
:type nums: List[int]
:rtype: int
"""
vals = list(set(nums))
mx = max(vals)
size = 1 << mx.bit_length()
pair = [False] * size
for a in vals:
for b in vals:
pair[a ^ b] = True
res = [False] * size
for ab in range(size):
if not pair[ab]:
continue
for c in vals:
res[ab ^ c] = True
return sum(res)
7/25
python
7/26
python