两数之和

题目

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素

示例:

给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

Java:

方法一:暴力法

暴力法很简单,就是用两遍循环的方式遍历nums

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");
}
}

复杂度分析:

  • 时间复杂度:O(n^2)

    • 对于每个元素,我们试图通过遍历数组的其余部分来寻找它所对应的目标元素,这将耗费 O(n) 的时间。因此时间复杂度为 O(n^2)
  • 空间复杂度:O(1)

方法二:两遍哈希表

为了对运行时间复杂度进行优化,我们需要一种更有效的方法来检查数组中是否存在目标元素。如果存在,我们需要找出它的索引。保持数组中的每个元素与其索引相互对应的最好方法是什么?哈希表

通过以空间换取速度的方式,我们可以将查找时间从 O(n) 降低到 O(1)。哈希表正是为此目的而构建的,它支持以 近似 恒定的时间进行快速查找。我用“近似”来描述,是因为一旦出现冲突,查找用时可能会退化到 O(n)。但只要你仔细地挑选哈希函数,在哈希表中进行查找的用时应当被摊销为 O(1)

一个简单的实现使用了两次迭代。在第一次迭代中,我们将每个元素的值和它的索引添加到表中。然后,在第二次迭代中,我们将检查每个元素所对应的目标元素(target - nums[i]target−nums[i])是否存在于表中。注意,该目标元素不能是 nums[i]nums[i] 本身!

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");
}
}

复杂度分析:

  • 时间复杂度:O(n)

    • 我们把包含有 n 个元素的列表遍历两次。由于哈希表将查找时间缩短到 O(1),所以时间复杂度为 O(n)
  • 空间复杂度:O(n)

    • 所需的额外空间取决于哈希表中存储的元素数量,该表中存储了 n个元素

方法三:一遍哈希表

事实证明,我们可以一次完成。在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回

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");
}
}

复杂度分析:

  • 时间复杂度:O(n)

    • 我们只遍历了包含有 n 个元素的列表一次。在表中进行的每次查找只花费 O(1)的时间
  • 空间复杂度:O(n)

    • 所需的额外空间取决于哈希表中存储的元素数量,该表最多需要存储 n 个元素

C++:

方法一:暴力法

暴力法很简单,就是用两遍循环的方式遍历nums

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int i,j;
for(i=0;i<nums.size();++i){
for(j=i+1;j<nums.size();++j){
if(nums[i]+nums[j]==target){
return {i,j};
}
} }
return {i,j};
}
};

复杂度分析:

  • 时间复杂度:O(n^2)

    对于每个元素,我们试图通过遍历数组的其余部分来寻找它所对应的目标元素,这将耗费 O(n) 的时间。因此时间复杂度为 O(n^2)

  • 空间复杂度:O(1)

方法二:两遍哈希法

该方法用map实现,map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int,int> a;//建立hash表存放数组元素
vector<int> b(2,-1);//存放结果
for(int i=0;i<nums.size();i++){
a.insert(map<int,int>::value_type(nums[i],i));
}
for(int i=0;i<nums.size();i++){
if(a.count(target-nums[i])>0&&(a[target-nums[i]]!=i)){
//判断是否找到目标元素且目标元素不能是本身
b[0]=i;
b[1]=a[target-nums[i]];
break;
}
}
return b;
};
};

复杂度分析:

  • 时间复杂度:O(n)

    • 我们把包含有 n 个元素的列表遍历两次。由于哈希表将查找时间缩短到 O(1),所以时间复杂度为 O(n)
  • 空间复杂度:O(n)

    • 所需的额外空间取决于哈希表中存储的元素数量,该表中存储了 n个元素

方法三:一遍哈希法

在两遍哈希方法上进行改进:在进行迭代并将元素插入到表中的同时,我们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。如果它存在,那我们已经找到了对应解,并立即将其返回

class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int,int> a;//提供一对一的hash
vector<int> b(2,-1);//用来承载结果,初始化一个大小为2,值为-1的容器b
for(int i=0;i<nums.size();i++){
if(a.count(target-nums[i])>0){
b[0]=a[target-nums[i]];
b[1]=i;
break;
}
a[nums[i]]=i;//反过来放入map中,用来获取结果下标
}
return b;
};
};
  • 时间复杂度:O(n)

    • 我们只遍历了包含有 n 个元素的列表一次。在表中进行的每次查找只花费 O(1)的时间
  • 空间复杂度:O(n)

    • 所需的额外空间取决于哈希表中存储的元素数量,该表最多需要存储 n 个元素

Python:

方法一:暴力法

用 Python 中 list 的相关函数求解

解题关键主要是想找到 num2 = target - num1,是否也在 list 中,那么就需要运用以下两个方法:

num2 in nums,返回 True 说明有戏

nums.index(num2),查找 num2 的索引

def twoSum(nums, target):
lens = len(nums)
j=-1
for i in range(lens):
if (target - nums[i]) in nums:
if (nums.count(target - nums[i]) == 1)&(target - nums[i] == nums[i]):#如果num2=num1,且nums中只出现了一次,说明找到是num1本身。
continue
else:
j = nums.index(target - nums[i],i+1)#index(x,i+1)是从num1后的序列后找num2
break
if j>0:
return [i,j]
else:
return []

方法二:

执行通过,不过耗时较长,共 1636ms。

在方法一的基础上,优化解法。想着,num2 的查找并不需要每次从 nums 查找一遍,只需要从 num1 位置之前或之后查找即可。但为了方便 index 这里选择从 num1 位置之前查找

def twoSum(nums, target):
lens = len(nums)
j=-1
for i in range(1,lens):
temp = nums[:i]
if (target - nums[i]) in temp:
j = temp.index(target - nums[i])
break
if j>=0:
return [j,i]

