代码随想录--哈希表章节总结

news2024/12/25 12:28:58

代码随想录–哈希表章节总结

1. LeetCode242 有效的字母异位词

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

示例 1:
输入: s = "anagram", t = "nagaram"
输出: true

解题思路1: 利用HashMap。

  • 首先循环第一个字符串,使用Map保存每一个字符出现的频率。
  • 然后遍历第二个字符串,首先判断Map中是否包含这个字符,如果不包含,则直接返回false。否则将Map中当前字符出现的频率-1
  • 然后再次遍历第一个字符串,这一次遍历实际上是遍历Map,如果发现Map中对应元素出现的频率不是0,那么返回false,否则循环结束返回true
public boolean isAnagram(String s, String t) {
    // 如果两个字符串长度不同,则返回false
    if (s.length() != t.length()) return false;
    // 将其中一个字符串放入set集合
    HashMap<Character, Integer> map = new HashMap<>();
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (map.containsKey(c)) {
          map.put(c, map.get(c) + 1);
        } else {
          map.put(c, 1);
        }
    }
    // 遍历第二个字符串
    for (int i = 0; i < t.length(); i++) {
        char c = t.charAt(i);
        if (!map.containsKey(c)) return false;
        map.put(c, map.get(c) - 1);
    }

    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (map.get(c) > 0) return false;
    }
    return true;
}

解题思路2:思路实际上和思路1是一样的,只不过实现方式不再使用Map,而是使用数组

  • 建立一个长度为26的数组,正好对应26个小写字母。数组的第一个位置代表a出现的次数,第二个位置代表b出现的位置,依此类推。
  • 然后遍历第一个字符串,记录每一个元素出现的次数
  • 然后遍历第二个字符串,发现出现的字符,就将出现次数-1
  • 遍历整个数组,一旦发现数组中元素有不是0的,则返回false。循环结束,返回true。
public boolean isAnagram(String s, String t) {
    if (s.length() != t.length()) return false;
    int count[] = new int[26];

    for (int i = 0; i < s.length(); i++) {
      count[s.charAt(i) - 'a']++;
    }
    for (int i = 0; i < t.length(); i++) {
        count[t.charAt(i) - 'a']--;
    }
    for (int i = 0; i < count.length; i++) {
        if (count[i] != 0) return false;
    }
    return true;
}

从运行时长可以看出,采用数组方式实现在时间上要快不少

image-20230119130244278

2. LeetCode349 两个数组的交集

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

解题思路1: 使用set集合,循环遍历将第一个数组中所有元素保存到set中,然后循环遍历第二个数组,将第二个数组中包含在set集合中的元素添加到返回set中。然后将返回set转化为int数组即可。

public int[] intersection(int[] nums1, int[] nums2) {
        Set<Integer> set = new HashSet<>();
        Set<Integer> res = new HashSet<>();

        for (int i = 0; i < nums1.length; i++) {
            if (!set.contains(nums1[i])) {
                set.add(nums1[i]);
            }
        }

        for (int i = 0; i < nums2.length; i++) {
            if (set.contains(nums2[i])) {
                res.add(nums2[i]);
            }
        }
        return SetToInt(res);
    }
private static int[] SetToInt(Set<Integer> allSet) {
    // 先将set集合转为Integer型数组
    Integer[] temp = allSet.toArray(new Integer[] {});//关键语句

    // 再将Integer型数组转为int型数组
    int[] intArray = new int[temp.length];
    for (int i = 0; i < temp.length; i++) {
        intArray[i] = temp[i].intValue();
    }
    return intArray;
}

解题思路2: 利用数组。使用数组来保存数组1中出现的元素。比如arr[1]就表示在数组1中元素1出现过。

  • 遍历数组1,使用数组记录数组1中元素包含的数字
  • 遍历数组2,判断数组2中是否包含数组1中的元素,如果包含保存到set中
  • 将set转化为数组返回。
public int[] intersection(int[] nums1, int[] nums2) {
    Set<Integer> set = new HashSet<>();
    int[] hashArray = new int[1001];
    // 遍历数组1,使用哈希数组记录数组1中包含的数字
    for (int i = 0; i < nums1.length; i++) {
        hashArray[nums1[i]] = 1;
    }
    // 遍历数组2
    for (int i = 0; i < nums2.length; i++) {
        if (hashArray[nums2[i]] == 1)
            set.add(nums2[i]);
    }
    return set.stream().mapToInt(x -> x).toArray();
}

3. LeetCode202 快乐数

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

「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:

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

解题思路: 对于满足快乐数条件的值,那么他最终会得到1,如果不满足,那么在经历n次循环后,sum的值会出现重复。因此我们利用set,判断是否值出现了重复,如果出现了重复,则不是快乐数,否则当循环结束后,返回true。

