IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 牛客面试必刷101——哈希 -> 正文阅读

[数据结构与算法]牛客面试必刷101——哈希

两数之和 BM50

原题

给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。

(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)

数据范围: 2 ≤ l e n ( n u m b e r s ) ≤ 1 0 5 , ? 10 ≤ n u m b e r s i ≤ 1 0 9 , 0 ≤ t a r g e t ≤ 1 0 9 2\leq len(numbers) \leq 10^5,-10 \leq numbers_i \leq 10^9,0 \leq target \leq 10^9 2len(numbers)105?10numbersi?1090target109

要求:空间复杂度 O ( n ) O(n) O(n),时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

思路:

使用哈希表来降低时间复杂度,遍历数组,如果没有 当前值, 就将(target - 当前值)存入哈希表,如果有,返回数字下标即可。

class Solution:
    def twoSum(self , numbers: List[int], target: int) -> List[int]:
        # write code here
        d = {}
        for k in range(len(numbers)):
            if numbers[k] not in d:
                d[target - numbers[k]] = k+1
            else:
                return [d[numbers[k]],k+1]
数组中出现次数超过一半的数字 BM51

原题

描述

给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

数据范围: n ≤ 50 n \le 50 n50,数组中元素的值 0 ≤ v a l ≤ 100000 0 \le val \le 100000 0val100000

要求:空间复杂度: O ( 1 ) O(1) O(1),时间复杂度 O ( n ) O(n) O(n)

输入描述:

保证数组输入非空,且保证有解

思路1

使用哈希表存储每个元素出现的次数,如果超过一半,直接返回该元素.

时间复杂度:O(n),空间复杂度:O(n)

class Solution:
    def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
        # write code here
        d = {}
        for k in numbers:
            if k not in d:
                d[k] = 1
            else:
                d[k] += 1
            if d[k] > len(numbers)//2:
                return k

思路2:投票法

出现次数超过一半,那该数字一定是众数,对数组中的数字进行相消,即如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众数。

时间复杂度:O(n),空间复杂度:O(1)

  • a表示众数出现的次数,res存储众数。
  • 如果a=0,说明前面的数字抵消了,因此假设当前的数字为众数, r e s = k res=k res=k
  • 如果当前数字和res相等,则令a加1;否则令a减一,表示抵消
class Solution:
    def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
        # write code here
        a = 0
        for k in numbers:
            if a == 0:
                res = k
            if res == k:
                a += 1
            else:
                a -= 1
        return res
数组中只出现一次的两个数字 BM52

原题

一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

数据范围:数组长度 2 ≤ n ≤ 1000 2\le n \le 1000 2n1000,数组中每个数的大小 0 < v a l ≤ 1000000 0 < val \le 1000000 0<val1000000
要求:空间复杂度 O ( 1 ) O(1) O(1),时间复杂度 O ( n ) O(n) O(n)。提示:输出时按非降序排列。

思路1

哈希表存储每个数字出现的次数;遍历哈希表,找到只出现一次的数字

class Solution:
    def FindNumsAppearOnce(self , array: List[int]) -> List[int]:
        # write code here
        dic = {}
        lst = []
        for i in array:
            if i not in dic:
                dic[i] = 1
            else:
                dic[i] += 1
        for k in dic:
            if dic[k] < 2:
                lst.append(k)
        return sorted(lst)

思路2

异或,数组中只出现一次的数字,对数组所有元素进行异或运算,即可得到只出现一次的数字。因此解决两个只出现一次的数字,只需要将数组分为两组,两个只出现一次的数字分别分布在两组中,对两组分别进行异或运算,即可得到结果。

难点在于,如何进行分组,可以使两个元素刚好分布在两个不同的分组里。

