图解经典题的多种解法:「哈希表」&「位数统计」&「DFA」|Java 刷题打卡

简介: 图解经典题的多种解法:「哈希表」&「位数统计」&「DFA」|Java 刷题打卡

题目描述



这是 LeetCode 上的 137. 只出现一次的数字 II


Tag : 「哈希表」、「位运算」


给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。


请你找出并返回那个只出现了一次的元素。


示例 1:


输入:nums = [2,2,3,2]
输出:3
复制代码


示例 2:


输入:nums = [0,1,0,1,0,1,99]
输出:99
复制代码


提示:


  • 1 <= nums.length <= 3 * 10410^4104
  • -2312^{31}231 <= nums[i] <= 2312^{31}231 - 1
  • nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次


进阶:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?


哈希表



一个朴素的做法是使用「哈希表」进行计数,然后将计数为 111 的数字进行输出。


哈希表以「数值 : 数值出现次数」形式进行存储。


代码:


class Solution {
    public int singleNumber(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int x : nums) {
            map.put(x, map.getOrDefault(x, 0) + 1);
        }
        for (int x : map.keySet()) {
            if (map.get(x) == 1) return x;
        }
        return -1;
    }
}
复制代码


  • 时间复杂度:O(n)O(n)O(n)
  • 空间复杂度:O(n)O(n)O(n)


位数统计



哈希表解法的空间复杂度是 O(n)O(n)O(n) 的,而题目的【进阶】部分提到应当使用常数空间来做。


其中一个比较容易想到的做法,是利用 intintint 类型固定为 323232 位。


使用一个长度为 323232 的数组 cnt[]cnt[]cnt[] 记录下所有数值的每一位共出现了多少次 111,再对 cnt[]cnt[]cnt[] 数组的每一位进行 modmodmod333 操作,重新拼凑出只出现一次的数值。


举个 🌰,考虑样例 [1,1,1,3]111333 对应的二进制表示分别是 00..00100..011,存入 cnt[]cnt[]cnt[] 数组后得到 [0,0,...,0,1,4]。进行 modmodmod333 操作后得到 [0,0,...,0,1,1],再转为十进制数字即可得「只出现一次」的答案 333


代码:


class Solution {
    public int singleNumber(int[] nums) {
        int[] cnt = new int[32];
        for (int x : nums) {
            for (int i = 0; i < 32; i++) {
                if (((x >> i) & 1) == 1) {
                    cnt[i]++;
                }
            }
        }
        int ans = 0;
        for (int i = 0; i < 32; i++) {
            if ((cnt[i] % 3 & 1) == 1) {
                ans += (1 << i);
            }
        }
        return ans;
    }
}
复制代码


  • 时间复杂度:O(n)O(n)O(n)
  • 空间复杂度:O(1)O(1)O(1)


DFA



如果我们考虑「除了某个元素只出现一次以外,其余每个元素均出现两次」的情况,那么可以使用「异或」运算。


利用相同数异或为 0 的性质,可以帮助我们很好实现状态切换:


网络异常,图片无法展示
|


本题是考虑「除了某个元素只出现一次以外,其余每个元素均出现三次」的情况,那么对应了「出现 0 次」、「出现 1 次」和「出现 2 次」三种状态,意味着至少需要两位进行记录,且状态转换关系为:


网络异常,图片无法展示
|


那么如何将上述 DFA 用表达式表示出来呢?有以下几种方法:


  1. 用「真值表」写出「逻辑函数表达式」可参考 这里,化简过程可以参考 卡诺图化简法
  2. 把结论记住(这是一道经典的 DFA 入门题)。
  3. 硬做,位运算也就那几种,不会「数字电路」也记不住「结论」,砸时间看着真值表不断调逻辑也是可以写出来的。


代码:


class Solution {
    public int singleNumber(int[] nums) {
        int one = 0, two = 0;
        for(int x : nums){
            one = one ^ x & ~two;
            two = two ^ x & ~one;
        }
        return one;
    }
}
复制代码


  • 时间复杂度:O(n)O(n)O(n)
  • 空间复杂度:O(1)O(1)O(1)


最后



这是我们「刷穿 LeetCode」系列文章的第 No.137 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先将所有不带锁的题目刷完。


在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。


为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…


在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

相关文章
|
2月前
|
存储 算法 安全
探究‘公司禁用 U 盘’背后的哈希表算法与 Java 实现
在数字化办公时代,信息安全至关重要。许多公司采取“禁用U盘”策略,利用哈希表算法高效管理外接设备的接入权限。哈希表通过哈希函数将设备标识映射到数组索引,快速判断U盘是否授权。例如,公司预先将允许的U盘标识存入哈希表,新设备接入时迅速验证,未授权则禁止传输并报警。这有效防止恶意软件和数据泄露,保障企业信息安全。 代码示例展示了如何用Java实现简单的哈希表,模拟公司U盘管控场景。哈希表不仅用于设备管理,还在文件索引、用户权限等多方面助力信息安全防线的构建,为企业数字化进程保驾护航。
|
2月前
|
存储 Java BI
java怎么统计每个项目下的每个类别的数据
通过本文,我们详细介绍了如何在Java中统计每个项目下的每个类别的数据,包括数据模型设计、数据存储和统计方法。通过定义 `Category`和 `Project`类,并使用 `ProjectManager`类进行管理,可以轻松实现项目和类别的数据统计。希望本文能够帮助您理解和实现类似的统计需求。
117 17
|
4月前
|
Java 编译器 程序员
Java面试高频题:用最优解法算出2乘以8!
本文探讨了面试中一个看似简单的数学问题——如何高效计算2×8。从直接使用乘法、位运算优化、编译器优化、加法实现到大整数场景下的处理,全面解析了不同方法的原理和适用场景,帮助读者深入理解计算效率优化的重要性。
60 6
|
7月前
|
算法 Java
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
LeetCode经典算法题:矩阵中省份数量经典题目+三角形最大周长java多种解法详解
87 6
|
7月前
|
存储 Java
数据结构中的哈希表(java实现)利用哈希表实现学生信息的存储
这篇文章通过Java代码示例展示了如何实现哈希表,包括定义结点类、链表类、数组存储多条链表,并使用简单的散列函数处理冲突,以及如何利用哈希表存储和查询学生信息。
数据结构中的哈希表(java实现)利用哈希表实现学生信息的存储
|
7月前
|
人工智能 算法 Java
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
LeetCode经典算法题:井字游戏+优势洗牌+Dota2参议院java解法
73 1
|
7月前
|
存储 算法 Java
LeetCode经典算法题:预测赢家+香槟塔java解法
LeetCode经典算法题:预测赢家+香槟塔java解法
97 1
|
7月前
|
算法 Java
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
79 0
|
7月前
|
存储 算法 Java
LeetCode初级算法题:两数之和+斐波拉契数列多种java解法
LeetCode初级算法题:两数之和+斐波拉契数列多种java解法
69 0
|
7月前
|
存储 算法 Java
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
58 0

热门文章

最新文章