一、两数之和(LeetCode1)
二分思路求解i,j
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# nums.sort()
an=[]
length=len(nums)
for n in range(length):
an.append([nums[n],n])
an.sort()
i,j=0,length-1
while(i<j):
if(an[i][0]+an[j][0]<target):
i+=1
elif(an[i][0]+an[j][0]>target):
j-=1
else:
return [an[i][1],an[j][1]]
return []
二、三数之和(LeetCode 15)
记得将nums排序再进行a,b,c判断。固定a,使用二分定位b,c。
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
n=len(nums)
res=[]
nums.sort()
for i in range(n):
if(nums[i]>0):
return res
if(i>0 and nums[i]==nums[i-1]):
continue
L,R=i+1,n-1
while(L<R):
if(nums[L]+nums[R]+nums[i]==0):
res.append([nums[i],nums[L],nums[R]])
#去重
while(L<R and nums[L]==nums[L+1]):
L+=1
while(L<R and nums[R]==nums[R-1]):
R-=1
L+=1
R-=1
elif(nums[L]+nums[R]+nums[i]>0):
R-=1
else:
L+=1
return res
三、和为K的子数组(LeetCode 560)
依图二面编程题
保存前缀和->差分法
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
cnt, n = 0, len(nums)
pre = [0] * (n + 1)
for i in range(1, n + 1):
pre[i] = pre[i - 1] + nums[i - 1]
for i in range(1, n + 1):
for j in range(i, n + 1):
if (pre[j] - pre[i - 1] == k): cnt += 1
return cnt
使用hashmap简化时间复杂度.
使用collections记录已经存在的和的数量。当前总和-k=字典里某个值。那么以当前节点为结尾结点,记录以当前结点作为尾结点的结点数量。
以下代码抄袭leetcode熊猫大神
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
# num_times 存储某“前缀和”出现的次数,这里用collections.defaultdict来定义它
# 如果某前缀不在此字典中,那么它对应的次数为0
num_times = collections.defaultdict(int)
num_times[0] = 1 # 先给定一个初始值,代表前缀和为0的出现了一次
cur_sum = 0 # 记录到当前位置的前缀和
res = 0
for i in range(len(nums)):
cur_sum += nums[i] # 计算当前前缀和
if cur_sum - k in num_times: # 如果前缀和减去目标值k所得到的值在字典中出现,即当前位置前缀和减去之前某一位的前缀和等于目标值
res += num_times[cur_sum - k]
# 下面一句实际上对应两种情况,一种是某cur_sum之前出现过(直接在原来出现的次数上+1即可),
# 另一种是某cur_sum没出现过(理论上应该设为1,但是因为此处用defaultdict存储,如果cur_sum这个key不存在将返回默认的int,也就是0)
# 返回0加上1和直接将其置为1是一样的效果。所以这里统一用一句话包含上述两种情况
num_times[cur_sum] += 1
return res
根据熊猫描述,1248题和本题有异曲同工之妙。
统计优美子数组(LeetCode 1248)
class Solution:
def numberOfSubarrays(self, nums, k):
from collections import defaultdict
odd_nums = defaultdict(int) # 前缀和类问题重要是设定一个可供查找的表,想清楚存什么后面就好理解了
odd_nums[0] = 1 # 给定一个初始状态,代表0个奇数的情况出现了1次
cur_odd_num = 0 # 到当前位置有几个奇数
res = 0
for i in range(len(nums)):
if nums[i] % 2 == 1:
cur_odd_num += 1
odd_nums[cur_odd_num] += 1
if cur_odd_num - k in odd_nums:
res += odd_nums[cur_odd_num - k]
return res