【哈希系列】舍友担心期末考睡不着,我连夜准备了这套哈希全套专题(下)

简介: 【哈希系列】舍友担心期末考睡不着,我连夜准备了这套哈希全套专题

🐟 4.两个数组的交集


给定两个数组,编写一个函数来计算它们的交集。(好像还没见过那么短的题目)


题目链接:两个数组的交集https://leetcode-cn.com/problems/intersection-of-two-arrays/        


       题目分析:比较直接的方法是遍历nums1,对于它的每一个元素,在遍历nums2的时候判断该元素是否在数组nums2中。这里我们才用两个Set集合,哈希查询元素的效率是O(1),可以帮助我们降低时间复杂度。


方法1:利用HashSet


      时间复杂度O(n):n为nums1和num2的长度更长的那个,主要是用与两数组的遍历。


      空间复杂度O(n):n是num1的长度,最坏的情况下整个nums1都被装入到set中。


class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        int n1=nums1.length;
        int n2=nums2.length;
        //用来存放其中一个数组
        Set set=new HashSet();
        //答案的长度不会超过短数组的长度
        int[] arr=new int[Math.min(n1,n2)];
        for(int i=0;i<n1;i++){
            //set是不允许存放重复元素的,不用担心是否重复存入
            set.add(nums1[i]);
        }
        //用来作为给答案数组放答案的指针
        int j=0;
        for(int i=0;i<n2;i++){
            //判断set中是否有,如果有说明两个数组都有
            if(set.contains(nums2[i])){
                //加入答案数组
                arr[j++]=nums2[i];
                //加入后就从set中去掉,防止nums2有重复的再次加入
                set.remove(nums2[i]);
            }
        }
        //答案数组没有装满,就将后面减掉
        return Arrays.copyOf(arr,j);
    }       
}

方法2:排序加双指针


       为了获得数组的交集,我们可以将数组排序,然后利用两个指针分别指向两个数组的起始端,然后判断。如果相等,则加入进答案数组,在加入前需要判断是否已经加入过,然后两指针向右移动一位。        


class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        if(nums1==null||nums1.length==0||nums2==null||nums2.length==0){
            return new int[0];
        }
        //排序数组
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int[] arr=new int[Math.min(nums1.length,nums2.length)];
        //双指针
        int p1=0;
        int p2=0;
        //用来放入答案数组的指针
        int index=0;
        while(p1<nums1.length&&p2<nums2.length){
              if(nums1[p1]==nums2[p2]){
                  //确保答案不重复
                  if(index==0||nums1[p1]!=arr[index-1]){
                  arr[index++]=nums1[p1];                 
                  } 
                  //无论是否放入数组,都应该++
                  p1++;
                  p2++;           
              }else if(nums1[p1]>nums2[p2]){
                  p2++;
              }else{
                  p1++;
              }  
        }
        return  Arrays.copyOfRange(arr,0,index);
    }
}


🐳5.快乐数


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


「快乐数」定义为:


对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。

然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。

如果 可以变为  1,那么这个数就是快乐数。

如果 n 是快乐数就返回 true ;不是,则返回 false 。


题目链接:快乐数https://leetcode-cn.com/problems/happy-number/          


       题目分析:我们可以猜想,如果一个数字如果不是快乐数,那它在进行题目要求的操作时一定会有循环,也就是会产生重复数字。这是一个猜想,但也确实如此,它的证明是需要数学来证明的,但是这个猜想其实也很容易想到。一直循环下去肯定会出现重复数字导致循环。这样我们就可以利用HashSet来判断重复。


方法1:哈希检测循环


       时间复杂度O(logn):这道题目时间复杂度不好分析,因为我们不知道循环会多少次,无法去准备计算,大家了解是O(logn)即可


       空间复杂度O(logn):同理于上


class Solution {
    public boolean isHappy(int n) {
        //用来存储每次操作以后的数
        Set<Integer> set=new HashSet<>();
        //先将n放入
        set.add(n);
        //一直循环,哈希检测
        while(true){
            //x保存n操作以后的值
            int x=test(n);
            //说明是快乐数
            if(x==1){
                return true;
            }
            //未出现的数,放入set
            if(!set.contains(x)){
                set.add(x);
            //出现过的数,说明不是快乐数
            }else{
                return false;
            }
            //把x赋值回给n
            n=x;
        }
    }
    //写一个操作方法
    public int test(int n){
        int count=0;
        while(n!=0){
            int a=n%10;
            count+=a*a;
            n=n/10;
        }
        return count;
    }
}


🐋6.赎金信


给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。


如果可以,返回 true ;否则返回 false 。


magazine 中的每个字符只能在 ransomNote 中使用一次。


题目链接:赎金信https://leetcode-cn.com/problems/ransom-note/


          题目解析:这道题目和前面第一道题的做法基本一模一样,只不过要求有一点点变化,这里直接贴上代码,只在第一题上稍微改动一下即可


方法:数组哈希映射


          时间复杂度O(n):n为ransomNote和magazine更长的字符串的长度。主要是遍历的耗时


          空间复杂度O(1):常数级数组的消耗视为O(1)


