LeetCode编程集训第1次

一、哈希表思想

哈希表:是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为Hash表,函数f(key)为Hash函数。

分配地址方法:

1,直接定址法:

函数公式:f(key)=a*key+b (a,b为常数)

这种方法的优点是:简单,均匀,不会产生冲突。但是需要事先知道关键字的分布情况,适合查找表较小并且连续的情况。

 

2,数字分析法:

比如我们的11位手机号码“136XXXX7887”,其中前三位是接入号,一般对应不同运营公司的子品牌,如130是联通如意通,136是移动神州行,153是电信等。中间四们是HLR识别号,表示用户归属地。最后四们才是真正的用户号。

若我们现在要存储某家公司员工登记表,如果用手机号码作为关键字,那么极有可能前7位都是相同的,所以我们选择后面的四们作为哈希地址就是不错的选择。


3,平方取中法:

故名思义,比如关键字是1234,那么它的平方就是1522756,再抽取中间的3位就是227作为哈希地址。


4,折叠法:

折叠法是将关键字从左到右分割成位数相等的几个部分(最后一部分位数不够可以短些),然后将这几部分叠加求和,并按哈希表表长,取后几位作为哈希地址。

比如我们的关键字是9876543210,哈希表表长三位,我们将它分为四组,987|654|321|0 ,然后将它们叠加求和987+654+321+0=1962,再求后3位即得到哈希地址为962,哈哈,是不是很有意思。


5,除留余数法:

函数公式:f(key)=key mod p (p<=m)m为哈希表表长。

这种方法是最常用的哈希函数构造方法。


6,随机数法:

函数公式:f(key)= random(key)。

这里random是随机函数,当关键字的长度不等是,采用这种方法比较合适。

二、例题

1、两数之和(1)

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

分析:为了对运行时间复杂度进行优化,我们需要一种更有效的方法来检查数组中是否存在目标元素。如果存在,我们需要找出它的索引。保持数组中的每个元素与其索引相互对应的最好方法就是哈希表。

通过以空间换取速度的方式,我们可以将查找时间从 O(n)O(n)O(n) 降低到 O(1)O(1)O(1)。哈希表正是为此目的而构建的,它支持以 近似 恒定的时间进行快速查找。我用“近似”来描述,是因为一旦出现冲突,查找用时可能会退化到 O(n)O(n)O(n)。但只要你仔细地挑选哈希函数,在哈希表中进行查找的用时应当被摊销为 O(1)O(1)O(1)。

一个简单的实现使用了两次迭代。在第一次迭代中,我们将每个元素的值和它的索引添加到表中。然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(target−nums[i]target - nums[i]target−nums[i])是否存在于表中。注意,该目标元素不能是 nums[i]nums[i]nums[i] 本身!

代码:

class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        if not nums:
            return None
            
        d = {}   
        for i, item in enumerate(nums):
            tmp  = target - item      #循环取nums里面的值与target作差
            
            for key, value in d.items():#寻找差值是否存在hash表里
                if value == tmp:
                    return [key, i] #如果存在,返回对应的key和i
            
            d[i] = item   #把nums里的值添加进hash表中
            
        return None 

运行结果: 

 

 

 

 

 

2、快乐数(202)

编写一个算法来判断一个数是不是“快乐数”。

一个“快乐数”定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1。如果可以变为 1,那么这个数就是快乐数。

示例: 

输入: 19
输出: true
解释: 
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

分析1:不是快乐数的数称为不快乐数(unhappy number),所有不快乐数的数位平方和计算,最後都会进入 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 的循环中,快乐数最终sum都会为1

方法一代码:

class Solution:
    def __init__(self):
        self.hash_dict={}
    
    def isHappy(self, n):
        """
        :type n: int
        :rtype: bool
        """
        sums = sum(map(lambda x:x**2, map(int, str(n)))) #逐位平方相加
        if sums == 1:
            return True
        if sums in self.hash_dict:
            return False
        else:
            self.hash_dict[sums]=0
        return self.isHappy(sums)  #循环

运行结果: 

分析2:如果n是快乐数它将不会进入循环,进入循环的就不是快乐数

方法二代码:

class Solution:
    def __init__(self):
        self.hash_dict={}
    
    def isHappy(self, n):
        """
        :type n: int
        :rtype: bool
        """
        sums = sum(map(lambda x:x**2, map(int, str(n)))) #逐位平方相加
        if sums == 1:
            return True
        if sums in self.hash_dict:
            return False
        else:
            self.hash_dict[sums]=0 #添加sums
        return self.isHappy(sums)  #循环
           

运行结果:
      

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值