public boolean isHappy(int n) {
    Set<Integer> set = new HashSet<>();
    while (n != 1) {
        if (set.contains(n)) return false;
        set.add(n);
        n = getRes(n);
    }
    return true;
}

private int getRes(int n) {
    int res = 0;
    while (n > 0) {
        int temp = n % 10;
        res += (temp * temp);
        n = n / 10;
    }
    return res;
}

这个题另外值得学习的地方是如何取一个数字的每一个位对应的数字

private int getRes(int n) {
 int res = 0;
 while (n > 0) {
     int temp = n % 10;
     res += (temp * temp);
     n = n / 10;
 }
 return res;
}

4. LeetCode1 两数之和

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

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

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

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

解题思路: 这道题可以利用Map来求解。

  • 首先,循环遍历nums,每遍历一个元素,就到Map中判断有没有包含target-nums[i]的key,如果有那么就返回i,以及target-nums[i]为key的值。比如target = 9,当前取出的元素值为2,那么就去Map中查找是否之前遍历过7
  • 否则,就将当前元素,以及当前元素的下标保存到Map中
  • 一直遍历,知道遍历结束都没有返回的话,那么返回false

image-20230119155529207

public int[] twoSum(int[] nums, int target) {
    int[] a = new int[] {1, 2};
    // 创建一个Map Key为数组中的元素,value为对应的下标
    Map<Integer, Integer> map = new HashMap<>();
    // 开始遍历数组
    for (int i = 0; i < nums.length; i++) {
        // 先判断之前是否遍历过符合要求的元素
        // 比如target = 9,当前取出的元素值为2,那么就去Map中查找是否之前遍历过7
        // 如果遍历过7,那么就找到了两个下标,分别是7对应的下标和当前的i
        if (map.containsKey(target - nums[i])) {
            // 如果存在,则直接返回
            return new int[] {i, map.get(target - nums[i])};
          }
        // 否则 将当前元素加入map
        map.put(nums[i], i);
    }
    return null;
}

因为是两个数求和,实际上就是先确定了一个数,然后另一个数肯定等于target-num, 然后再去找是否有满足target-num的数即可。

解题思路2:当然这个题也可以使用暴力法求解

public int[] twoSum(int[] nums, int target) {
    for (int i = 0; i < nums.length; i++) {
        for (int j = 0; j < nums.length; j++) {
            if (i == j) continue;
            if (nums[i] + nums[j] == target)
                return new int[] {i, j};
        }
    }
    return null;
}

对比一下两个方法的耗时,竟然差了100倍
image-20230119160552530

5. LeetCode454 四数相加II

给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

0 <= i, j, k, l < n
nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

示例 1:

输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

解题思路: 这个题如果我们使用暴力方法去做的话,时间复杂度高达 O ( n 4 ) O(n^4) O(n4),因此我们考虑其他方法。

  • 首先我们可以将四个数组划分为两个数组,通过把nums1 nums2相加的这种方式。通过一个双重for循环,遍历nums1和nums2中两两相加的所有可能,并保存到Map中。Map的key为求和的值,value为等于这个值的组合的数量。
  • 然后过一个双重for循环,遍历nums3和nums4中两两相加的所有可能,每遍历一个可能,就去判断在Map中是否存在0-(nums3[i]+nums4[j])的记录是否存在,如果存在则count += map.get(0-(nums3[i]+nums4[j]))

Map中的key保存的是nums1,nums2两两相加所有可能的值,而value保存的是对应可能的值的所有组合方式个数

public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
    // 创建两个数组 分别用来保存nums1+nums2 nums3+nums4
    // 数组长度相同
    int[] sum = new int[nums1.length];

    Map<Integer, Integer> map = new HashMap<>();

    // 计算nums1 + nums2的所有可能和
    for (int i = 0; i < nums1.length; i++) {
        for (int j = 0; j < nums3.length; j++) {
            int temp = nums1[i] + nums2[j];
            if (map.containsKey(temp)) {
                map.put(temp, map.get(temp) + 1);
            } else {
                map.put(temp, 1);
            }
        }
    }
    // 遍历nums3 + nums 4
    Integer count = 0;
    for (int i = 0; i < nums3.length; i++) {
        for (int j = 0; j < nums4.length; j++) {
            int temp = nums3[i] + nums4[j];
            if (map.containsKey(-temp)) {
                count += map.get(-temp);
            }
        }
    }
    return count;
}

image-20230119193648351

为什么是两两组合呢?

是因为两两组合在遍历的时候,时间复杂度都是 O ( n 2 ) O(n^2) O(n2)的,所以一共的时间复杂度是 O ( 2 n 2 ) O(2n^2) O(2n2)

如果求第一个数组,存入Map,然后遍历nums2,nums3,nums4的可能性的话,那么时间复杂度为 O ( n + n 3 ) O(n+n^3) O(n+n3) 时间复杂度比较高