class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] arr=new int[26];
        for(int i=0;i<ransomNote.length();i++){
            arr[ransomNote.charAt(i)-'a']--;
        }
        for(int i=0;i<magazine.length();i++){
            arr[magazine.charAt(i)-'a']++;
        }
        for(int i=0;i<26;i++){
            if(arr[i]<0){
                //小于0说明不够
                return false;
            }
        }
        return true;
    }
}


🐬7.两数之和


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


你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。


你可以按任意顺序返回答案。


题目链接:两数之和https://leetcode-cn.com/problems/two-sum/      


       题目分析:不能太经典的题目,我在几数之和系列中也详细讲解过,这里就只为大家贴上哈希的做法。


       时间复杂度O(n):n为nums的长度,主要是循环的耗时


       空间复杂度O(n):n为nums的长度,主要是哈希的开销


class Solution {
    public int[] twoSum(int[] nums, int target) {
        int n=nums.length;
        //key存放值,value存放下标
        Map<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<n;i++){
            //找到了
            if(map.containsKey(target-nums[i])){
                //返回下标
                return new int[]{map.get(target-nums[i]),i};
            }
            //没找到放入map中
            map.put(nums[i],i);
        }
        //遍历结束仍然未找到
        return new int[0];
    }
}


☀️ 3.哈希总结(题目总链接)


      哈希做法是经典的以空间换时间,我们做题一般都是更容易超时,哈希可以很好的帮我们解决这个问题。但是基础的题目只用哈希就可以,如果进阶的题目还需要和其他做法,比如双指针等等一起搭配。所以大家一定要打好哈希的基础,从简单题入手,不然以后用哈希都想不到。后续我也会写出哈希的进阶以及多种算法练习的练题集锦,希望大家收藏支持一下。


1.存在重复元素 https://leetcode-cn.com/problems/contains-duplicate/

2.存在重复元素|| https://leetcode-cn.com/problems/contains-duplicate-ii/

3.有效字母异位词 https://leetcode-cn.com/problems/valid-anagram/

4.两个数组的交集 https://leetcode-cn.com/problems/intersection-of-two-arrays/

5.快乐数 https://leetcode-cn.com/problems/happy-number/

6.赎金信 https://leetcode-cn.com/problems/ransom-note/

7.两数之和 https://leetcode-cn.com/problems/two-sum/


相关文章
|
前端开发 Python
幸运哈希hash单双尾数大小竞猜游戏开发源码部署
def is_even_number(number): """判断一个整数是否为偶数""" return number % 2 == 0
|
存储 算法 安全
走进Python Hash函数的魔幻世界:解密哈希算法与防碰撞技术
走进Python Hash函数的魔幻世界:解密哈希算法与防碰撞技术
179 0
|
存储 算法 程序员
程序员常说的「哈希表」是个什么鬼?
程序员常说的「哈希表」是个什么鬼?
|
区块链 数据安全/隐私保护
 哈希竞猜游戏源码版丨哈希竞猜游戏系统开发(逻辑及详情)丨哈希竞猜游戏开发稳定版
哈希函数的运算结果是哈希值竞猜,如果两个哈希值相同的话,那这两个输入值的微盘结果极大可能会是多国语言相同的,也有一部分可能是大富不同的,这一部分的情况就叫做幸运哈希竞猜碰撞。反之如果两个哈希值是不相同的,那么这两个散列值的原始输入一定是不相同的。
|
存储 区块链 数据安全/隐私保护
Hash哈希竞猜游戏系统开发(区块链游戏开发案例)丨Hash哈希竞猜游戏系统开发(详细程序)丨源码方案
单向性(one-way),从预映射,能够简单迅速的得到散列值,而在计算上不可能构造一个预映射,使其散列结果等于某个特定的散列值,即构造相应的M=J(h)不可行。这样,散列值就能在统计上唯一的表征输入值,因此,密码学上的Hash又被称为”消息摘要(message digest)”,就是要求能方便的将”消息”进行”摘要”,但在”摘要”中无法得到比”摘要”本身更多的关于”消息”的信息。
|
算法
算法竞赛100天第四天 —— 设计哈希表(散列表)
算法竞赛100天第四天 —— 设计哈希表(散列表)
134 0
算法竞赛100天第四天 —— 设计哈希表(散列表)
|
存储 安全 区块链
Hash哈希竞猜游戏开发运营版丨哈希Hash竞猜游戏系统开发(开发案例)及源码规则
去中心化存储技术是一种新型存储技术,它改变了传统的集中式存储技术,将数据从单一位置移到多个位置,这样就消除了存储数据的中心机构或服务器的责任,增加了安全性和数据的有效存储,确保用户的数据安全性
|
存储 安全 Java
哈希竞猜游戏系统开发(hash哈希开发)丨哈希竞猜游戏开发成熟源码及运营版
 哈希表属于抽象数据结构,需要开发者按哈希表数据结构的存储要求进行API定制,对于大部分高级语言而言,都会提供已经实现好的、可直接使用的API,如JAVA中有MAP集合、C++中的MAP容器,Python中的字典……
|
算法 安全 前端开发
Hash哈希竞猜游戏系统开发(开发详情)丨Hash哈希竞猜游戏开发案例及源码版
 Blockchain technology can thus empower enterprises in many ways:providing reliable shared data and building trust between all parties;Eliminate data islands,that is,
|
NoSQL 数据挖掘 应用服务中间件
哈希游戏系统开发技术讲解
哈希游戏系统开发技术讲解
146 1