四道算法题+一道陈述题
- 有一个长度为n的数组是1到n的排列,现在我们每次可以进行一个操作,选择数组中第i个数和第j个数,对第i个数减去1而对第j个数加上1,要求操作后,数组中仍为一个1到n的排列。要求进行尽可能少的操作次数后,使得数组是非递减的。按顺序输出操作,答案可能有很多种,任意一种合理的即可。
"""
假定我们在一次操作中选中了a与b两个数字,a+=1 b-=1,
由于操作后数组仍为全排列,因此必定有set(a,b)=set(a-1,b+1)。
于是有a-1=b,即我们每次进行的操作必定是选两个值相差1的数,
其实就相当于交换二者的位置。
那我们可以贪心地求解这个问题,从前往后为第i个位置找到其主人
如果当前的nums[i]是大于i+1的,那么我们不断地进行操作使得这
个位置上的数字减去1,直到nums[i]=i+1即可
"""
def func1(arr):
#输出操作使得arr是升序的
#每次操作后都必须保证是一个排列,说白了就是a b变成a+1 b-1 有a = b-1
#即每次可以交换大小差距为1的两个数的位置 所以对nums[i] 可以进行nums[i]-i+1
dic={}#dic[i]记录数字i在arr中的下标
for i,a in enumerate(arr):
dic[a] = i
times = 0
ans = []
for i in range(len(arr)):
while arr[i] != i + 1:
#将arr[i]与arr[i]-1交换位置
times += 1
a = dic[arr[i]]#得到需要交换的两个数字的下标
b = dic[arr[i]-1]
ans.append((b,a))
dic[arr[i]] = b#记录更改后的下标
dic[arr[i]-1] = a
cur = arr[i]
arr[a] = cur-1#进行位置交换
arr[b] = cur
print(times)
for a,b in ans:
print(a,b)
2.有一个由字母r,e,d组成的字符串,问其中有多少个子串满足其中三种字母的数目一样多。
"""
可以记录s[0:i]中三种字母的数字信息,只需要用一个大小为2的tuple=(a,b)即可描述此时三种字母的差值,a=count(e)-count(r) b = count(d)-count(r)
如果一个子串s[i:j]满足要求,必定有s[0:i]对应的差值信息与s[0:j]的差值信息相同。
因此我们可以用一个dic记录之前出现过(a,b)差值的位置
"""
import collections
#计算由r e d构成的字符串中有多少个子串中r e d数目相同
def func2(s1):
dic = collections.defaultdict(int)
r = 0#记录到目前为止,三种字母的出现次数
e = 0
d = 0
ans = 0
#dic[(a,b)] 代表三种字母出现的值的为 c, c+a, c+b的情况
dic[(0,0)]+= 1
for i in range(len(s1)):
if s1[i] == 'r':
r += 1
elif s1[i] == 'e':
e += 1
else:
d += 1
#然后查找dic[(e-r,d-r)]的个数
ans += dic[(e-r,d-r)]
dic[(e-r,d-r)]+=1
print(ans)
3.有一个数组arr,现在要从中挑选k个数来把它们做按位与运算,求最大值
"""
把arr中的每个数字都写成二进制形式后,我们可以从高位往低位遍历,
对第i位时,我们需要遍历arr中的a,将满足a[i]=1的a加入候选者列表。
遍历完后,如果此时候选者列表数目小于k,说明这一位上无法找到k个1,
因此答案的这一位必定为0;否则说明这一位上可以找到k个1,答案这一
位为1,并将arr置为候选者列表。继续对第i+1位重复这个过程
"""
def func3(arr,k):
ans = [0 for i in range(30)]#决定最终答案每个数位上的结果
temp = []
for a in arr:
cur = str(bin(a))[2:]
if len(cur) < 30:
cur = '0'*(30-len(cur))+cur
temp.append(cur)
for i in range(30):
cur = []
#代表当前检查第i位结果
for a in temp:
if a[i] == '1':
cur.append(a)
if len(cur) >= k:#代表这个位置上有超过k个数为1,所以答案此位置置为1,然后把候选者加入其中;否则此位置为0,保留全部参与者进行下一轮比试
ans[i] = 1
temp = cur
result = 0
for a in ans:
result*=2
result+=a
print(result)
- 一个数列,第一项是a,第二项是b,随后的每一项等于前两项乘积后再平方,求第N项的值。因为值很大,所以答案对10**9+7取模。 a,b,N<1e12
"""
题目意思很简单,但是由于N较大,直接写肯定超时。我考试时也没想出来咋写,只能设了个限制,然后正常迭代来写。后面查了资料,发现可以用快速幂来优化
"""
#傻瓜版本,只过了60%
def func4(a,b,n):
if n > 1e8:
print(0)
return
a = a%(10**9+7)
b = b%(10**9+7)
if n == 1:
print(a)
return
elif n == 2:
print(b)
return
first = 0,
second = b
for i in range(2,n):
cur=(first*second)%(10**9+7)
cur = (cur*cur)%(10**9+7)
first = second
second = cur
print(cur)
#快速幂版本
"""
观察可以发现,我们可以把第i项写作[Ai,Bi]代表第i项是a的Ai次幂与b的Bi次幂的乘积
有A0 = 1 A1 = 0 A2 = 2 A3= 4
B0=0 B1=1 B2 = 2 B3 = 6
发现有Ai+2 = [2 2 Ai+1
Ai+1 1 0] * Ai
因此可以得到AN [2 2 A1
AN-1 =( 1 0] )**(N-1) * A0
同理得到 BN [2 2 B1
BN-1 =( 1 0] )**(N-1) * B0
#我们用快速幂得到AN与BN后 再用快速幂求出a**AN与b**BN
2 2 2 2 6 4 16 12
1 0 1 0 = 2 2 6 4
"""
from functools import cache
MOD = 10**9+7
@cache
def fast(a,times):
#用于快速求得a的times次幂
if times == 0:
return 1
if times == 1:
return a%MOD
rest = times%2
temp = fast(a, times//2)
ans = temp*temp
if rest:
ans *= a
return ans%MOD
def multi(a,b):
#用于矩阵乘法
a11,a12,a21,a22 = a
b11,b12,b21,b22 = b
c11 = a11*b11+a12*b21
c12 = a11*b12+a12*b22
c21 = a21*b11+a22*b21
c22 = a21*b12+a22*b22
return c11%(MOD-1),c12%(MOD-1),c21%(MOD-1),c22%(MOD-1)
#有一个问题,就是矩阵的元可能过大,需不需要也取个模?根据费马小定理发现
#,如果p是质数,a不是p的倍数,则a**(p-1)modp=1 于是我们对矩阵的元mod(p-1)
#如果不用费马小定理优化还是会超时
@cache
def fast_matrix(a,times):
a11, a12, a21, a22 = a
if times == 0:
return 1,0,0,1
elif times == 1:
return a11,a12,a21,a22
rest = times%2
t = fast_matrix(a,times//2)
ans = multi(t,t)
if rest:
ans = multi(ans,a)
return ans
#快速幂优化版本
def func4_new(a,b,n):
a = a % MOD
b = b % MOD
if n == 0:
return a
elif n == 1:
return b
ans = fast_matrix((2,2,1,0),n-2)
# print('ans:',ans)
m11, m12, _, _ = ans
A = fast(a,m12)
B = fast(b,m11)
print((A*B)%MOD)
陈述题:
讲讲怎么处
理同声传译中的1)多模态问题2)实时性翻译3)翻译涉及专业术语,在通用语料上的训练有偏差怎么解决
帮助你的研究生同学写好第一篇学术论文,你该怎么用NLP领域的知识解决这个问题
PS:最后吐个槽,一开始因为网络原因,我一直没法连上网页。于是我拨打了下图中的手机,结果显示该号码已停机。。。有点离谱。。。