LeetCode 热题 HOT 100(00,两数之和)
LeetCode 热题 HOT 100(00,两数之和)
不够优秀,发量尚多,千锤百炼,方可成佛。
算法的重要性不言而喻,无论你是研究者,还是最近比较火热的IT 打工人,都理应需要一定的算法能力,这也是面试的必备环节,算法功底的展示往往能让面试官眼前一亮,这也是在大多数竞争者中脱颖而出的重要影响因素。
然而往往大多数人比较注重自身的实操能力,着重于对功能的实现,却忽视了对算法能力的提高。有的时候采用不同的算法来解决同一个问题,运行效率相差还是挺大的,毕竟我们最终还是需要站在客户的角度思考问题嘛,能给用户带来更加极致的体验当然再好不过了。
万法皆空,因果不空。Taoye之前也不怎么情愿花费太多的时间放在算法上,算法功底也是相当的薄弱。这不,进入到了一个新的学习阶段,面对导师的各种“严刑拷打”和与身边人的对比,才意识到自己“菜”的事实。
步入11月,也开学一个多月了,所以想开始记录下刷算法题的过程,也算是对自己的一个督促。初步的目标是一到两天更新一期,每周至少更新四期。
题目:两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
思路
这是LeetCode 热题 HOT 100中的第一道题,难度级别属于简单,也是每一位刷题er的入门必经之题,它的地位就等同于英语单词表中的abandon,算法记录的第一天就拿它开刀吧。
按照对这道题的正常思维,直接通过两层循环、一次判断就能完成任务,也就是我们常常提到的暴力解题,相关Python代码如下:
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
# 两层循环
for index_1, num_1 in enumerate(nums):
for index_2, num_2 in enumerate(nums):
# 一次判断
if (num_1 + num_2) == target and index_1 != index_2:
return [index_1, index_2]
return []
但是,要想有效提高自己的算法能力,还是有必要培养自己的“不正常”思维的。毫无疑问,上述暴力破解自然能够满足题意的要求,但在我们的业务功能已经全部实现的情况下,就不得不考虑代码的执行效率问题了,这也就凸显出了算法的重要性。
暴力解题的时间复杂度为,空间复杂度为。但我们可以通过哈希表(key-value键值对)来降低算法的时间复杂度。
对于遍历的每一个,我们都计算其对应的的值,判断值是否在哈希表中,如果在的话说明已经匹配成功,直接返回值对应的索引。反之,我们需要将当前遍历的添加到哈希表中,为x
,为在列表中所对应的索引。
如此一来,最多只需要遍历一次列表即可查找到目标值的索引,其时间复杂度为,空间复杂度为。相对于暴力解题来讲,采用的是以空间换时间的策略。
在计算机发展初期,内存是极为奢侈的,内存的使用都是要经过慎重考虑的。而在今日,曾今的内存问题已经不再是问题了,有的时候,站在客户的角度来讲,我们通常会情愿采用以空间换时间的策略。
代码实现
- Python
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
hashtable = dict()
for index, num in enumerate(nums):
if (target - num) in hashtable: # 补集在哈希表中,直接返回目标索引
return [hashtable.get(target - num), index]
hashtable[num] = index # 补集不在哈希表中,添加到hashtable
return []
- C++
官方
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hashtable;
for (int i = 0; i < nums.size(); ++i) {
auto it = hashtable.find(target - nums[i]); // find查询关键字,没找到则返回end迭代器
if (it != hashtable.end()) { // 如果找到了目标关键字
return {it->second, i}; // 返回索引
}
hashtable[nums[i]] = i; // 没找到,则将关键字添加到hashtable
}
return {};
}
};
在C++中,通过hashtable作为底层实现的主要有两个容器
- unordered_set,就是一个单类型数据的set集合,内部的元素不能重复,比如名字set集合,
name_set={"taoye", "taotao"}
- unordered_map,一个key-value键值对型的容器,比如id、姓名类型的map,
info_map={1: "taoye", 2: "taotao"}
// 在unordered_map中,find用于进行关键字的查询,找到则返回指向关键字的迭代器,否则返回指向end的迭代器
iterator find (const key_type& k);
我是Taoye,研究生在读。爱专研,爱分享,热衷于各种技术,学习之余喜欢下象棋、听音乐、聊动漫,希望借此一亩三分地记录自己的成长过程以及生活点滴,也希望能结实更多志同道合的圈内朋友,更多内容欢迎来访微信公主号:玩世不恭的Coder。
推荐阅读:
Taoye渗透到一家黑平台总部,背后的真相细思极恐
《大话数据库》-SQL语句执行时,底层究竟做了什么小动作?
那些年,我们玩过的Git,真香
基于Ubuntu+Python+Tensorflow+Jupyter notebook搭建深度学习环境
网络爬虫之页面花式解析
手握手带你了解Docker容器技术
一文详解Hexo+Github小白建站
打开ElasticSearch、kibana、logstash的正确方式