6.LeetCode303 赎金信

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

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

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

示例 1:
输入:ransomNote = "a", magazine = "b"
输出:false
示例 2:
输入:ransomNote = "aa", magazine = "ab"
输出:false
示例 3:
输入:ransomNote = "aa", magazine = "aab"
输出:true

解题思路: 这个题和之前的第一题思路是一样的。因为字符串中只有小写字母,因此采用数组的方式模拟哈希

  • 首先遍magazine,然后计算出字符串中不同字符出现的次数
  • 然后遍历ransomNote,在hash数组中找到匹配的就让出现的次数-1
  • 遍历结束后,如果hash中的元素都大于等于0,返回true,否则返回false
public boolean canConstruct(String ransomNote, String magazine) {
    // 遍历ransomNote,保存到hash数组中
    // 数组中的值表示对应字符在ransomNote出现的次数
    int[] hash = new int[26];
    for (int i = 0; i < magazine.length(); i++) {
        hash[magazine.charAt(i) - 'a']++;
    }
    for (int i = 0; i < ransomNote.length(); i++) {
        hash[ransomNote.charAt(i) - 'a']--;
    }
    for (int i = 0; i < hash.length; i++) {
        if (hash[i] < 0)
            return false;
    }
    return true;
}

注意:一定要遍历magazine放入hash,而不是遍历ransomNote

举例 ransomNote = “a” magazine=“b”

  • ransomNote放入hash,[1,0,…], magazine执行完–后,hash为[1,-1,0,…],看不出是不是符合
  • magazine放入hash,[0,1,…], ransomNote执行完–后,hash为[-1,1,…],出现了-1,说明magazine中的字母已经不够用了,所以不满足。如果遍历完之后,hash中元素都是不小于0的,那么就满足。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/173443.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高德地图红绿灯读秒是怎么实现的?(二)

通过上一篇高德官方回复&#xff0c;以及一些科技大佬们的脑回路&#xff0c;做了一些简单的回复&#xff1b; 这次好好的从个人研究观点来阐述一下这个论题 目前有两种说法&#xff0c;一种说是靠大数据分析&#xff0c;一种说是靠交管部门数据。 从个人的研究来看&#xff0…

socket 2---TCP编程

目录 一、TCP编程流程 二、函数接口 2.1、监听接口 2.2、发起连接 connect 2.3、接收新连接 accept 2.4、收发接口 三、代码实现 问题&#xff1a; 要是创建多个客户端的话会怎么样呢&#xff1f; 那么怎么去真正解决这个问题呢&#xff1f; 一、TCP编程流程 这里…

数据结构与算法基础(王卓)(9):线性表的应用(有序表合并)(有序,可重复)

PPT&#xff1a;第二章P176&#xff1b; 合并为一个新的整体&#xff1a;有序表的合并&#xff08;有序&#xff0c;可重复&#xff09; 线性表&#xff1a; 对于该操作的具体实现的流程设计&#xff1a;&#xff08;各模块&#xff09; 创建一个空表C 依次从A或B(中&#…

移动云国产商用密码规模化应用

前言 为深入贯彻落实《密码法》&#xff0c;推动商用密码技术在工业和信息化行业领域的融合应用&#xff0c;工业和信息化部密码应用研究中心组织开展了“首届全国商用密码应用优秀案例征集”工作&#xff0c;并评审选出15项优秀案例。 同时&#xff0c;为持久发挥本次活动的…

CSAPP笔记

目录 第一章 一个典型的硬件组成 从键盘上读取hello指令​编辑 存储器结构示例 相对性能公式 计算机系统抽象 第二章--信息的表示和处理 按位 & | ^ ~ 与逻辑运算 && || 逻辑右移和算术右移 左移 定义计算机如何编码和操作整数的数学定义 补码编码的定义 补码…

【JavaWeb】前端开发三剑客之CSS(上)

✨哈喽&#xff0c;进来的小伙伴们&#xff0c;你们好耶&#xff01;✨ &#x1f6f0;️&#x1f6f0;️系列专栏:【JavaWeb】 ✈️✈️本篇内容:CSS从零开始学习&#xff01; &#x1f680;&#x1f680;代码托管平台github&#xff1a;JavaWeb代码存放仓库&#xff01; ⛵⛵作…

擎创动态 | 官宣!与深智城集团正式签约

近日&#xff0c;上海擎创信息技术有限公司与深圳市智慧城市科技发展集团有限公司&#xff08;以下简称“深智城集团”&#xff09;就“一体化协同办公平台项目”达成战略合作&#xff0c;签约仪式已圆满完成。 ​深智城集团副总经理罗介平、智城软件公司常务副总经理韩小宇、智…

android 读取assets配置文件

