数组: 你还在用暴力法解 两数之和 吗? 力扣1

Posted 孤柒

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组: 你还在用暴力法解 两数之和 吗? 力扣1相关的知识,希望对你有一定的参考价值。

此专栏文章是对力扣上算法题目各种方法总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解.

目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), 毕竟算法不是做了一遍就能完全记住的. 所以本文适合已经知道解题思路和方法, 想进一步加强理解和记忆的朋友, 并不适合第一次接触此题的朋友(可以根据题号先去力扣看看官方题解, 然后再看本文内容).

关于本专栏所有题目的目录链接, 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击此链接. 导图中源码在文章最后.

博主在公众号 [一起学计算机]每日首发力扣算法, 欢迎关注公众号每日和博主一起刷题!

博主在 B站 同步更新了 算法视频讲解 和 其他文章/导图讲解, 更易于理解, 欢迎来看!

目录

0.导图整理

1.暴力法

2.两遍哈希表

3.一遍哈希表

4.哈希表中的循环和异议

5.java和Python中哈希表的差别

源码


0.导图整理

1.暴力法

暴力法的思想很简单, 就是两层循环: 一层用来遍历所有元素, 另一层用来寻找目标数.

但此题中的注意点是题目中的: 假设每种输入只会对应一个答案. 但是, 数组中同一个元素不能使用两遍.

每种输入只对应一个输出 也就是要求我们找到满足的元素直接返回就可以了, 并不需要再去找其他满足的元素, 这也为下面使用哈希表的方法提供了前提, 因为如果需要找到所有满足的元素, 那么哈希表的结构就不能满足要求了.

数组中同一个元素不能使用两遍 这个要求就是代码中标注重点的部分 j = i + 1; 的含义. 当遍历整个数组寻找 target - x 时, 需要注意到每一个位于 x 之前的元素都已经和 x 匹配过, 因此不需要再进行匹配. 而每一个元素不能被使用两次, x本身也不需要进行匹配, 所以只需要在 x 后面的元素中寻找 target - x, 也就是从i+1开始遍历.

2.两遍哈希表

暴力法使用了两层循环, 时间复杂度达到了O(n^2), 而使用哈希表就可以将寻找目标数的操作降为O(1), 直接降了一个量级, 具体过程如下: 

使用了两次迭代。在第一次迭代中, 将每个元素的值和它的索引添加到表中。然后, 在第二次迭代中, 检查每个元素所对应的目标元素(target−nums[i])是否存在于表中。注意, 该目标元素不能是 nums[i]本身!也就是 map.get(complement) != i 的含义.

3.一遍哈希表

对于上面方法还有一点优化, 就是将两次迭代合并到一次中完成, 先进行匹配, 再插入到哈希表中!

首先创建一个哈希表, 对于每一个 x, 首先查询哈希表中是否存在 target - x, 如果存在直接返回结果就可以了. 之后将 x 插入到哈希表中, 即可保证不会让 x 和自己匹配, 因为在匹配时, x还未插入到哈希表中.

这种优化对于时间复杂度没有太大影响, 但是代码看起来更简洁了.

4.哈希表中的循环和异议

对于使用哈希表的算法, 有人提出了异议, HashMap的containsKey里面还有一个循环, 也就还是O(n^2), map还增加了空间复杂度和开销, 综合来看还是暴力法最为有效, 但是这个观点也有点问题: 这个containsKey里的循环, 只有冲突了才会进入, 同时如果冲突频繁, 会改用getTreeNode方法去获取值, getTreeNode是从一棵红黑树中获取值, 时间复杂度顶多O(logN), 综合来看, 还是降低了时间复杂度. 对于红黑树感兴趣的朋友, 可以看博主的这篇思维导图.

5.java和Python中哈希表的差别

从上述代码可以看出, 两者对于哈希表的实现还是有很大的差别的.

首先java中的哈希表是用Map类实现的, 判断是否包含一个元素用的是 map.containsKey(Key) 函数, 获取 键 对应的 值 使用的是 map.get(Key) 函数, 插入到哈希表中使用的是 map.put(Key, Value)

但是在Python中直接使用它自带的数据类型 字典dict 就实现了哈希表的操作, 并不需要新建类, 而且相应的操作也非常简单, 几乎不需要通过其他函数来实现. 判断是否包含一个元素用的是 in, 获取 键 对应的 值 使用的是 hashtable[Key] 函数, 插入到哈希表中使用的是 hashtable[Key] = Value

仔细对比会发现, Python语法是真的简洁明了, 这也是博主喜欢Python的原因.

这里补充说明一下Python中的 enumerate(nums) 函数, 简单来说就是对nums数组中的所有数添加了下标, 它返回的是 由下标和数据构成的二元元组, 在Python的for循环中还是挺经常使用的函数.

源码

Python: 

# 暴力法
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i + 1, n):
                if nums[i] + nums[j] == target:
                    return [i, j]

        return []