假设要找到的两个元素为a、b,首先计算所有元素的异或,假设异或结果存储在xor中。若xor的第i位等于1,说明a和b的第i位一个是1一个是0。因此可以找到xor中的最低位1,根据最低位为0或1将原始数组分为两组即可。

  1. 首先计算所有元素的异或结果,xor
  2. 计算xor的最低位1,即令 l o w = 1 low=1 low=1,如果low&上xor等于0,说明第一位不是1,则low左移,直到low&上xor等于1,找到xor的最低位1。为了便于后续理解,假设我们找到的最低位为low_bit
  3. 元素分组,如果当前元素与上low等于0,说明该元素的第low_bit位为0;否则该元素的第low_bit位为1。这样数组元素就分为了两组,分别用a和b存储两组元素的异或结果,最终a和b即为要求的两个只出现一次的元素
class Solution:
    def FindNumsAppearOnce(self , array: List[int]) -> List[int]:
        # write code here
        xor = 0
        for k in array:
            xor ^= k
        low = 1
        while not low & xor:
            low <<= 1
        a ,b = 0,0
        for k in array:
            if low & k == 0:
                a ^= k
            else:
                b ^= k
        if a > b:
            a,b = b,a
        return [a,b]
缺失的第一个正整数 BM53

原题

给定一个未排序的整数数组nums,请你找出其中没有出现的最小的正整数 。进阶: 空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

数据范围:

? 2 31 < = n u m s [ i ] < = 2 31 ? 1 -2^{31}<=nums[i]<=2^{31}-1 ?231<=nums[i]<=231?1

0 < = l e n ( n u m s ) < = 5 ? 1 0 5 0<=len(nums)<=5*10^5 0<=len(nums)<=5?105

思路1

使用哈希表记录nums中每个元素出现的位置,定义一个num初始化为1,当num出现在nums中,则num加1,直到nums中不存在num,直接返回num。使用哈希表存储nums中的元素,便于后续进行O(1)的查找。

class Solution:
    def minNumberDisappeared(self , nums: List[int]) -> int:
        # write code here
        d = {}
        for i in range(len(nums)):
            d[nums[i]] = i
        num = 1
        while True:
            if num in d:
                num += 1
            else:
                return num

思路2

原地哈希,一共有n个元素,则定义一个长度为n的数组,记录1-n范围内数字的出现情况。该题最终返回的要么是1-n之间的数字,要么是n+1

三数之和 BM54

原题

给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。

数据范围:$0 \le n \le $,数组中各个元素值满足 ∣ v a l ∣ ≤ 100 |val | \le 100 val100。空间复杂度:O(n^2)O(n2),时间复杂度 O(n^2)O(n2)

注意:

  1. 三元组(a、b、c)中的元素可以按任意顺序排列。
  2. 解集中不能包含重复的三元组。

思路

使用一个哈希表记录num中每个元素出现的位置,为了后面进行O(1)的查找

步骤:双重循环遍历num,i从0—(n-1),j从(i+1)—(n-1),计算num[i]+num[j],查找哈希表中是否存在-(num[i]+num[j]),如果存在,且该元素与num[i]和num[j]不冲突,则证明这是一个有效的三元组。

注意事项:为了避免获取到重复的结果,需要进行去重,因此先对num数组进行排序,则num[i]一定小于num[j],保证每个三元组都是有序的,因而可以直接判断当前三元组是否已经在结果集中,如果在,过滤。

class Solution:
    def threeSum(self , num: List[int]) -> List[List[int]]:
        res = []     
        d = {}
        num = sorted(num)
        for k in range(len(num)):
            d[num[k]] = k
        for i in range(len(num)):
            for j in range(i+1,len(num)):
                t = -(num[i] + num[j])
                if t in d and d[t] != i and d[t] != j:
                    if t < num[i]:
                        r = [t,num[i],num[j]]
                    elif t > num[j]:
                        r= [num[i],num[j],t]
                    else:
                        r = [num[i],t,num[j]]
                    if r not in res:
                        res.append(r)
        return res

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-06-01 15:26:10  更:2022-06-01 15:26:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 14:50:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码