zoukankan      html  css  js  c++  java
  • 《极客时间--算法面试》-哈希表

    哈希表

       有效的字母异位词

      两数相和

      三数相和

      四数相和

    力扣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                                                              #最终返回结果值
                    
  • 相关阅读:
    使用国内镜像安装pyqt5
    python线程池 ThreadPoolExecutor 的用法及实战
    进程和线程、协程的区别
    python线程池实现
    python 多进程使用总结
    参与开源项目
    脑图——前端技术
    HTML中DTD使用小结
    浅谈面向对象——追溯法
    Dva.js 里面的几个概念
  • 原文地址:https://www.cnblogs.com/missidiot/p/10954089.html
Copyright © 2011-2022 走看看