方法1-getAssets().open(“re.properties”) try {Properties props new Properties();props.load(getAssets().open("re.properties"));Log.e(TAG, "className:" props.getProperty("className"));} catch (IOException e) {e.printStackTrace…

支持加密的日记应用程序DailyTxT

本文完成于 12 月下旬&#xff0c;对应的版本为 1.0.10(2022_11_02)&#xff1b; 什么是 DailyTxT &#xff1f; DailyTxT 是一个加密的 Web 日记应用程序&#xff0c;用于写下您当天的故事并轻松地再次找到它们。它是用 Python Flask&#xff08;后端&#xff09;和 Vue.JS&am…

23种设计模式(十二)——外观模式【接口隔离】

外观模式 文章目录 外观模式意图什么时候使用外观真实世界类比外观模式的实现外观模式的优缺点亦称:Facade 意图 外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容…

一直以来,人们都在探索互联网赋能实体的正确的途径和逻辑

一直以来&#xff0c;人们都在寻找互联网回归实体的正确的方式和方法&#xff1b;一直以来&#xff0c;人们都在探索互联网赋能实体的正确的途径和逻辑。然而&#xff0c;互联网似乎始终都游离于产业之外&#xff0c;似乎始终都超脱于产业之上。尽管经历了PC时代和移动互联网时…

分支预测详解

分支预测用于在微处理器中以流水线效率为目标来预测程序流。有许多方法来实现分支预测&#xff0c;通常在更好的预测结果和增加硬件做预测之间需要进行权衡。 目录 分支预测简介 静态分支预测 动态分支预测 启动分支预测 分支预测简介 要了解分支预测器&#xff0c;就不得…

QT当类有多个不同类型的同名信号时如何处理QOverload?

我们在设计类的信号时也许也会像设计类方法一样&#xff0c;给予多种不同参数类型的重载版本&#xff0c;这样一来我们就可以应对不同类型的参数输入或者输出。 但我们在使用有重载的信号版本时就不那么方便了&#xff0c;QT系统没有那么智能&#xff0c;不会自动匹配&#xff…

【实操案例三】进制转换、异常捕获、输出颜色设置、格式化字符串的设置等实例代码及运行效果图!

任务一&#xff1a;将指定的十进制数转换成二进制、八进制、十六进制 # 任务一&#xff1a;将指定的十进制数转换成二进制、八进制、十六进制 def fun():numint(input(请输入一个十进制整数&#xff1a;))print(num,的二进制数为&#xff1a;,bin(num)) # 第一种写法&#xff…

网线交叉、直连区别

欢迎来到东用知识小课堂&#xff01;一.网线常识网线常用的有&#xff1a;双绞线、同轴电缆、光纤等。双绞线可按其是否外加金属网丝套的屏蔽层而区分为屏蔽双绞线&#xff08;STP&#xff09;和非屏蔽双绞线&#xff08;UTP&#xff09;。从性价比和可维护性出发&#xff0c;大…

golang语言websocket百万长链接

是简单demo测试 前端 <html> <head><title>Simple client</title><script type"text/javascript">var ws;function init() {// Connect to Web Socketws new WebSocket("ws://localhost:8866/ws");// Set event handlers…

联合证券|再创纪录,外资狂买超1000亿!券商、期货板块持续活跃

A股今天全线上扬&#xff0c;沪指小幅走高&#xff0c;创业板、科创50指数体现强势&#xff1b;港股走势疲弱&#xff0c;恒生科技指数一度跌超2%。 详细来看&#xff0c;两市股指盘中震动上扬&#xff0c;午后全线走高&#xff0c;创业板指、科创50指数涨超1%&#xff1b;到收…

PCB板缺陷检测识别系统 YOLOv7

PCB板缺陷检测识别系统通过YOLOv7网络深度学习技术&#xff0c;对现场PCB是否存在缺陷部分进行实时分析检测&#xff0c;当检测到PCB本身存在缺陷的时候&#xff0c;立即抓拍存档告警方便后期针对性的进行调整改。YOLO系列算法是一类典型的one-stage目标检测算法&#xff0c;其…

CSS+JS 折叠

文章目录CSSJS 折叠效果CSSjQuery 鼠标经过显示详细信息CSSJS 折叠效果 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>折叠效果</title><style type"text/css">.collapse-box {width: 500px;borde…

FMC子卡设计资料原理图:FMC177-基于AD9361的双收双发射频FMC子卡

FMC177-基于AD9361的双收双发射频FMC子卡一、板卡介绍 FMC177射频模块分别包含两个接收通道与发射通道&#xff0c;其频率可覆盖达到70MHz~6GHz&#xff0c;AD9361芯片提供具有成本效益的实验平台&#xff0c;具有达到56MHz的瞬时带宽&#xff0c;更高的灵敏度&#xff…