classSolution: defminOperations(self, nums: List[int], target: int) -> int: ifsum(nums) < target: return -1 cnt = Counter(nums) ans = s = i = 0 while1 << i <= target: s += cnt[1 << i] << i mask = (1 << (i + 1)) - 1 i += 1 if s >= target & mask: continue ans += 1# 一定要找更大的数操作 while cnt[1 << i] == 0: ans += 1# 还没找到,继续找更大的数 i += 1 return ans
classSolution: defgetMaxFunctionValue(self, receiver: List[int], k: int) -> int: n = len(receiver) m = k.bit_length() - 1 pa = [[(p, p)] + [None] * m for p in receiver] for i inrange(m): for x inrange(n): p, s = pa[x][i] pp, ss = pa[p][i] pa[x][i + 1] = (pp, s + ss) # 合并节点值之和
ans = 0 for i inrange(n): x = sum = i for j inrange(m + 1): if (k >> j) & 1: # k 的二进制从低到高第 j 位是 1 x, s = pa[x][j] sum += s ans = max(ans, sum) return ans
思路:这题当时因为给的范围特别小,我直接把所有的满足要求的数打印出来。灵神则是通过,遍历 Low High 直接对比两位。当时做这个题的时候,总觉得是有规律的,按道理应该是可以减少时间复杂度的。
1 2 3 4 5 6 7 8 9 10 11 12 13
classSolution: defcountSymmetricIntegers(self, low: int, high: int) -> int: ans = 0 for i inrange(low, high + 1): s = str(i) n = len(s) ans += n % 2 == 0andsum(map(int, s[:n // 2])) == sum(map(int, s[n // 2:])) return ans
classSolution: defminimumOperations(self, num: str) -> int: n = len(num) deff(tail: str) -> int: i = num.rfind(tail[1]) if i < 0: return n i = num.rfind(tail[0], 0, i) # 写成 num[:i].rfind(tail[0]) 会产生额外的切片空间 if i < 0: return n return n - i - 2 returnmin(n - ('0'in num), f("00"), f("25"), f("50"), f("75"))
思路:首先得把题目进行一个转换,转换成子序列和,而这中间又涉及一个如何把(l,r)之间的和弄出来,这边灵神的思路是再保留一个 list,元素 i 就是子序列前 i 个元素的和,真的是非常妙呀!要擅长使用过 Counter() 代表哈希表
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defcountInterestingSubarrays(self, nums: List[int], mod: int, k: int) -> int: cnt = Counter([0]) # 把 s[0]=0 算进去 ans = s = 0 for x in nums: s += x % mod == k ans += cnt[(s - k) % mod] # Python 取模可以把负数自动转成非负数 cnt[s % mod] += 1 return ans
classSolution: defnumberOfPoints(self, nums: List[List[int]]) -> int: max_end = max(end for _, end in nums) diff = [0] * (max_end + 2) for start, end in nums: diff[start] += 1 diff[end + 1] -= 1 returnsum(s > 0for s in accumulate(diff))
classSolution: defminimumMoves(self, grid: List[List[int]]) -> int: from_ = [] to = [] for i, row inenumerate(grid): for j, cnt inenumerate(row): if cnt > 1: from_.extend([(i, j)] * (cnt - 1)) elif cnt == 0: to.append((i, j))
ans = inf for from2 in permutations(from_): total = 0 for (x1, y1), (x2, y2) inzip(from2, to): total += abs(x1 - x2) + abs(y1 - y2) ans = min(ans, total) return ans
classSolution: defmaximumSumOfHeights(self, a: List[int]) -> int: n = len(a) suf = [0] * (n + 1) st = [n] # 哨兵 s = 0 for i inrange(n - 1, -1, -1): x = a[i] whilelen(st) > 1and x <= a[st[-1]]: j = st.pop() s -= a[j] * (st[-1] - j) # 撤销之前加到 s 中的 s += x * (st[-1] - i) # 从 i 到 st[-1]-1 都是 x suf[i] = s st.append(i)
ans = s st = [-1] # 哨兵 pre = 0 for i, x inenumerate(a): whilelen(st) > 1and x <= a[st[-1]]: j = st.pop() pre -= a[j] * (j - st[-1]) # 撤销之前加到 pre 中的 pre += x * (i - st[-1]) # 从 st[-1]+1 到 i 都是 x ans = max(ans, pre + suf[i + 1]) st.append(i) return ans
# 标记 10**5 以内的质数 MX = 10 ** 5 + 1 is_prime = [True] * MX is_prime[1] = False for i inrange(2, isqrt(MX) + 1): if is_prime[i]: for j inrange(i * i, MX, i): is_prime[j] = False
classSolution: defcountPaths(self, n: int, edges: List[List[int]]) -> int: g = [[] for _ inrange(n + 1)] for x, y in edges: g[x].append(y) g[y].append(x)
defdfs(x: int, fa: int) -> None: nodes.append(x) for y in g[x]: if y != fa andnot is_prime[y]: dfs(y, x)
ans = 0 size = [0] * (n + 1) for x inrange(1, n + 1): ifnot is_prime[x]: # 跳过非质数 continue s = 0 for y in g[x]: # 质数 x 把这棵树分成了若干个连通块 if is_prime[y]: continue if size[y] == 0: # 尚未计算过 nodes = [] dfs(y, -1) # 遍历 y 所在连通块,在不经过质数的前提下,统计有多少个非质数 for z in nodes: size[z] = len(nodes) # 这 size[y] 个非质数与之前遍历到的 s 个非质数,两两之间的路径只包含质数 x ans += size[y] * s s += size[y] ans += s # 从 x 出发的路径 return ans
classSolution: defminimumSum(self, nums: List[int]) -> int: n = len(nums) suf = [0] * n suf[-1] = nums[-1] for i inrange(n - 2, 1, -1): suf[i] = min(suf[i + 1], nums[i])
ans = inf pre = nums[0] for j inrange(1, n - 1): if pre < nums[j] > suf[j + 1]: ans = min(ans, pre + nums[j] + suf[j + 1]) pre = min(pre, nums[j]) return ans if ans < inf else -1
classSolution: defminGroupsForValidAssignment(self, nums: List[int]) -> int: cnt = Counter(nums) for k inrange(min(cnt.values()), 0, -1): ans = 0 for c in cnt.values(): q, r = divmod(c, k) if q < r: break ans += (c + k) // (k + 1) else: return ans
# 预处理每个数的真因子,时间复杂度 O(MX*logMX) MX = 201 divisors = [[] for _ inrange(MX)] for i inrange(1, MX): for j inrange(i * 2, MX, i): divisors[j].append(i)
defget_modify(s: str) -> int: res = n = len(s) for d in divisors[n]: cnt = 0 for i0 inrange(d): i, j = i0, n - d + i0 while i < j: cnt += s[i] != s[j] i += d j -= d res = min(res, cnt) return res
classSolution: defminimumChanges(self, s: str, k: int) -> int: n = len(s) modify = [[0] * n for _ inrange(n - 1)] for left inrange(n - 1): for right inrange(left + 1, n): # 半回文串长度至少为 2 modify[left][right] = get_modify(s[left: right + 1])
@cache defdfs(i: int, j: int) -> int: if i == 0: return modify[0][j] returnmin(dfs(i - 1, L - 1) + modify[L][j] for L inrange(i * 2, j)) return dfs(k - 1, n - 1)