记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
-
-
- [9/21 3524. 求出数组的 X 值 I](#9/21 3524. 求出数组的 X 值 I)
- [9/22 3525. 求出数组的 X 值 II](#9/22 3525. 求出数组的 X 值 II)
- [9/23 1658. 将 x 减到 0 的最小操作数](#9/23 1658. 将 x 减到 0 的最小操作数)
- [9/24 1096. 花括号展开 II](#9/24 1096. 花括号展开 II)
- [9/25 3550. 数位和等于下标的最小下标](#9/25 3550. 数位和等于下标的最小下标)
- [9/26 1807. 替换字符串中的括号内容](#9/26 1807. 替换字符串中的括号内容)
- [9/27 1190. 反转每对括号间的子串](#9/27 1190. 反转每对括号间的子串)
-
9/21 3524. 求出数组的 X 值 I
删掉任意前缀和后缀、中间不能空,剩下的就是一段连续子数组。题目其实是:统计所有非空子数组,按乘积模 k 分组,resultx 是余数为 x 的个数。
从左往右扫,记下目前以当前位置结尾、乘积模 k 分别有多少段。
当前数既可以自己单开一段,也可以接到前面那些段后面(余数变成 旧余数*当前数 % k)。每扫完一个位置,把这些段数加进答案。
python
def resultArray(nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
ans = [0] * k
cnt = [0] * k
for val in nums:
v = val % k
nxt = [0] * k
nxt[v] += 1
for r in range(k):
nxt[r * v % k] += cnt[r]
cnt = nxt
for r in range(k):
ans[r] += cnt[r]
return ans
9/22 3525. 求出数组的 X 值 II
每次询问先改 numsindex(这次改动会一直留下),再丢掉左边前缀,只看 numsstart...n-1。
右边还可以再丢掉一段后缀,数组不能空,所以剩下的一定是从 numsstart 开头、到某个位置 r 为止的一段。
问题变成:有多少个 r,使得 numsstart*...*numsr 模 k 等于 x。
k 最大只有 5,用线段树每个节点记下两样东西:这段整体乘积模 k,以及「从这段左端点出发的各个前缀,乘积模 k 分别有多少个」。
合并左右两段时,左段前缀原样留下;右段每个前缀前面要先乘上左段整体乘积,再加进计数。单点修改后查询 start, n-1 即可。
python
def resultArray(nums, k, queries):
"""
:type nums: List[int]
:type k: int
:type queries: List[List[int]]
:rtype: List[int]
"""
n = len(nums)
a = [x % k for x in nums]
prod = [1] * (4 * n)
cnt = [[0] * k for _ in range(4 * n)]
def pull(p):
l, r = p * 2, p * 2 + 1
prod[p] = prod[l] * prod[r] % k
c = cnt[p]
for i in range(k):
c[i] = cnt[l][i]
lp = prod[l]
for i in range(k):
c[i * lp % k] += cnt[r][i]
def build(p, l, r):
if l == r:
prod[p] = a[l]
cnt[p][a[l]] = 1
return
m = (l + r) // 2
build(p * 2, l, m)
build(p * 2 + 1, m + 1, r)
pull(p)
def update(p, l, r, i, v):
if l == r:
for j in range(k):
cnt[p][j] = 0
prod[p] = v
cnt[p][v] = 1
return
m = (l + r) // 2
if i <= m:
update(p * 2, l, m, i, v)
else:
update(p * 2 + 1, m + 1, r, i, v)
pull(p)
def query(p, l, r, ql, qr):
if ql <= l and r <= qr:
return prod[p], cnt[p][:]
m = (l + r) // 2
if qr <= m:
return query(p * 2, l, m, ql, qr)
if ql > m:
return query(p * 2 + 1, m + 1, r, ql, qr)
lp, lc = query(p * 2, l, m, ql, qr)
rp, rc = query(p * 2 + 1, m + 1, r, ql, qr)
nc = lc[:]
for i in range(k):
nc[i * lp % k] += rc[i]
return lp * rp % k, nc
build(1, 0, n - 1)
ans = []
for idx, val, start, x in queries:
update(1, 0, n - 1, idx, val % k)
ans.append(query(1, 0, n - 1, start, n - 1)[1][x])
return ans
9/23 1658. 将 x 减到 0 的最小操作数
suml,sumr用来记录前缀 后缀的和
l,r记录前缀0,l 后缀的位置r,n
初始空前缀l=-1,全后缀r=0
遍历每一个前缀l
如果suml+sumr>x 则减少后缀
python
def minOperations(nums, x):
"""
:type nums: List[int]
:type x: int
:rtype: int
"""
n = len(nums)
s = sum(nums)
if s<x:
return -1
suml,sumr = 0,s
r = 0
ans = n+1
for l in range(-1,n-1):
if l!=-1:
suml+=nums[l]
while r<n and suml+sumr>x:
sumr-=nums[r]
r+=1
if suml+sumr==x:
ans = min(ans,l+1+n-r)
return -1 if ans>n else ans
9/24 1096. 花括号展开 II
递归解析
add用来生成两个set相加
如果遇到, 说明前后两部分相或
如果遇到{ 往后找到其对应的} 将这部分递归解析
如果前面为, 则将两部分相或 否则相加
其他符号则为表达式相连 根据前一个符号来决定相或 相加
python
def braceExpansionII(expression):
"""
:type expression: str
:rtype: List[str]
"""
def add(a,b):
ans = set()
for i in a:
for j in b:
ans.add(i+j)
return ans
def check(ex):
tmp = set()
ans = set()
loc = 0
last = ","
while loc<len(ex):
if ex[loc]==",":
ans = ans | tmp
tmp =set()
loc +=1
elif ex[loc]=="{":
cur = 1
x = loc+1
while cur>0:
if ex[x]=="{":
cur+=1
elif ex[x]=="}":
cur-=1
x+=1
if last ==",":
tmp = tmp | check(ex[loc+1:x-1])
else:
tmp = add(tmp,check(ex[loc+1:x-1]))
loc = x
last = "}"
else:
s = ""
while loc<len(ex) and ex[loc]!="," and ex[loc]!="{":
s += ex[loc]
loc+=1
if last==",":
tmp.add(s)
else:
tmp = {i+s for i in tmp}
last = ex[loc-1]
return ans | tmp
return sorted(check(expression))
9/25 3550. 数位和等于下标的最小下标
从左到右依次判断 func用来计算num的数位和
python
def smallestIndex(nums):
"""
:type nums: List[int]
:rtype: int
"""
def func(num):
res = 0
while num > 0:
res += num % 10
num //= 10
return res
for i in range(len(nums)):
if i == func(nums[i]):
return i
return -1
9/26 1807. 替换字符串中的括号内容
按序遍历 m存储knowledge一一对应的内容
遇到(时 获取括号内容 在m中查询
python
def evaluate(s, knowledge):
"""
:type s: str
:type knowledge: List[List[str]]
:rtype: str
"""
loc = 0
n = len(s)
ans = ""
m = {}
for k,v in knowledge:
m[k] = v
while loc<n:
if s[loc]=="(":
loc +=1
cur = ""
while s[loc]!=")":
cur +=s[loc]
loc+=1
if cur in m:
ans +=m[cur]
else:
ans +="?"
else:
ans +=s[loc]
loc+=1
return ans
9/27 1190. 反转每对括号间的子串
1.遇到字母就往结果里追加。
遇到左括号记下当前结果写到了哪。
遇到右括号,就把对应左括号之后追加的那一段原地翻转。
从内到外每对括号翻转一次。
2.遇到左括号把当前攒好的串压栈,开始攒括号里面的新串。
遇到右括号把里面攒的串翻转,再接到栈里弹出的外层串后面。
最后剩下的就是答案。
python
def reverseParentheses(s):
"""
:type s: str
:rtype: str
"""
l = []
ans = []
loc = 0
for i in range(lenss(s)):
if s[i]>='a' and s[i]<='z':
ans.append(s[i])
loc+=1
elif s[i]=='(':
l.append(loc)
else:
start = l.pop()
if start==0:
ans = ans[::-1]
else:
ans[start:loc] = ans[loc-1:start-1:-1]
return ''.join(ans)
def reverseParentheses2(s):
"""
:type s: str
:rtype: str
"""
ans = []
num=''
for i in s:
if i=='(':
ans.append(num)
num=''
elif i==')':
a = ans.pop()
num = num[::-1]
num = a+num
else:
num+=i
return num