执行通过,耗时缩短一半多,共 652ms。

方法三:字典模拟哈希

这种办法相较于方法一其实就是字典记录了 num1 和 num2 的值和位置,而省了再查找 num2 索引的步骤

def twoSum(nums, target):
hashmap={}
for ind,num in enumerate(nums):
hashmap[num] = ind
for i,num in enumerate(nums):
j = hashmap.get(target - num)
if j is not None and i!=j:
return [i,j]

通过字典的方法,查找效率快很多,执行速度大幅缩短,共 88ms。

方法四:

类似方法二,不需要 mun2 不需要在整个 dict 中去查找。可以在 num1 之前的 dict 中查找,因此就只需要一次循环可解决

def twoSum(nums, target):
hashmap={}
for i,num in enumerate(nums):
if hashmap.get(target - num) is not None:
return [i,hashmap.get(target - num)]
hashmap[num] = i #这句不能放在if语句之前,解决list中有重复值或target-num=num的情况

​ hashmap[num] = i #这句不能放在if语句之前,解决list中有重复值或target-num=num的情况

不过方法四相较于方法三的运行速度没有像方法二相较于方法一的速度提升。运行速度在 70ms 多

LeetCode题解001:两数之和的更多相关文章

  1. leetcode题解:两数之和

    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元 ...

  2. LeetCode 题解 | 1. 两数之和

    题目描述: 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [2, 7, 11, 15], t ...

  3. Leetcode 001. 两数之和(扩展)

    1.题目要求 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 2.解法一:暴力法(for*for,O(n*n)) ...

  4. 每日一道 LeetCode (1):两数之和

    引言 前段时间看到一篇刷 LeetCode 的文章,感触很深,我本身自己上大学的时候,没怎么研究过算法这一方面,导致自己直到现在算法都不咋地. 一直有心想填补下自己的这个短板,实际上又一直给自己找理由 ...

  5. Leetcode系列之两数之和

    Leetcode系列之两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标.你可以假设每种输入只会对应一个答案.但是,你 ...

  6. leetcode刷题--两数之和(简单)

    一.序言 第一次刷leetcode的题,之前从来没有刷题然后去面试的概念,直到临近秋招,或许是秋招结束的时候才有这个意识,原来面试是需要刷题的,面试问的问题都是千篇一律的,只要刷够了题就差不多了,当然 ...

  7. LeetCode :1.两数之和 解题报告及算法优化思路

    最近开始重拾算法,在 LeetCode上刷题.顺便也记录下解题报告以及优化思路. 题目链接:1.两数之和 题意 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 ...

  8. LeetCode 167:两数之和 II - 输入有序数组 Two Sum II - Input array is sorted

    公众号: 爱写bug(ID:icodebugs) 给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值 index1 和 index2,其中 index ...

  9. LeetCode | No.1 两数之和

    题目描述: Given an array of integers, return indices of the two numbers such that they add up to a speci ...

  10. leetCode刷题 | 两数之和

    两数之和: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数 ...

随机推荐

  1. SpringCloud的入门学习之Eureka(高可用注册中心HA)构建Provider服务、Consumer服务

    1.在高可用的Eureka注册中心中构建provider服务. 使用springboot的多环境配置,来搭建Eureka的高可用集群式部署.由于使用的是maven构建的springboot项目,所以首 ...

  2. python distutils 基本打包与发布

    distutils 实现对package 包的发布 import math def showMsg(a): return a * a * a a = 10 print('%d 的三次方是 %d' % ...

  3. Reuse Implemented Functionality 重用实现功能

    A default XAF solution contains one platform-agnostic (shared) module and platform-dependent modules ...

  4. NumPy数据的归一化

    数据的归一化 首先我们来看看归一化的概念: 数据的标准化(normalization)和归一化 数据的标准化(normalization)是将数据按比例缩放,使之落入一个小的特定区间.在某些比较和评价 ...

  5. QT无窗口状态下对键盘事件的监听

    Question:最近在搞linux下的一个客户端项目,需要接收键盘事件,但是又不能有界面,这种情况怎么处理呢? int main(int argc, char *argv[]) { QApplica ...

  6. 团队展示&选题

    团队展示 1.队名:螺旋升天队 2.队员学号: 李光证 3117004660 (队长) 卢俊杰 3117004662 吴子昊 3117004671 陈浩民 3117004646 陈俊铭 3117004 ...

  7. Hive表的几种存储格式

    Hive的文件存储格式: textFile textFile为默认格式 存储方式:行存储 缺点:磁盘开销大:数据解析开销大:压缩的text文件,hive无法进行合并和拆分 sequencefile 二 ...

  8. 机器学习--用PCA算法实现三维样本降到二维

    对于维数比较多的数据,首先需要做的事就是在尽量保证数据本质的前提下将数据中的维数降低.降维是一种数据集预处理技术,往往在数据应用在其他算法之前使用,它可以去除掉数据的一些冗余信息和噪声,使数据变得更加 ...

  9. 2019面向对象程序设计(Java) 第16周学习指导及要求

    2019面向对象程序设计(Java)第16周学习指导及要求 (2019.12.13-2019.12.16) 学习目标 (1) 掌握Java应用程序的打包操作: (2) 掌握线程概念: (3) 掌握线程 ...

  10. acWing 825. 排队购物

    题目描述苏西小朋友和她的妈妈正在超市里购物,看着收银处排着的长长的队伍,她就想如何能够提高整体的服务质量呢? 已知,现在有n个人正在排队等待结账,每个人结账所花的时间都可能是不同的,第 i 个人的结账 ...