P1. 替换所有的问号 显示英文描述
给你一个仅包含小写英文字母和 ‘?’ 字符的字符串 s ,请你将所有的 ‘?’ 转换为若干小写字母,使最终的字符串不包含任何 连续重复 的字符。
注意:你 不能 修改非 ‘?’ 字符。
题目测试用例保证 除 ‘?’ 字符 之外,不存在连续重复的字符。
在完成所有转换(可能无需转换)后返回最终的字符串。如果有多个解决方案,请返回其中任何一个。可以证明,在给定的约束条件下,答案总是存在的。
解:
- “ x ? y " = > " x z y " “x?y" => "xzy" “x?y"=>"xzy"
- " x 0 ? ? ? y " = > " x 1 ? ? y " = > . . . "x_0???y"=>"x_1??y" => ... "x0???y"=>"x1??y"=>...
- 遍历+枚举, 因为解一定存在。
class Solution:
def modifyString(self, s: str) -> str:
ret = ['^']
n = len(s)
s = ['^'] + list(s) + ['$']
f = lambda x: chr(ord('a') + x)
A = [f(x) for x in range(26)]
for i in range(1, n+1):
if s[i] != '?':
ret.append(s[i])
else:
for ch in A:
if ch != ret[-1] and ch != s[i+1]:
ret.append(ch)
break
return "".join(ret[1:])
P2. 数的平方等于两数乘积的方法数
给你两个整数数组 nums1 和 nums2 ,请你返回根据以下规则形成的三元组的数目(类型 1 和类型 2 ):
类型 1:三元组 (i, j, k) ,如果 nums1[i]2 == nums2[j] * nums2[k] 其中 0 <= i < nums1.length 且 0 <= j < k < nums2.length
类型 2:三元组 (i, j, k) ,如果 nums2[i]2 == nums1[j] * nums1[k] 其中 0 <= i < nums2.length 且 0 <= j < k < nums1.length
解:
- Hash
class Solution:
def numTriplets(self, nums1: List[int], nums2: List[int]) -> int:
return self.solve(nums1, nums2) + self.solve(nums2, nums1)
def solve(self, nums1: List[int], nums2: List[int]) -> int:
d = collections.defaultdict(int)
n1, n2 = len(nums1), len(nums2)
for j in range(n1):
for k in range(j+1, n1):
d[nums1[j] * nums1[k]] += 1
return sum(d[x * x] for x in nums2)
P3. 避免重复字母的最小删除成本
给你一个字符串 s 和一个整数数组 cost ,其中 cost[i] 是从 s 中删除字符 i 的代价。
返回使字符串任意相邻两个字母不相同的最小删除成本。
请注意,删除一个字符后,删除其他字符的成本不会改变。
解:
- 不用华丽的操作, 只要扫一遍。
- 我为什么要贴个st表, wa了4发。
class Solution:
def minCost(self, s: str, cost: List[int]) -> int:
c, m, n, ret = cost[0], cost[0], len(s), 0
for i in range(1, n):
if s[i] == s[i-1]:
c += cost[i]
m = max(m, cost[i])
else:
ret += c - m
c, m = cost[i], cost[i]
ret += c - m
return ret
code 2 (比赛时,萌萌的自己,居然还被我搞过去了):
from math import log
class ST:
def __init__(self, arr):
n = len(arr)
K = int(log(n, 2))
self.Ma = [[0]*(K+1) for _ in range(n)]
for k in range(K+1):
for i in range(n):
if k == 0:
self.Ma[i][k] = arr[i]
else:
if i + (1 << (k - 1)) >= n:
continue
self.Ma[i][k] = max(self.Ma[i][k-1], self.Ma[i+(1 << (k-1))][k-1])
def query_max(self, L, R):
k = int(log(R - L + 1, 2))
return max(self.Ma[L][k], self.Ma[R - (1 << k) + 1][k])
class Solution:
def minCost(self, s: str, cost: List[int]) -> int:
st = ST(cost)
n = len(cost)
prefix = [0] * n
for i in range(n):
prefix[i] = prefix[i-1] + cost[i]
def get(L, R):
return prefix[R] if L == 0 else prefix[R] - prefix[L-1]
f = lambda L, R: get(L, R) - st.query_max(L, R)
L, R, ret = 0, -1, 0
for i in range(1, n):
if s[i] != s[L]:
if R != -1:
ret += f(L, R)
L, R = i, -1
else:
R = i
if R != -1: ret += f(L, R)
return ret
P4 保证图可完全遍历
Alice 和 Bob 共有一个无向图,其中包含 n 个节点和 3 种类型的边:
类型 1:只能由 Alice 遍历。
类型 2:只能由 Bob 遍历。
类型 3:Alice 和 Bob 都可以遍历。
给你一个数组 edges ,其中 edges[i] = [typei, ui, vi] 表示节点 ui 和 vi 之间存在类型为 typei 的双向边。请你在保证图仍能够被 Alice和 Bob 完全遍历的前提下,找出可以删除的最大边数。如果从任何节点开始,Alice 和 Bob 都可以到达所有其他节点,则认为图是可以完全遍历的。
返回可以删除的最大边数,如果 Alice 和 Bob 无法完全遍历图,则返回 -1 。
解:
- 倒着思考, 用并查集 带个 路径压缩。 一开始没加,T了。
class DSU:
def __init__(self, N):
self.parent = [i for i in range(N)]
def find(self, x):
if self.parent[x] == x: return x
ret = self.find(self.parent[x])
self.parent[x] = ret
return ret
def union(self, x, y):
self.parent[self.find(x)] = self.parent[self.find(y)]
class Solution:
def maxNumEdgesToRemove(self, n: int, edges: List[List[int]]) -> int:
dsu = DSU(n)
def valid(dsu):
A = [dsu.find(i) for i in range(n)]
return len(set(A)) == 1
t3 = [[x - 1, y - 1] for t, x, y in edges if t == 3]
t2 = [[x - 1, y - 1] for t, x, y in edges if t == 2]
t1 = [[x - 1, y - 1] for t, x, y in edges if t == 1]
use, m = 0, len(edges)
def add_graph(dsu, t):
nonlocal use
for x, y in t:
if dsu.find(x) != dsu.find(y):
dsu.union(x, y)
use += 1
add_graph(dsu, t3)
dsu2 = DSU(n)
dsu2.parent = [x for x in dsu.parent]
add_graph(dsu2, t2)
add_graph(dsu, t1)
return m - use if valid(dsu) and valid(dsu2) else -1