代码随想录算法训练营第六天 | LeetCode 242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1. 两数之和

简介: 代码随想录算法训练营第六天 | LeetCode 242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1. 两数之和

1. 哈希表基础

1.1 概念

顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较顺序查找时间复杂度为O(N),平衡树中为树的高度,即O( ),搜索的效率取决于搜索过程中元素的比较次数。

理想的搜索方法:可以不经过任何比较,一次直接从表中得到要搜索的元素如果构造一种存储结构,通过某种函(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快

找到该元素

当向该结构中:

  • 插入元素

       根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放

  • 搜索元素

       对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功

该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)        

例如:数据集合{176459}

哈希函数设置为:hash(key) = key % capacity; capacity为存储元素底层空间总的大小。

用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快 问题:按照上述哈希方式,向集合中插入元素44,会出现什么问题?

1.2 冲突-概念

对于两个数据元素的关键字 和 (i != j),有!= ,但有:Hash( ) == Hash( ),即:不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞

1.3 冲突-解决

解决哈希冲突两种常见的方法是:闭散列和开散列

1.4 冲突-解决-闭散列

闭散列:也叫开放定址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以key存放到冲突位置中的下一个空位置中去。那如何寻找下一个空位置呢?

        线性探测

       

       比如上面的场景,现在需要插入元素44,先通过哈希函数计算哈希地址,下标为4,因此44理论上应该插在该位置,但是该位置已经放了值为4的元素,即发生哈希冲突。

       线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

       

       插入:

  • 通过哈希函数获取待插入元素在哈希表中的位置
  • 如果该位置中没有元素则直接插入新元素,如果该位置中有元素发生哈希冲突,使用线性探测找到下一个空位置,插入新元素

1.5冲突-解决-开散列/哈希桶

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。

从上图可以看出,开散列中每个桶中放的都是发生哈希冲突的元素。

开散列,可以认为是把一个在大集合中的搜索问题转化为在小集合中做搜索了

2. LeetCode 242.有效的字母异位

2.1 思路

  1. 本题全由小写字母组成,“a-z”,ASCII码值是连续的,那么a可以对应到数组下标为0的位置,z可以对应到数组下标为25的位置,因此定义一个哈希数组长度为26即可
  2. 先用数组统计第一个字符串每一个字母出现的频率,在数组做对应的加法
  3. 再用数组统计第二个字符串每一个字母出现的频率,在数组做对应的减法
  4. 如果最后遍历数组所有位置的值都为0那说明对了
  5. 关于哈希表什么时候用数组、set、map?哈希值比较小且范围小可控用数组,数值很大用set,有k对应value就用map

2.2 代码

/**
 * 242. 有效的字母异位词 字典解法
 * 时间复杂度O(m+n) 空间复杂度O(1)
 */
class Solution {
    public boolean isAnagram(String s, String t) {
        int[] record = new int[26];
        for (int i = 0; i < s.length(); i++) {
            record[s.charAt(i) - 'a']++;     // 并不需要记住字符a的ASCII,只要求出一个相对数值就可以了
        }
        for (int i = 0; i < t.length(); i++) {
            record[t.charAt(i) - 'a']--;
        }
        for (int count: record) {
            if (count != 0) {               // record数组如果有的元素不为零0,说明字符串s和t 一定是谁多了字符或者谁少了字符。
                return false;
            }
        }
        return true;                        // record数组所有元素都为零0,说明字符串s和t是字母异位词
    }
}

3. LeetCode 349. 两个数组的交集

3.1 思路

  1. 为什么用哈希表?哈希表最擅长于解决给你一个元素判断在这个集合里是否出现过这种情况,就用数组或者map或者set
  2. 数值很大的话做哈希映射时用数组就不合适了,太浪费了,就用set做(什么时候用map后面说)
  3. 把nums1里的所有数值放入set1中,然后遍历nums2,遍历时去set1里查询是否出现过,如果出现过再放入set2中,这个集合是去重(因为Set不允许有相同的元素出现)的(两个2的话就只有一个1)

