2019.08.05
3.无重复字符的最长字串
- 基本思想:
双指针
、哈希表
- 实现:
- 使用 head 指向无重复子串的头,ind 指向当前位置(即当前无重复子串的尾),len_max记录当前无重复字串的最长长度,使用字典的 key 存储串 s 的字符,value 存储字符在串中的位置。
- 当 k(当前字符)不在字典中时,表明 k 是当前无重复子串的尾元素,故当前无重复字符的子串长度为( ind - head + 1 ),与最大长度进行比较看是否更新,然后将此 k 放入字典中;
- 当 k 已经存在于字典中时,还需判断 字典中的这个 k 的 value(即在串中的位置)是否大于等于 head,(因为 head 是当前无重复子串的首位置)如果小于 head 则认为这个已经存在的 k 早已废弃(与当前无重复子串无关),与 k 不在字典中时的情况一致处理,k 的 value 大于等于 head 则认为遇到了重复元素,k 之前的无重复子串的长度为 ( ind - head ),与最大长度进行比较看是否需要更新,然后 head 跟新为 被重复了的元素 k~ 的下一个位置,这样从 k~ 的下一个位置到当前 k 的位置的子串又是另一个无重复子串,同时更新 k 的 value 值,最后返回依次遍历过程中的最大长度。
def lengthOfLongestSubstring(self, s: str) -> int:
head = 0
len_max = 0
_dict = {}
for ind, k in enumerate(s):
if k in _dict and _dict.get(k) >= head:
len_max = (ind - head) if (ind - head) > len_max else len_max
head = _dict.get(k) + 1
_dict[k] = ind
else:
len_max = (ind - head + 1) if (ind - head + 1) > len_max else len_max
_dict[k] = ind
return len_max
15.三数之和
- 基本思想:
双指针
、回溯
- 实现:
1. 找组合思路:固定三个数字中最左数字的指针 a,遍历数组找到每个 a 对应的所有满足nums[a] + nums[b] + nums[c] == 0 的 b,c 组合:
2. 当 nums[a] > 0 时直接跳出,因为 c > b > a,即三个数字都大于 0,在此k之后不可能找到组合了
3. 当 a > 0 且 nums[a] == nums[a - 1] 时跳过此数字,因为 nums[a - 1] 的所有组合已经被加入到结果中,本次搜索只会搜索到重复组合。
4. b,c 分设在数组 [a+1, len(nums)-1] 两端,根据 sum 与 0 的大小关系交替向中间逼近,如果遇到等于 0 的组合则加入 arr 中,需要注意:移动 i,j 需要跳过所有重复值,以避免重复答案被计入 arr。
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
arr = []
for a in range(len(nums)-2):
if nums[a] > 0:break
# 剪枝操作
if a > 0 and nums[a] == nums[a-1]:continue
b = a + 1
c = len(nums) - 1
while b < c:
if nums[a] + nums[b] + nums[c] == 0:
arr.append([nums[a], nums[b], nums[c]])
b += 1
c -= 1
while b < c and nums[b] == nums[b-1]:
b += 1
while b < c and nums[c] == nums[c+1]:
c -= 1
elif nums[a] + nums[b] + nums[c] > 0:
c -= 1
while b < c and nums[c] == nums[c+1]:
c -= 1
else:
b += 1
while b < c and nums[b] == nums[b-1]:
b += 1
return arr
2019.08.06
18.四数之和
- 基本思想:
双指针
、回溯
- 实现:可以在三数之和的基础上做,或者找出所有符合条件的四数,再去重。
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
nums.sort()
ans=set() #去重
for i in range(len(nums)-3): #固定第一个数
if i > 0 and nums[i] == nums[i-1]:continue # 剪枝
for j in range(i+1,len(nums)-2): #固定第二个数
if j > i+1 and nums[j] == nums[j-1]:continue # 剪枝
left=j+1 #左指针
right=len(nums)-1 #右指针
while(right>left):
temp=nums[i]+nums[j]+nums[left]+nums[right]
if temp==target:
ans.add((nums[i],nums[j],nums[left],nums[right]))
left+=1
right-=1
if temp>target:right-=1 #太大了,右指针左移
if temp<target:left+=1 #反之
res=[] #修改返回格式
for i in ans:
res.append(list(i))
return res
2019.08.09
16.最接近的三数之和
- 基本思想:
双指针
、回溯
- 实现:在三数之和的基础上设置最小差值,每次出现新的组合时更新最小差值,并保留最小差值时的三数之和。
def threeSumClosest(self, nums: List[int], target: int) -> int:
nums.sort()
min_t = sys.maxsize
for i in range(len(nums) - 2):
#剪枝操作
if i > 0 and nums[i] == nums[i-1]:continue
left = i + 1
right = len(nums) - 1
while(left < right):
sum_t = nums[i] + nums[right] + nums[left]
if abs(sum_t - target) < min_t:
min_t = abs(sum_t - target)
res = sum_t
if sum_t > target:
right -= 1
elif sum_t < target:
left += 1
else:
return sum_t
return res