牛客经典101题题解集--哈希

目录

哈希

两数之和

题目

分析

代码

java

python

数组中出现次数超过一半的数字

题目

代码

java

python

数组中只出现一次的两个数字

题目

分析

代码

java

python

缺失的第一个正整数

题目

分析

代码

java

python

三数之和

题目

分析

代码

java

python


哈希

两数之和

题目

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

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

数据范围:2≤𝑙𝑒𝑛(𝑛𝑢𝑚𝑏𝑒𝑟𝑠)≤105,−10≤𝑛𝑢𝑚𝑏𝑒𝑟𝑠𝑖≤109,0≤𝑡𝑎𝑟𝑔𝑒𝑡≤109

要求:空间复杂度 𝑂(𝑛),时间复杂度 𝑂(𝑛𝑙𝑜𝑔𝑛)

示例1

输入:[3,2,4],6

返回值:[2,3]

说明:因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以返回[2,3]

示例2

输入:[20,70,110,150],90

返回值:[1,2]

说明:20+70=90

分析

记住哈希表可以快速查找某个元素是否存在。

代码

java
java 复制代码
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型一维数组 
     * @param target int整型 
     * @return int整型一维数组
     */
    public int[] twoSum (int[] numbers, int target) {
        // write code here
        Map<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<numbers.length;i++){
            int x=numbers[i];
            if(map.containsKey(target-x)){
                return new int[]{map.get(target-x)+1,i+1};
            }
            map.put(x,i);
        }
            
        return new int[0];  
        
        }
    }
python
python 复制代码
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param numbers int整型一维数组 
# @param target int整型 
# @return int整型一维数组
#
class Solution:
    def twoSum(self , numbers: List[int], target: int) -> List[int]:
        # write code here
        index={}
        for j,x in enumerate(numbers):
            if target-x in index:
                return [index[target-x]+1,j+1]
            index[x]=j

数组中出现次数超过一半的数字

题目

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

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

数据范围:𝑛≤50000,数组中元素的值 0≤𝑣𝑎𝑙≤10000

要求:空间复杂度:𝑂(1),时间复杂度 𝑂(𝑛)

输入描述:

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

示例1

输入:[1,2,3,2,2,2,5,4,2]

返回值:2

示例2

输入:[3,3,3,3,2,2,2]

返回值:3

示例3

输入:[1]

返回值:1

代码

java
java 复制代码
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param numbers int整型一维数组 
     * @return int整型
     */
    public int MoreThanHalfNum_Solution (int[] numbers) {
        // write code here
        Map<Integer,Integer> map=new HashMap<>();
        for(int i:numbers){
            if(map.containsKey(i)){
                map.replace(i,map.get(i)+1);
            }else{
                map.put(i,1);
            }
        }
        for(int i:map.keySet()){
            if(map.get(i)>numbers.length/2){
                return i;
            }
        }
        return -1;
    }
}
python
python 复制代码
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param numbers int整型一维数组 
# @return int整型
#
class Solution:
    def MoreThanHalfNum_Solution(self , numbers: List[int]) -> int:
        # write code here
        index={}
        for num in numbers:
            if num in index:
                index[num]+=1
            else:
                index[num]=1
        for key in index:
            if index[key]>len(numbers)/2:
                return key
        return -1

                

数组中只出现一次的两个数字

题目

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

数据范围:数组长度 2≤𝑛≤1000,数组中每个数的大小 0<𝑣𝑎𝑙≤1000000

要求:空间复杂度 𝑂(1),时间复杂度 𝑂(𝑛)

提示:输出时按非降序排列。

示例1

输入:[1,4,1,6]

返回值:[4,6]

说明:返回的结果中较小的数排在前面

示例2

输入:[1,2,3,3,2,9]

返回值:[1,9]

分析

首先要知道 a^b^a=a^a^b=b,如果数组中除了某一个数字,其他数字都出现了两次,找出该数字。思路就是遍历数组,对每一个数字都求异或,最后得到的值就是要找的数字。

本题是要找两个数字a和b,那我们把该数组分成两个数组,其中a和一部分出现两次的数字在一块儿,b和另一部分出现两次的数字在一块儿,然后再分别对这两个数组求异或,就可以找到这两个数字了。

怎么把a和b区分开来?

可以利用二进制来区分。先对整个数组求异或得到c,根据上面的知识,可以知道c其实就是a^b=c。那么对于c,假如c二进制的第一位是1,其实就代表a二进制的第一位是1(或0),b二进制的第一位是0(或1),总而言之如果第一位的c等于1,那么a和b在第一位肯定不相等。

