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 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 从单一元素的异或解法到HashMap源码 -> 正文阅读

[数据结构与算法]从单一元素的异或解法到HashMap源码

从单一元素的异或解法到HashMap源码

有序数组中的单一元素

来自力扣原题:

给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。

请你找出并返回只出现一次的那个数。

你设计的解决方案必须满足 O(log n) 时间复杂度和 O(1) 空间复杂度。

示例 1:

输入: nums = [1,1,2,3,3,4,4,8,8]
输出: 2
示例 2:

输入: nums =  [3,3,7,7,10,11,11]
输出: 10

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-element-in-a-sorted-array

普通解法

这道题其实很简单,就是跳两下判断下一个数是否和当前数相同就好了。

class Solution {
    public int singleNonDuplicate(int[] nums) {
        // 原来我就是单一元素 22.2.14简记
        for(int i = 0; i < nums.length-1; i += 2){
            if(nums[i] != nums[i+1]){
                return nums[i];
            }
        }
        return nums[nums.length - 1];
    }
}

异或解法

做完奔着题解区看看别人的想法,没想到有个异或的题解是真滴帅。

class Solution {
    public int singleNonDuplicate(int[] nums) {
        // 原来我就是单一元素 22.2.14简记
        int ans = 0;
        for (int i = 0; i < nums.length; i++){
            ans ^= nums[i];
        }            
        return ans;
    }
}

异或概念

一开始我也是不清楚异或的概念的,于是上网查了下:

异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1)

逻辑异或运算怎么算

demo:

0011
1110 异或运算后是:

1101

简单说就是两个数不相等为1,相等为0

简单的说完了异或的概念,在解析下是如何把刚才的单一元素解出来的。

如[1,1,2,3,3]

// 初始值ans给个0,1的二进制是0001,于是:
0000 ^
0001 = 0001


// 1和1在异或运算,就变回0了
0001^
0001 = 0000


// 0和1做运算,变成1
0001 ^
0010 = 0010


// 2的二进制是0011,异或变成1
0010 ^ 
0011 = 0001


// 最后异或运算成为2
0001 ^ 
0011 = 0010

那么我们最后返回的是nums[ans],也就是在第二位的数,正确的返回了我们想要的单一元素。

异或运算多应用于加密、寻找单一元素上,这里不在多讲,感兴趣的朋友可以自己拓展。

HashMap是如何使用异或的呢

学会异或运算后,突然想起了曾经在HashMap的源码中看到过使用,只不过当时懵懵懂懂没深入研究,那么就现在乘胜追击吧~

在HashMap中,用hash算法或得存取位置无疑是最重要的一步,而在hash算法中就用到了异或运算,我们来看看这里是如何巧妙设计的。

源码

方法一:
static final int hash(Object key) {   //jdk1.8 & jdk1.7
     int h;
     // h = key.hashCode() 为第一步 取hashCode值
     // h ^ (h >>> 16)  为第二步 高位参与运算
     return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
方法二:
static int indexFor(int h, int length) {  //jdk1.7的源码,jdk1.8没有这个方法,但是实现原理一样的
     return h & (length-1);  //第三步 取模运算
}

流程图解

来源美团技术团队

img

思考

首先想明白,为什么已经用hashCode()方法取到哈希值了,还需要继续 ^ (h >>> 16)。

这是因为只用后四位数进行运算,非常容易产生大量的hash碰撞,于是将高16位右移,并且异或计算。

那么打破砂锅问到底,为什么用异或^

我查阅了挺多文章,都说是右移16位异或可以同时保留高16位于低16位的特征。并且如果采用&运算计算出来的值会向1靠拢,采用|运算计算出来的值会向0靠拢。用异或则能让01能更随机的出现,而不趋向某一边。

一开始不太懂,后来想到作者的想法应该是:

让哈希后的结果更均匀的分布,减少哈希碰撞,提升hashmap的运行效率

就想到了,保留两边的特征反而能让hash值更离散或者说随机,尽可能的减少了hash碰撞。

参考

主要参考:

https://tech.meituan.com/2016/06/24/java-hashmap.html

本章源码解析参考:

https://blog.csdn.net/dam454450872/article/details/102965920

https://blog.csdn.net/weixin_43842753/article/details/105927912

https://tech.meituan.com/2016/06/24/java-hashmap.html

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:48:42  更:2022-03-24 00:52:47 
 
开发: 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/26 11:26:12-

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