# 一遍哈希表
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hashtable = dict()
        for i, num in enumerate(nums):
            if target - num in hashtable:
                return [hashtable[target - num], i]
            hashtable[nums[i]] = i
        return []

java: 

// 暴力法
class Solution {
    public int[] twoSum(int[] nums, int target) {
         for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[j] == target - nums[i]) {
                    return new int[] { i, j };
                }
            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

//两遍哈希表
class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            map.put(nums[i], i);
        }
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];
            if (map.containsKey(complement) && map.get(complement) != i) {
                return new int[] { i, map.get(complement) };
            }
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

//一遍哈希表
class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];
            if (map.containsKey(complement)) {
                return new int[] { map.get(complement), i };
            }
            map.put(nums[i], i);
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

感觉作者写的不错的, 别忘了点赞关注加收藏哦(一键三连)!你的支持会带给我极大的动力, 写出更多优秀文章!

文章到这里就结束了, 感谢你的认真观看, 为了感谢读者们, 我把我一直以来整理的各种计算机相关/考研相关精品思维导图/力扣算法讲解/面试资料/各种实用软件工具分享给大家(并且会持续更新哦!), 希望能够帮助到你们.

关注公众号 [一起学计算机] 点击 资源获取 即可获得所有资源, 包含的资源如下图, 其中具体资源的相关讲解和各种软件的使用可以查看下面相应的文章.

我的更多精彩文章链接, 欢迎查看

各种电脑/软件/生活/音乐/动漫/电影技巧汇总(你肯定能够找到你需要的使用技巧)

力扣算法刷题 根据思维导图整理笔记快速记忆算法重点内容(可在公众号和博主一起打卡学习哦)

经典动漫全集目录 精彩剧集

海贼王 动漫 全集目录 分章节 精彩打斗剧集 思维导图整理

火影忍者 动漫 全集目录 分章节 精彩打斗剧集 思维导图整理

死神 动漫 全集目录 分章节 精彩打斗剧集 思维导图整理

 

计算机专业知识 思维导图整理

最值得收藏的 Python 全部知识点思维导图整理, 附带常用代码/方法/库/数据结构/常见错误/经典思想(持续更新中)

最值得收藏的 C++ 全部知识点思维导图整理(清华大学郑莉版), 东南大学软件工程初试906科目

最值得收藏的 计算机网络 全部知识点思维导图整理(王道考研), 附带经典5层结构中英对照和框架简介

最值得收藏的 算法分析与设计 全部知识点思维导图整理(北大慕课课程)

最值得收藏的 数据结构 全部知识点思维导图整理(王道考研), 附带经典题型整理

最值得收藏的 人工智能导论 全部知识点思维导图整理(王万良慕课课程)

最值得收藏的 数值分析 全部知识点思维导图整理(东北大学慕课课程)

最值得收藏的 数字图像处理 全部知识点思维导图整理(武汉大学慕课课程)

红黑树 一张导图解决红黑树全部插入和删除问题 包含详细操作原理 情况对比

各种常见排序算法的时间/空间复杂度 是否稳定 算法选取的情况 改进 思维导图整理

人工智能课件  算法分析课件  Python课件  数值分析课件  机器学习课件 图像处理课件

考研相关科目 知识点 思维导图整理

考研经验--东南大学软件学院软件工程(这些基础课和专业课的各种坑和复习技巧你应该知道)

东南大学 软件工程 906 数据结构 C++ 历年真题 思维导图整理

东南大学 软件工程 复试3门科目历年真题 思维导图整理

最值得收藏的 考研高等数学 全部知识点思维导图整理(张宇, 汤家凤), 附做题技巧/易错点/知识点整理

最值得收藏的 考研线性代数 全部知识点思维导图整理(张宇, 汤家凤), 附带惯用思维/做题技巧/易错点整理

高等数学 中值定理 一张思维导图解决中值定理所有题型

考研思修 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研近代史 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研马原 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研数学课程笔记  考研英语课程笔记  考研英语单词词根词缀记忆  考研政治课程笔记

Python相关技术 知识点 思维导图整理

Numpy常见用法全部OneNote笔记     全部笔记思维导图整理

Pandas常见用法全部OneNote笔记     全部笔记思维导图整理

Matplotlib常见用法全部OneNote笔记  全部笔记思维导图整理

PyTorch常见用法全部OneNote笔记    全部笔记思维导图整理

Scikit-Learn常见用法全部OneNote笔记  全部笔记思维导图整理

Java相关技术/ssm框架全部笔记

Spring  springmvc  Mybatis  jsp

科技相关 小米手机

小米 红米 历代手机型号大全 发布时间 发布价格

常见手机品牌的各种系列划分及其特点

历代CPUGPU的性能情况和常见后缀的含义 思维导图整理

以上是关于数组: 你还在用暴力法解 两数之和 吗? 力扣1的主要内容,如果未能解决你的问题,请参考以下文章

力扣1两数之和(简单)

力扣1两数之和

力扣刷题记录——两数之和

力扣刷题记录——两数之和

力扣刷题记录——两数之和

力扣刷题记录——两数之和