所以我们就可以想到利用二进制的第一位(有可能是第二位,第三位 。。。因为上面是假设的c第一位是1)为1来区分两个数组,第一位为1的是数组一,第一位为0的是数组二。这样就相当于把a和b给区分开来了。

代码

java
java 复制代码
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型一维数组
     */
    public int[] FindNumsAppearOnce (int[] nums) {
        // write code here
        if(nums==null || nums.length==0){
            return new int[0];
        }
        int res=0;
        for(int x:nums){
            res=res^x;
        }
         // 第二步:找到第一个为 1 的二进制位 index
        int index = 0;
        while ((res & 1) == 0) {
            res = res >> 1;
            index++;
        }
        // 第三步:分组异或
        int a = 0, b = 0;
        for (int num : nums) {
            if (helper(num, index)) {
                a ^= num;
            } else {
                b ^= num;
            }
        }
        return a < b ? new int[]{a, b} : new int[]{b, a};
    }
    // 辅助函数:判断数字 num 第 index 位是否为 1
    private boolean helper(int num, int index) {
        num = num >> index;
        return (num & 1) != 0;
    }
}
python
python 复制代码
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param nums int整型一维数组 
# @return int整型一维数组
#
class Solution:
    def FindNumsAppearOnce(self , nums: List[int]) -> List[int]:
        # write code here
        if not nums:
            return []
    
    # 第一步:整个数组异或,得到 a ^ b
        res = 0
        for x in nums:
            res ^= x
    
    # 第二步:找到第一个为 1 的二进制位 index
        index = 0
        while (res & 1) == 0:
            res = res >> 1
            index += 1
    
    # 第三步:根据第 index 位分组异或
        a, b = 0, 0
        for num in nums:
            if self.helper(num, index):
                a ^= num
            else:
                b ^= num
    
    # 按升序返回
        return [a, b] if a < b else [b, a]

# 辅助函数:判断数字 num 第 index 位是否为 1
    def helper(self,num, index):
        num = num >> index
        return (num & 1) != 0

缺失的第一个正整数

题目

给定一个无重复元素的整数数组nums,请你找出其中没有出现的最小的正整数

进阶: 空间复杂度 𝑂(1),时间复杂度 𝑂(𝑛)

数据范围:

−231≤𝑛𝑢𝑚𝑠[𝑖]≤231−1

0≤𝑙𝑒𝑛(𝑛𝑢𝑚𝑠)≤5∗105

示例1

输入:[1,0,2]

返回值:3

示例2

输入:[-2,3,4,1,5]

返回值:2

示例3

输入:[4,5,6,8,9]

返回值:1

分析

想象有一间教室,座位从左到右编号为 1 到 n。

有 n 个学生坐在教室的座位上,把 nums[i] 当作坐在第 i 个座位上的学生的学号。我们要做的事情,就是让学号在 1 到 n 中的学生,都坐到编号与自己学号相同的座位上(学号与座位编号匹配)。学号不在 [1,n] 中的学生可以忽略。

学生们交换座位后,从左往右看,第一个学号与座位编号不匹配的学生,其座位编号就是答案。

特别地,如果所有学生都坐在正确的座位上,那么答案是 n+1。
假设数组的下标是从 1 开始的。

假设 nums=[2,3,1]。

从 nums[1] 开始。这个座位上的学生,学号是 2,他应当坐在 nums[2] 上,所以他和 nums[2] 交换。交换后 nums=[3,2,1]。

仍然看 nums[1],这个座位上的学生,学号是 3,他应当坐在 nums[3] 上,所以他和 nums[3] 交换。交换后 nums=[1,2,3]。

仍然看 nums[1],这个座位上的学生,学号是 1,他坐在正确的座位上。

向后遍历,nums[2]=2,他坐在正确的座位上。

向后遍历,nums[3]=3,他坐在正确的座位上。

换座位过程结束。

再次遍历 nums,发现 nums[i]=i 都满足,说明数组中 1,2,3 都有,所以缺失的第一个正数是 4。

代码

