2022-01-07 每日打卡:难题精刷
写在前面
“这些事儿在熟练之后,也许就像喝口水一样平淡,但却能给初学者带来巨大的快乐,我一直觉得,能否始终保持如初学者般的热情、专注,决定了在做某件事时能走多远,能做多好。” 该系列文章由python编写,所刷题目共三个来源:之前没做出来的 ;Leetcode中等,困难难度题目; 周赛题目;某个专题的经典题目,所有代码已AC。每日1-3道,随缘剖析,希望风雨无阻,作为勉励自己坚持刷题的记录。
2122. 还原原数组

这个题分析一下可以知道,让我们寻找间隔相同的两个数组。但是间隔是无法通过数学方法计算出来的,使用枚举。枚举的开始是最小的元素or最大的元素,一定是属于较小or较大数组的。
在遍历过程中注意一点,需要在含有相同元素的数字的列表中标记,无法使用搜索,而只能使用遍历。另外,像是while(i<n){i++}这样的循环体,考察边界,如果满足条件还是会加一的。
class Solution:
def recoverArray(self, nums: List[int]) -> List[int]:
nums.sort()
n, lenth, ans =len(nums), len(nums)//2, []
for _ in range(1,len(nums)):
# 枚举每个k的可能性
k = (nums[_]-nums[0])
if k ==0 or k%2!=0:
continue
l, used, ans, k = 0, [False for _ in range(n)],[], k//2
for r in range(1,n):
while r<n-1 and (used[r] or nums[r]!=nums[l]+2*k):
r+=1
used[l] = used[r] = True
ans.append(nums[l]+k)
if r == n-1:
break
while l<n-1 and used[l]:
l += 1
r = l
if len(ans) == lenth:
return ans
2121. 相同元素的间隔之和

很类似之前做的接水问题,我们把需要重复计算的部分提取出来,而不是通过循环计算。比如上题3的位置,对于第一个3而言,其下标为2,则遍历第二个3时,加入5-2=3,遍历到第三个3时,加入3+6-5=4即可,而此时也同时加入第二个3的位置为6-5。
对于每个有重复数字的位置而言,其最终结果=左侧数字的贡献+右侧数字的贡献,通过两次遍历分别正向和逆向统计出结果即可。

这里的res是针对每个下标单独计算,而total和cnt可以重复利用,不断累加。
class Solution:
def getDistances(self, arr: List[int]) -> List[int]:
n = len(arr)
res = [0] * n
# 每个数值出现下标之和
total = defaultdict(int)
# 每个数值出现次数
cnt = defaultdict(int)
# 正向遍历并更新两个哈希表以及间隔之和数组
for i in range(n):
val = arr[i]
if val in cnt:
res[i] += i * cnt[val] - total[val]
total[val] += i
cnt[val] += 1
# 清空哈希表
total.clear()
cnt.clear()
# 反向遍历并更新两个哈希表以及间隔之和数组
for i in range(n - 1, -1, -1):
val = arr[i]
if val in cnt:
res[i] += total[val] - i * cnt[val]
total[val] += i
cnt[val] += 1
return res