3.2 代码

import java.util.HashSet;
import java.util.Set;
class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        if (nums1 == null || nums1.length == 0 || nums2 == null || nums2.length == 0) {
            return new int[0];
        }
        Set<Integer> set1 = new HashSet<>();
        Set<Integer> resSet = new HashSet<>();
        //遍历数组1
        for (int i : nums1) {
            set1.add(i);
        }
        //遍历数组2的过程中判断哈希表中是否存在该元素
        for (int i : nums2) {
            if (set1.contains(i)) {
                resSet.add(i);
            }
        }
        //方法1:将结果集合转为数组
        return resSet.stream().mapToInt(x -> x).toArray();
        //方法2:另外申请一个数组存放setRes中的元素,最后返回数组
        int[] arr = new int[resSet.size()];
        int j = 0;
        for(int i : resSet){
            arr[j++] = i;
        }
        return arr;
    }
}

4. LeetCode 202. 快乐数

4.1 思路

  1. 通过set判断n是否在一个集合里
  2. 关键点:将n转化为各个位上的平方和,先%10方式求得最后一位上的数,然后平方加到result上,然后n/10将最后一位上的数去掉,这样就求得各个位上的平方和
  3. 判断条件:n!=1并且n没有进入过set集合中,如果进入过还进去就陷入无限循环了

4.2 代码

class Solution {
    public boolean isHappy(int n) {
        Set<Integer> set=new HashSet<>();
        //如果这个数不是1并且set里没有这个数(有的话还进去就无限循环了)
        while(n!=1&&!set.contains(n)){
            set.add(n);
            n=getNextNum(n);
        }
        return n==1;
    }
    public static int getNextNum(int n){
        int result=0;
        int temp=0;
        //将n替换为各个位上的平方和
        while(n>0){
            temp=n%10;
            result+=temp*temp;
            n/=10;
        }
        return result;
    }
}

5. LeetCode 1. 两数之和

5.1 思路

  1. 什么时候用哈希表?给你一个元素判断在这个集合里是否出现过,这题里遍历一个元素的时候我们判断另一个需要的元素是否遍历保存过,比如这题target是9,你遍历到3时就要判断是否遍历保存过6,因为3+6=9
  2. 什么时候用数组还是set还是map?这题里我们想要找一个元素,这个元素出现过,同时还要知道这个元素在数组里的下标,即需要<元素,下标>,用数组和set都不行了,就用map的key和value
  3. 又因为我们要查找的是元素是否出现过,因此把元素作为key,下标作为value

5.2 代码

