《极客时间--算法面试》-哈希表

哈希表

   有效的字母异位词

  两数相和

  三数相和

  四数相和

力扣242:有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

说明:

思路:

  一、排序

    将两个词都排序,快排是nlogn,最终看两者是否相同。

  二、map进行计数

    对两个词分别map计数,最终比较两个字典是否相同

代码:

class Solution(object):
    def isAnagram(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: bool
        """
        '''
        #方案一:采用排序的方式
        return sorted(s) == sorted(t)                       #nlogn时间复杂度
        '''
        dict1, dict2 = {}, {}                               #两个字典存放两个字符串的键值对
        for item in s:
            dict1[item] = dict1.get(item,0)+1               #get方法是查找指定键的值,如果不存在返回默认值,最开始即为0,计数+1
        for item in t:
            dict2[item] = dict2.get(item,0)+1
        return dict1 == dict2                               #最终比较两个字典是否相同

两数相和

  https://leetcode-cn.com/problems/two-sum/

思路:

  一、暴力破解,采用两重循环,至少可以解决问题,时间复杂度为N的平方。

  二、转换问题,y=target-x,遍历x然后在哈希表中查找是否有有,遍历为N,查找为1,总共的时间复杂度为N

代码:

class Solution(object):
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        dic = {}                            #存放遍历元素之前的键值对
        for i in range(len(nums)):          #遍历全部元素
            y = target - nums[i]            #转换思路
            if y in dic:                    
                return [dic[y],i]           #返回下标
            dic[nums[i]] = i                #将当前元素之前的元素加入到字典中

三数求和

力扣:https://leetcode-cn.com/problems/3sum/submissions/

思路:

  一、暴力破解,将会是立方级别的时间复杂度。

  二、在此基础上,c = target -a -b,采用查询,这样就是平方级别的时间复杂度。

  三、排序的基础上夹逼,会改变原始数据,时间复杂度较低(推荐)

    首先对原数组进行排序,开始从头遍历第一个元素,第二和三值采用双指针,前后夹逼遍历。期间需要处理,如果中间值重复的话需要继续,减少计算量。

代码:

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        nums.sort()                                                     #首先进行排序
        n = len(nums)
        res = []                                                        #存放中间结果值
        for i in range(n):                                              #遍历全部的数据
            if i>0 and nums[i]==nums[i-1]:                              #如果这两个数重复,就继续向后遍历
                continue
            left = i+1                                                  #left是子数组的左指针,从i+1开始
            right = n-1                                                 #right是子数组的右指针,从n-1开始
            while left < right:                                         #大循环,查找子数组中的值
                cur_sum = nums[i]+nums[left]+nums[right]                #如果三者值等于目标值
                if cur_sum == 0:                                        #此时的目标值为0
                    temp = [nums[i],nums[left],nums[right]]             
                    res.append(temp)                                    #将其结果保存
                    while left<right and nums[left]==nums[left+1]:      #值重复,向后夹逼
                        left += 1
                    while left<right and nums[right]==nums[right-1]:    #值重复,向前夹逼
                        right -= 1
                    left += 1                                           #向后夹逼
                    right -= 1                                          #向前夹逼
                elif cur_sum < 0:                                       #如果值三者和小于目标值,由于是已经排好序的
                    left += 1                                           #前值小于后值,那就寻找大的数
                else:                                                   #同理,如果大于目标值,向前查找
                    right -= 1
        return res                                                      #最终返回结果值

四数相和

https://leetcode-cn.com/problems/4sum/submissions/

思路:

  根据上面的三数相和思路,双指针双向夹逼。

  第一个数从1到倒数第四个值进行遍历

  第二个值从第一个值后面到倒数第三个值进行遍历

  第三和第四值采用双指针双向夹逼遍历。

  中间需要进行判断是否重复代码和是否去掉一些冗余的计算,比如前面的值都大于了目标值,那么后面的计算是没有意义的,直接跳过即可。

代码:

class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        n = len(nums)                                                           #获取数组的长度
        if n<4:     
            return []                                                           #如果数组个数小于4个,直接返回空
        nums.sort()                                                             #进行排序
        res = []                                                                #存放结果值
        for i in range(n-3):                                                    #第一个值从,头到倒数第四个截止,【0,n-4】
            if i>0 and nums[i]==nums[i-1]:                                      #如果值重复,就跳过继续执行
                continue
            if nums[i]+nums[i+1]+nums[i+2]+nums[i+3]>target:                    #如果前三个数都超过了目标值,则直接退出,由于是排序的,后面的值肯定大
                break
            if nums[i]+nums[n-1]+nums[n-2]+nums[n-3]<target:                    #如果后面的值小于目标值,则跳出下次循环
                continue
            for j in range(i+1,n-2):                                            #第二个值从[i+1,n-3]遍历
                if j-i>1 and nums[j]==nums[j-1]:                                #对第二个数进行判断是否重复
                    continue
                if nums[i]+nums[j]+nums[j+1]+nums[j+2]>target:                  #同理,如果钱的数都大于目标值,则直接退出
                    break
                if nums[i]+nums[j]+nums[n-1]+nums[n-2]<target:                  #同理,如果后面的值小于了目标值,则跳出直接下个循环
                    continue
                left = j+1                                                      #双指针,第三个数,向后夹逼遍历
                right = n-1                                                     #第四个数,向前夹逼遍历
                while left<right:                                                           
                    temp = nums[i]+nums[j]+nums[left]+nums[right]               #四数相和
                    if temp == target:                                          #如果等于目标值
                        res.append([nums[i],nums[j],nums[left],nums[right]])    #将其加入到结果中
                        while left<right and nums[left]==nums[left+1]:          #同理,对第三个值判断重复
                            left += 1
                        while left<right and nums[right]==nums[right-1]:        #同理对第四个值判断重复
                            right -= 1
                        left += 1
                        right -= 1
                    elif temp<target:                                           #如果小于,则向后夹逼
                        left += 1
                    else:                                                       #同上,向前夹逼
                        right -= 1
        return res                                                              #最终返回结果值
                

 

posted @ 2019-06-19 11:08  weilongyitian  阅读(246)  评论(0编辑  收藏  举报