LeetCode题解001:两数之和

两数之和

题目

给定一个整数数组 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 多

原文地址:https://www.cnblogs.com/MessiXiaoMo3334/p/11518008.html

时间: 2024-07-30 04:50:53

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

[leetcode题解]01两数之和

给定一个整数数组 nums?和一个目标值 target,请你在该数组中找出和为目标值的那?两个?整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元素. 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 分析 关键字:数组.查找.下标. 由于数组是无序的,查找必须要遍历,不能用二分查找,时间复杂度一般最小为O(n). 暴力解法:遍历

LeetCode 题解 | 1. 两数之和

题目描述: 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 方法一.暴力解法: 暴力法很简单,遍历每个元素 ,并查找是否存在一个值与 相等的目标元素. class Solution { public: vector<int> twoSum(vect

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

一.序言 第一次刷leetcode的题,之前从来没有刷题然后去面试的概念,直到临近秋招,或许是秋招结束的时候才有这个意识,原来面试是需要刷题的,面试问的问题都是千篇一律的,只要刷够了题就差不多了,当然你的基础也要扎实,毕竟在技术面的时候很容易露馅的. 所以奉劝各位还未毕业,在大三或大二的师弟师妹早点刷题,心里也有底气进入求职大军,毕竟大四开始刷题的话时间上有些太紧了,推荐刷题的话就是牛客和leetcode. 回归正题,这次记录的是leetcode刷的第一题--两数之和. 二.审题 审题真的很重要

LeetCode | No.1 两数之和

题目描述: Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice. 给定一个整数数组nums和一个目标值target,请你在该数

leetcode——Two Sum 两数之和(AC)

Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that

LeetCode算法题——两数之和(python)

两数之和: 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数.你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用.例如:给定 nums = [2, 7, 11, 15], target = 9.由nums[0] + nums[1] = 2 + 7 = 9,所以返回 [0, 1] 原文地址:http://blog.51cto.com/13921683/2318829

LeetCode【167. 两数之和 II - 输入有序数组】

这道题最开始想到的就是,两个for,target是两数之和,就可以target - numbers[i],比较是否有与后面数相等. class Solution { public int[] twoSum(int[] numbers, int target) { int i,j,s; int c = numbers.length; int[] t = new int[2]; for(i = 0;i <= c-1;i++) { s = target - numbers[i]; t[0] = i+1

leetcode刷题两数之和

给定一个整数数组 nums?和一个目标值 target,请你在该数组中找出和为目标值的那?两个?整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元素. 示例: 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/two-sum 两

Leetcode篇:两数之和

@author: ZZQ @software: PyCharm @file: addTwoNumbers.py @time: 2018/9/18 10:35 要求:给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. e.g.: 输入:(2 -> 4 -> 3) + (5 -> 6 -> 4) 输出:7 -> 0 -> 8 原因:342 + 465

leetcode中的两数之和(第一题:简单)

描述:给定一个整数数组和一个目标值,找出数组中和为目标值的 两个 数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用.示例:给定 nums = [2, 7, 11, 15], target = 9因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 题意:给一个整形的数,这个数在会在给定数组的两个位置数相加的和!这个和是指值的相加,不是数组的索引相加:如果在数组中有这样的两个数,要求返回两个数的索引(也就是数组的下标): 解法一:暴力方法:应用