public int[] twoSum(int[] nums, int target) {
    int[] res = new int[2];
    if(nums == null || nums.length == 0){
        return res;
    }
    Map<Integer, Integer> map = new HashMap<>();
    for(int i = 0; i < nums.length; i++){
        int temp = target - nums[i];   // 遍历当前元素,并在map中寻找是否有匹配的key
        if(map.containsKey(temp)){
            res[1] = i;
            res[0] = map.get(temp);
            break;
        }
        map.put(nums[i], i);    // 如果没找到匹配对,就把访问过的元素和下标加入到map中
    }
    return res;
}
相关文章
|
8天前
|
算法 Java
[Java·算法·简单] LeetCode 283. 移动零
[Java·算法·简单] LeetCode 283. 移动零
16 2
|
8天前
|
算法 Java
[Java·算法·中等] LeetCode21. 合并两个有序链表
[Java·算法·中等] LeetCode21. 合并两个有序链表
14 2
|
11天前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-2
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
11天前
|
算法 C++
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题-1
【数据结构与算法】:关于时间复杂度与空间复杂度的计算(C/C++篇)——含Leetcode刷题
|
2天前
|
算法
基于GA遗传优化的混合发电系统优化配置算法matlab仿真
**摘要:** 该研究利用遗传算法(GA)对混合发电系统进行优化配置,旨在最小化风能、太阳能及电池储能的成本并提升系统性能。MATLAB 2022a用于实现这一算法。仿真结果展示了一系列图表,包括总成本随代数变化、最佳适应度随代数变化,以及不同数据的分布情况,如负荷、风速、太阳辐射、弃电、缺电和电池状态等。此外,代码示例展示了如何运用GA求解,并绘制了发电单元的功率输出和年变化。该系统原理基于GA的自然选择和遗传原理,通过染色体编码、初始种群生成、适应度函数、选择、交叉和变异操作来寻找最优容量配置,以平衡成本、效率和可靠性。
|
3天前
|
机器学习/深度学习 算法
基于鲸鱼优化的knn分类特征选择算法matlab仿真
**基于WOA的KNN特征选择算法摘要** 该研究提出了一种融合鲸鱼优化算法(WOA)与K近邻(KNN)分类器的特征选择方法,旨在提升KNN的分类精度。在MATLAB2022a中实现,WOA负责优化特征子集,通过模拟鲸鱼捕食行为的螺旋式和包围策略搜索最佳特征。KNN则用于评估特征子集的性能。算法流程包括WOA参数初始化、特征二进制编码、适应度函数定义(以分类准确率为基准)、WOA迭代搜索及最优解输出。该方法有效地结合了启发式搜索与机器学习,优化特征选择,提高分类性能。
|
3天前
|
机器学习/深度学习 算法 数据可视化
基于BP神经网络的64QAM解调算法matlab性能仿真
**算法预览图省略** MATLAB 2022A版中,运用BP神经网络进行64QAM解调。64QAM通过6比特映射至64复数符号,提高数据速率。BP网络作为非线性解调器,学习失真信号到比特的映射,对抗信道噪声和多径效应。网络在处理非线性失真和复杂情况时展现高适应性和鲁棒性。核心代码部分未显示。
|
1天前
|
算法 计算机视觉
基于Chan-Vese算法的图像边缘提取matlab仿真
**算法预览展示了4幅图像,从边缘检测到最终分割,体现了在matlab2022a中应用的Chan-Vese水平集迭代过程。核心代码段用于更新水平集并显示迭代效果,最后生成分割结果及误差曲线。Chan-Vese模型(2001)是图像分割的经典方法,通过最小化能量函数自动检测平滑区域和清晰边界的图像分割,适用于复杂环境,广泛应用于医学影像和机器视觉。**
|
6天前
|
机器学习/深度学习 算法 数据可视化
m基于PSO-LSTM粒子群优化长短记忆网络的电力负荷数据预测算法matlab仿真
在MATLAB 2022a中,应用PSO优化的LSTM模型提升了电力负荷预测效果。优化前预测波动大,优化后预测更稳定。PSO借鉴群体智能,寻找LSTM超参数(如学习率、隐藏层大小)的最优组合,以最小化误差。LSTM通过门控机制处理序列数据。代码显示了模型训练、预测及误差可视化过程。经过优化,模型性能得到改善。
23 6
|
3天前
|
缓存 算法
基于机会网络编码(COPE)的卫星网络路由算法matlab仿真
**摘要:** 该程序实现了一个基于机会网络编码(COPE)的卫星网络路由算法,旨在提升无线网络的传输效率和吞吐量。在MATLAB2022a中测试,结果显示了不同数据流个数下的网络吞吐量。算法通过Dijkstra函数寻找路径,计算编码机会(Nab和Nx),并根据编码机会减少传输次数。当有编码机会时,中间节点执行编码和解码操作,优化传输路径。结果以图表形式展示,显示数据流与吞吐量的关系,并保存为`R0.mat`。COPE算法预测和利用编码机会,适应卫星网络的动态特性,提高数据传输的可靠性和效率。