目录
1.周赛总结
第1题:公因子的数目
第2题:沙漏的最大总和
第3题:最小XOR
第4题:对字母串可执行的最大删除数
2.Trie
1.周赛总结
首先,先展示一波,我这周的战绩。与第一相比,我简直菜得一批,而且这还是我做得最好的一场周赛!
第1题:公因子的数目
class Solution:
def commonFactors(self, a: int, b: int) -> int:
x = gcd(a,b)
count = 0
for i in range(1,x+1):
if a % i == 0 and b % i == 0:
count += 1
return count
没啥好说的,正常的签到题,正常暴力枚举就好!
需要注意的一点是,两个数的公因子,也一定是最大公约数的因子!
我的代码还可以优化一下!
class Solution:
def commonFactors(self, a: int, b: int) -> int:
x = gcd(a,b)
count = 0
for i in range(1,x+1):
if x % i == 0:
count += 1
return count
第2题:沙漏的最大总和
这个题也没啥好说的,不必用前缀和啥的,就直接暴力模拟一下即可!
class Solution:
def maxSum(self, grid: List[List[int]]) -> int:
def sum_(x,y):
sum_1 = 0
for i in range(x,x+3):
for j in range(y,y+3):
if (i == x + 1 and j == y) or (i == x + 1 and j == y +2) :
continue
sum_1 += grid[i][j]
return sum_1
m = len(grid)
n = len(grid[0])
res = 0
for i in range(m - 2):
for j in range(n - 2):
res = max(res,sum_(i,j))
return res
第3题:最小XOR
这个题思路其实很好想的,不过我模拟时,由于粗心大意,模拟错了三遍!
这道题真得很好,把我最近学得位运算都运用进去了!
class Solution:
def minimizeXor(self, num1: int, num2: int) -> int:
def count_(num):
count = 0
while num:
res = num & -num
num -= res
count += 1
return count
n = count_(num2)
lst=[]
count = 0
for i in range(31,-1,-1):
if num1 >> i & 1:
count += 1
if count:
lst.append(num1 >> i & 1)
lst = lst[::-1]
# print(n)
# print(lst)
l = len(lst)
if n == count:
return num1
elif n > count:
flag = n - count
s = 0
while flag > 0:
for i in range(l):
if flag == 0:
break
if lst[i] == 0:
s += 2 **i
# print(s)
flag -= 1
for i in range(l,l+flag):
s += 2**i
flag -= 1
return num1+s
elif n < count:
flag = count - n
for i in range(l):
if flag == 0:
break
if lst[i] == 1:
num1 -= 2**i
flag -= 1
return num1
第4题:对字母串可执行的最大删除数
这道题我不会做!
我就简要说一下,我关注了两个up主的做法!
第一个是灵神:
LCP + 动态规划
LCP:最小公共前缀
求法:
求的是s[i:] 与 s[j:] 的最长公共前缀
s = "abababababsbdbuidhq"
if s[i] == s[j]:
lcp [i][j] = lcp[i+1][j+1] + 1
else:
lcp[i][j] = 0 (因为第一个数就不同,那么肯定为0)
动态规划:
if s[i:j] == s[i+j:i+2j]:
f[i] = f[i + j] + 1
(把s[i:j]删掉需要一次,之后是之前已经求过的f[i+j],因为是前面与后面有关,所以从后往前遍历)
else:
f[i] = 1 (不能与后面的数组成公共的,则将其整个删掉,所以为1)
class Solution:
def deleteString(self, s: str) -> int:
n = len(s)
if len(set(s)) == 1:
return n
lcp = [[0] * (n + 1) for _ in range(n + 1)]
for i in range(n - 1, -1, -1):
for j in range(n - 1, -1, -1):
if s[i] == s[j]:
lcp[i][j] = lcp[i + 1][j + 1] + 1
f = [1] * n
for i in range(n - 1, -1, -1):
# i + 2j <= n
# j <= (n - i)//2
for j in range(1, (n - i) // 2 + 1):
if lcp[i][i + j] >= j:
f[i] = max(f[i], f[i + j]+1)
return f[0]
第二个是y总:
字符串哈希 + 动态规划
class Solution:
def deleteString(self, s: str) -> int:
n = len(s)
if len(set(s)) == 1:
return n
base = 131
p = [0 for _ in range(n+1)]
h = [0 for _ in range(n+1)]
p[0] = 1
for i in range(1,n+1):
p[i] = p[i-1] * base
h[i] = h[i-1] * base + ord(s[i-1])
def get(l,r):
return h[r] - h[l-1] * p[r - l + 1]
f = [1] * n
for i in range(n - 1, -1, -1):
for j in range(1, (n - i) // 2 + 1):
if get(i+1,i+j) == get(i+j+1,i+2*j):
f[i] = max(f[i], f[i + j]+1)
return f[0]
不过python会超时,y总用c++就没超,不过还是贴一下代码,字符串哈希确实巧妙!
class Solution:
def deleteString(self, s: str) -> int:
n = len(s)
if len(set(s)) == 1:
return n
base = 131
p = [0 for _ in range(n+1)]
h = [0 for _ in range(n+1)]
MOD = 123456789
p[0] = 1
for i in range(1,n+1):
p[i] = p[i-1] * base % MOD
h[i] = ((h[i-1] * base) + ord(s[i-1]))% MOD
def get(l,r):
return (h[r] % MOD - h[l - 1] * p[r - l + 1] % MOD + MOD) % MOD
f = [1] * n
for i in range(n - 1, -1, -1):
for j in range(1, (n - i) // 2 + 1):
if get(i+1,i+j) == get(i+j+1,i+2*j):
f[i] = max(f[i], f[i + j]+1)
return f[0]
经过取模优化,这里竟让过了,字符串哈希你太牛了
这里不仅要感叹一下python切片功能的强大,直接用切片比较字符串是否相等,居然是最快的做法,实在令人感叹!
class Solution:
def deleteString(self, s: str) -> int:
n = len(s)
if len(set(s)) == 1:
return n
f = [1] * n
for i in range(n - 1, -1, -1):
# i + 2j <= n
# j <= (n - i)//2
for j in range(1, (n - i) // 2 + 1):
if s[i:i+j] == s[i+j:i+2*j]:
f[i] = max(f[i], f[i + j]+1)
return f[0]
哈哈哈,简单干脆,不得不说,python真强,人生苦短,我用python!
2.Trie
Trie 是一种数据结构,也叫字典树,可以快速存储与查找字符串。
速度很快,甚至比哈希表更快,不过这是一种以时间换空间的结构,需要定义极大的空间。
这里尝试以二维数组方式实现字典树,其实有很多种字典树,不过以我目前的水平,先掌握这一种
吧!来日方长!
如图所示!
所有的字符串,都是从根节点root引入!并且对最后一个节点进行标记,证明存在这样一个以标记节点结尾的字符串!
话不多说,模板代码展示!
trie = [[0 for _ in range(26)]for _ in range(100010)]
cnt =[0 for _ in range(100010)]
idx = 0
def insert(str):
global trie,cnt,idx
p = 0
n = len(str)
for i in range(n):
s = ord(str[i]) - 97
if not trie[p][s]:
idx += 1
trie[p][s] = idx
p = trie[p][s]
cnt[p] += 1
def search(str):
global trie,cnt
p = 0
n = len(str)
for i in range(n):
s = ord(str[i]) - 97
if not trie[p][s]:
return 0
p = trie[p][s]
return cnt[p]
或许大家不知道,这个二维数组最后变成什么样了,我打印了一部分如下:
再配一道ACwing经典的例题
结合上述模板,再配上输入输出
n = int(input())
while n:
o,s = input().split()
if o =="I":
insert(s)
else:
print(search(s))
n -= 1
除此之外,还有一道变题!
这道题,若用暴力法,时间复杂度是O(n^2),max(N)^2 = 10 ^10,必然超时,于是我们想到在内层循环进行优化!
我们知道 0 ^ 0 = 0, 1 ^ 1 = 0,1 ^ 0 = 1
若想让异或值最大,则要使两个数的二进制数的对应位不一样的多一些。一个贪心的思路
于是,我们想到,将整数转化成二进制数,存储在字典树中,之后在字典树中,不断寻找与自己不一样的节点,便可使得异或值越大!
代码展示如下!
t = [[0,0] for _ in range(3100000)]
idx = 0
def insert(x):
global t,idx
p = 0
for i in range(31,-1,-1):
u = x >> i & 1
if not t[p][u]:
idx += 1
t[p][u] = idx
p = t[p][u]
def search(x):
global t
p = 0
res = 0
for i in range(31,-1,-1):
u = x >> i & 1
if t[p][u^1]:
p = t[p][u^1]
res = res * 2 + u^1
else:
p = t[p][u]
res = res * 2 + u
return res
res = 0
n = int(input())
lst = list(map(int,input().split()))
for x in lst:
insert(x)
res = max(res,search(x)^x)
print(res)