哈希表用于较快地找到元素(即是否存在这个元素),
进一步地,可以判断是否是重复元素
目录
两数之和
我们先来看一道题目两数之和,利用哈希表,可以显著地把的时间复杂度降低到
题目的要求是找到列表中的和为target的两个元素,并返回两个元素的索引
我们首先建立一个空的哈希表,为一个空的字典dict
循环遍历列表nums,每遍历一个元素,使用target-该元素,查看得到的值是否在列表nums中
如果在,则返回nums列表中的索引,和在哈希字典中键所对应的值
如果不在,则在哈希字典中保存下该元素和元素所对应的索引。代码如下:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hashTable = dict()
for (i, num) in enumerate(nums):
if (target-num) in hashTable:
return [hashTable[target-num], i]
hashTable[num] = i;
return [];
无重复字符的最长子串
我们来看下一道题目无重复字符的最长子串,
这里对哈希表的实现使用集合set
这道题目的要求是找到子串,要求这个子串没有重复字符,并且要求是最长的
那么一种想法是:
遍历给的字符串(其实是遍历要寻找子串的首字母),
采用哈希表set记录下要寻找子串中存在的字符
如果出现重复,则进入下一次循环(首字母往后推一位)
如果没有出现重复,则记录下子串的长度,如果大于最大长度,则更新最大长度
注意:遍历过的子串的尾部不需要从首字母开始计入子串(因为不重复子串的子串一定是不重复的),所以采用一个tail,它只需遍历一遍字符串就可以了
在首字母往后推一位时,需要在哈希表中移去前一个字母
遍历结束,则返回子串的最大长度。
时间复杂度为O(n)
代码如下:
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
n = len(s)
hashSet = set()
tail = 0
lenth = 0
for i in range(n):
if(i != 0):
hashSet.remove(s[i-1])
while(tail < n) and s[tail] not in hashSet:
hashSet.add(s[tail])
tail += 1
lenth = max(lenth, tail-i)
return lenth
三数之和
下面再考虑一个数字之和的问题三数之和
将采用双指针的方法解决。
题目给出一个数字列表,找出3个数字的和等于0
题目中要求返回三元列表组成的列表。
题目的关键在于要对列表进行排序,才能够使用双指针解决这个问题。
注意题目要求不可包含重复的三元列表:
那么首先要求首数字不可以重复,那么在发现相同数字时,需要跳过(不作处理),进入下一次循环
然后再使用双指针选择另外两个数字时,也要注意不可以选择重复的数字。(如果发现三数之和等于0了,一侧扫描到相同的数字,跳过,直到不是相同的数字)
如何使用双指针:
如果发现三数之和<0,则左侧指针+1
如果发现三数之和>0,则右侧指针-1
如果找到符合条件的三元列表,则存储在列表中。
代码如下:
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []
n = len(nums)
if(n < 3):
return []
nums.sort()
for i in range(n):
if(nums[i] > 0): return res
if(i > 0 and nums[i] == nums[i-1]):
continue
l = i+1
r = n-1
while(l < r):
if(nums[i] + nums[l] +nums[r] == 0):
res.append([nums[i], nums[l], nums[r]])
while(l+1 < n and nums[l] == nums[l+1]):
l = l+1
while(r-1 > l and nums[r] == nums[r-1]):
r = r-1
l = l+1
r = r-1
elif(nums[i] + nums[l] +nums[r] < 0):
l = l+1
else:
r = r-1
return res
最接近的三数之和
下面考虑一道 相近的三数之和题目最接近的三数之和
题目给出数字列表,并且给出一个target,要求找出三个数的和最接近这个target
并返回最接近的三个数的和。
可以同样采用双指针的方法来考虑这道题目。
首先需要将数字列表进行排序,
此处便不需要考虑重复元素的问题,因为返回的是三个数的和,
遍历数字列表,获得第一个数字
采用双指针的方法获得第二个和第三个数字,
如果>target,右指针移一位
如果<target,左指针移一位
对于选定的三个数字,计算他们的和,如果比最大的差距小,则记录下这个和,
如果发现差距为0,则可以跳出循环,返回target
代码如下:
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
n = len(nums)
nums.sort()
bestDiff = abs(nums[0] + nums[1] + nums[2] - target)
bestSum = 0
flag = 0
for i in range(n):
l = i + 1
r = n - 1
while(l < r):
sum = nums[i] + nums[l] + nums[r]
if(sum == target):
bestSum = sum
flag = 1
break
if(abs(sum - target) <= bestDiff):
bestDiff = abs(sum - target)
bestSum = sum
if(sum < target):
l = l + 1
if(sum > target):
r = r - 1
if(flag == 1):
break
return bestSum