链接: 1146. 快照数组
class SnapshotArray:
def __init__(self, length: int):
self.arr = [{0:0} for _ in range(length)]
self.snap_id = 0
def set(self, index: int, val: int) -> None:
self.arr[index][self.snap_id] = val
def snap(self) -> int:
self.snap_id += 1
return self.snap_id-1
def get(self, index: int, snap_id: int) -> int:
arr = self.arr
dct = arr[index]
# print(sd)
if snap_id in dct :
return dct[snap_id]
ks = list(dct.keys())
pos = bisect_right(ks,snap_id)
if pos < 0:
return 0
return dct[ks[pos-1]]
链接: 1498. 满足条件的子序列数目
MOD = 10**9+7
@cache
def fastPower3(a,n):
ans = 1
base = a
while n != 0:
if (n & 1 != 0):
ans *= base % MOD
base *= base % MOD
n >>= 1
return ans % MOD
f = [1]
for i in range(10**5):
f.append(f[-1]*2%MOD)
class Solution:
def numSubseq(self, nums: List[int], target: int) -> int:
nums.sort()
n = len(nums)
l,r=0,n-1
ans = 0
while l<=r :
while r>=l and nums[l] + nums[r]>target:
r -= 1
if l>r:
break
# ans = (ans+2**(r-l))%MOD
ans = (ans+f[r-l])%MOD
# print(l,r,ans)
l += 1
return ans%MOD
链接: 1802. 有界数组中指定下标处的最大值
这题蛮有意思的,核心是快速计算元素和。
class Solution:
def maxValue(self, n: int, index: int, maxSum: int) -> int:
# 设index上数是k,k∈[1,maxSum-n+1]
# 那它左边要分配长度w=index个数,若w
# 它右边要分配w=n-index-1个,若w
# 为了两边数值最小,两边一定是山峰状最快下降(每次降1)。
def calc(k): # index设k时的元素和
s = k
w = index
s += (k-1+k-w)*w//2 if w<k else (k-1+1)*(k-1)//2 + w-k+1
w = n-index-1
s += (k-1+k-w)*w//2 if w<k else (k-1+1)*(k-1)//2 + w-k+1
return s
return bisect_right(range(maxSum-n+1+1),maxSum,lo=1,key=calc)-1
链接: 2040. 两个有序数组的第 K 小乘积
这题写了一天,它值得一篇题解:[LeetCode解题报告] 2040. 两个有序数组的第 K 小乘积
class Solution:
def kthSmallestProduct(self, nums1: List[int], nums2: List[int], k: int) -> int:
m,n = len(nums1), len(nums2)
pos1,neg1,zero1 = [x for x in nums1 if x>0],[x for x in nums1 if x < 0],[x for x in nums1 if x == 0]
pos2,neg2,zero2 = [x for x in nums2 if x>0],[x for x in nums2 if x < 0],[x for x in nums2 if x == 0]
m1,m2,m3 = len(pos1),len(neg1),len(zero1) # 数组1中,正数的个数,负数的个数,0的个数
n1,n2,n3 = len(pos2),len(neg2),len(zero2)
tot_neg = m1*n2+m2*n1 # 总共的负数积数量
tot_pos = m1*n1+m2*n2 # 总共的正数积数量
tot_zero = m3*(n1+n2)+n3*(m1+m2) + m3*n3 # 总共的0数量
min1,min2 = min(nums1),min(nums2)
max1,max2 = max(nums1),max(nums2)
def calc(x):
# 计算乘积小于等于x的数对有多少个。
if x == 0: # 显然就是0的数量+负数的数量
return tot_neg+tot_zero
if x > 0: # 0和负数都先算上,然后计算有多少个正数小于等于x:用两边正数结合,负数结合
ret = tot_neg+tot_zero
j = n1-1
for i in pos1:
while j >= 0 and i * pos2[j] > x:
j -= 1
ret += j+1
j = 0
for i in neg1[::-1]:
while j<n2 and i * neg2[j] > x:
j += 1
ret += n2-j
return ret
if x < 0: # 用两边正结合负
ret = 0
j = 0
for i in neg1:
while j < n1 and i * pos2[j] > x:
j += 1
ret += n1-j
j = 0
for i in neg2:
while j < m1 and i * pos1[j] > x:
j += 1
ret += m1-j
return ret
bound = [a*b for a,b in product([min1,max1],[min2,max2])]
t = range(min(bound),max(bound)+1)
pos = bisect_left(t,k,key=calc)
return t[pos]