基于力扣,分析哈希表的应用

哈希表用于较快地找到元素(即是否存在这个元素),

进一步地,可以判断是否是重复元素

目录

两数之和

无重复字符的最长子串 

三数之和

最接近的三数之和


两数之和

我们先来看一道题目两数之和,利用哈希表,可以显著地把O(n^{2})的时间复杂度降低到O(n)

题目的要求是找到列表中的和为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

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值