java
java 复制代码
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param nums int整型一维数组 
     * @return int整型
     */
    public int minNumberDisappeared (int[] nums) {
        // write code here
        int n=nums.length;
        for(int i=0;i<nums.length;i++){
            while(1<=nums[i] && nums[i]<=n && nums[nums[i]-1]!=nums[i]){
                int j=nums[i]-1; // 减一是因为数组下标从 0 开始
                int tmp = nums[i];
                nums[i] = nums[j];
                nums[j] = tmp;
            }
        }
        for (int i = 0; i < n; i++) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }
        return n+1;
    }
}
python
python 复制代码
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param nums int整型一维数组 
# @return int整型
#
class Solution:
    def minNumberDisappeared(self , nums: List[int]) -> int:
        # write code here
        n=len(nums)
        for i in range(n):
            while nums[i]>=1 and nums[i]<=n and nums[nums[i]-1]!=nums[i]:
                j=nums[i]-1
                temp=nums[i]
                nums[i]=nums[j]
                nums[j]=temp
        for i in range(n):
            if nums[i]!=i+1:
                return i+1
        return n+1

三数之和

题目

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

数据范围:0≤𝑛≤1000,数组中各个元素值满足 ∣𝑣𝑎𝑙∣≤100

空间复杂度:𝑂(𝑛2),时间复杂度 𝑂(𝑛2)

注意:

  1. 三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c)
  2. 解集中不能包含重复的三元组。
复制代码
例如,给定的数组 S = {-10 0 10 20 -10 -40},解集为(-10, -10, 20),(-10, 0, 10) 

示例1

输入:[0]

返回值:[]

示例2

输入:[-2,0,1,1,2]

返回值:[[-2,0,2],[-2,1,1]]

示例3

输入:[-10,0,10,20,-10,-40]

返回值:[[-10,-10,20],[-10,0,10]]

分析

这道题重点是去重

代码

java
java 复制代码
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param num int整型一维数组 
     * @return int整型ArrayList<ArrayList<>>
     */
    public ArrayList<ArrayList<Integer>> threeSum (int[] num) {
        // write code here
        ArrayList<ArrayList<Integer>> result=new ArrayList<>();
        Arrays.sort(num);
        for(int i=0;i<num.length;i++){
            if(i>0 && num[i]==num[i-1]){
                continue;
            }
            int left=i+1;
            int right=num.length-1;
            while(left<right){
                int sum=num[i]+num[left]+num[right];
                if(sum>0){
                    right-=1;
                }else if(sum<0){
                    left+=1;
                }else{
                result.add(new ArrayList<>(Arrays.asList(num[i],num[left],num[right])));
                while (right > left && num[right] == num[right - 1]) right--;
                    while (right > left && num[left] == num[left + 1]) left++;
                    left++;
                    right--;
                }
            }
        }
        return result;
    }
}
python
python 复制代码
#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
# 
# @param num int整型一维数组 
# @return int整型二维数组
#
class Solution:
    def threeSum(self , num: List[int]) -> List[List[int]]:
        # write code here
        num.sort()
        result=[]
        for i in range(len(num)):
            if i>0 and num[i]==num[i-1]:
                continue
            left=i+1
            right=len(num)-1
            while left<right:
                sum=num[i]+num[left]+num[right]
                if sum>0:
                    right-=1
                elif sum<0:
                    left+=1
                else:
                    result.append([num[i],num[left],num[right]])
                    while left<right and num[right]==num[right-1]:
                        right-=1
                    while left<right and num[left]==num[left+1]:
                        left+=1
                    right-=1
                    left+=1
        return result
相关推荐
2301_787312432 小时前
Go 中自定义类型与基础类型的显式转换规则详解
jvm·数据库·python
qq_432703662 小时前
CSS如何引入CSS预加载器配置_优化样式编译流程提升效率
jvm·数据库·python
深度学习lover2 小时前
<数据集>yolo航拍军事目标识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·航拍军事目标识别
架构师老Y2 小时前
002、Prompt基础:大模型交互的第一性原理
人工智能·python·prompt
SamDeepThinking2 小时前
秒杀系统里的RocketMQ,不是发个消息那么简单
java·后端·架构
2401_832365522 小时前
如何用 FormData 配合 Fetch 实现无刷新的多文件上传
jvm·数据库·python
卷毛的技术笔记2 小时前
告别“盲猜式”排障:分布式链路追踪方案选型与Spring Boot 3实战
java·spring boot·分布式·后端·spring·面试·系统架构
自我意识的多元宇宙2 小时前
【数据结构】 红黑树
数据结构·算法
2401_871492852 小时前
如何在网页中实现国际象棋棋子的拖拽与格点吸附功能
jvm·数据库·python