Leetcode1——两数之和

题目分类:数组、哈希表的应用

1. 题目描述

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

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。(原题网址:https://leetcode-cn.com/problems/two-sum/)

示例1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例3

输入:nums = [3,3], target = 6
输出:[0,1]

2. 解法

2.1 暴力匹配

这个应该是最容易想到的解法了,既然答案说了一定只有一个组合成立,我们只要使用两个for循环,遍历一下nums数组,如果nums[i] + nums[j] == target,那么就输出对应的i和j即可。

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[i] + nums[j] == target) {
return new int[] {i, j};
}
}
}
return new int[0];
}
}

注意:有返回值的Java方法要求最后一定有确定的返回值,即你的return语句不能全部都在条件分支里面(万一分支条件均不满足,那么就出错了),所以在最后一行也会放上一个return语句,像本题我们放上一个长度为0的数组(代表没有找到结果),但是题中描述说必有一个唯一解,实际上这个语句永远不会运行,若是不加则会报错哦。

复杂度分析

假设问题的规模为n(这里即是数组长度为n)

我们使用了两个for循环,最坏的情况是比较全部元素后才发现目标元素,即比较次数为\(\frac{n(n-2)}{2}\),那么时间复杂度为\(O(n^2)\)。额外存储空间为常数,故空间复杂度为\(O(1)\)。

能不能将时间复杂度降低一些呢?首先来分析一下暴力破解法,其相当于选定nums[i]再从i到n-1中选取target - nums[i],而这个寻找target - nums[i]的操作时间复杂度是\(O(n)\),这是因为我们无法直接确定target - nums[i]的位置,需要逐个比较确定。

2.2 哈希表解法

暴力破解法的困难可以用HashMap来解决,我们可以将nums[i]——i以键值对的形式存储在哈希表中,这样就可以以O(1)的时间复杂度找到target - nums[i]。

2.2.1 一个笨笨的代码

class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hash = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
hash.put(nums[i], i);
}
for (int i = 0; i < nums.length; i++) {
while (hash.containsKey(target - nums[i]) &&
(hash.get(target - nums[i]) != i)) {
return new int[] {hash.get(target - nums[i]), i};
}
}
return new int[0];
}
}

代码分析

首先将全部键值对存到哈希表中,这个操作时间复杂度为O(n)。接下来使用一个for循环来遍历nums,注意,这里内层仍选用了一个while循环!这个while循环是为了避免在哈希表查找到i(也就是当前遍历到的)的值,这样就相当于使用了一个元素多次。所以,当查找到的数组下标为仍为i时,需要重新查找一下,找到除了当前元素的其它target - nums[i]。这个while最多只会运行2次,所以不会是时间复杂度为\(O(n^2)\),该步骤时间复杂度仍为O(n)。故整体的时间复杂度仍为O(n)。时间复杂度大大降低啦!但是代价是空间复杂度飙升到O(n)。

2.2.2 更聪明的代码

在使用哈希表时,我们先将nums[i]和i全部存到哈希表中再进行查找,能不能把代码进一步优化一下呢?而且上一组代码的while使用有些丑陋,下面给出更优雅的实现(leetcode官方题解

class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
for (int i = 0; i < nums.length; ++i) {
if (hashtable.containsKey(target - nums[i])) {
return new int[]{hashtable.get(target - nums[i]), i};
}
hashtable.put(nums[i], i);
}
return new int[0];
}
}

官方的解法通过在寻找target - nums[i]后构造哈希表的方式,有效避免了哈希表查到自己的麻烦(笨笨的解法),而且缩短了代码行数。

如何避免麻烦的解释:在查找target - nums[i]时,nums[i]的键值对未存到哈希表中,也就是此时只能查到数组下标不是i但值为target - nums[i]的元素。而且只用了一个for循环就解决了问题,十分简洁。

3. 总结

本题虽然很简单,但还是有着许多解法的,本题除了以上两种解法还可以先将数组排序(不妨设选用的是平均时间复杂度为O(nlogn)的排序,例如快速排序、归并排序),在遍历有序数组的时候利用二分查找快速查找target - nums[i],整体平均时间复杂度为O(nlogn),这同样也是一种很好的思路。在学习算法的时候也是一样,在解出题目后要分析其时间和空间复杂度,看看能否优化。

Leetcode1——两数之和 详细解析的更多相关文章

  1. LeetCode1——两数之和

    最近在家拧三阶魔方,把初级的玩法掌握了,也就是可以还原六个面了,速度不快,但是也很兴奋.三阶魔方的初级玩法按照套路拧就可以了,每一步需要完成的任务,该步骤转动的方法基本都是固定的,而且变化也并不是特别 ...

  2. Leetcode-1.两数之和

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

  3. [Swift]LeetCode1 .两数之和 | Two Sum

    Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...

  4. LeetCode1.两数之和 JavaScript

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

  5. Leetcode1.两数之和——简洁易懂

    > 简洁易懂讲清原理,讲不清你来打我~ 输入一个数组和一个整数,从数组中找到两个元素和为这个整数,输出下标![在这里插入图片描述](https://img-blog.csdnimg.cn/img ...

  6. 前端与算法 leetcode 1. 两数之和

    目录 # 前端与算法 leetcode 1. 两数之和 题目描述 概要 提示 解析 解法一:暴力法 解法二:HashMap法 算法 传入[1, 2], [11, 1, 2, 3, 2]的运行结果 执行 ...

  7. LeetCode_#1_两数之和 Two Sum_C++题解

    1. 两数之和 Two Sum 题目描述 Given an array of integers, return indices of the two numbers such that they ad ...

  8. 【LeetCode】 两数之和 twoSum

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

  9. 给定数组A,大小为n,现给定数X,判断A中是否存在两数之和等于X

    题目:给定数组A,大小为n,现给定数X,判断A中是否存在两数之和等于X 思路一: 1,先采用归并排序对这个数组排序, 2,然后寻找相邻<k,i>的两数之和sum,找到恰好sum>x的 ...

随机推荐

  1. 【用户状态】详细解读Oracle用户ACCOUNT_STATUS的九种状态

    转至:http://blog.itpub.net/519536/viewspace-672276/ DBA_USERS视图中ACCOUNT_STATUS记录的用户的当前状态,一般情况下在使用的正常用户 ...

  2. docker:打包node+npm+pm2运行环境镜像

    最近公司有一个外包项目需要在不能连外网的情况下部署node项目到甲方公司内部.直接使用node官网的安装包可以获得node运行环境,但像pm2这种工具要离线装就会比较费劲,所以最终选择了使用docke ...

  3. Mysql基础学习第二天

    Mysql基础学习第二天 函数 函数:是指一段可以直接被另一段程序调用的程序或代码. 字符串函数 数值函数 日期函数 流程函数 字符串函数 MySQL内置很多字符串函数,常用的几个如下: 函数 功能 ...

  4. PyTorch深度学习实践——反向传播

    反向传播 课程来源:PyTorch深度学习实践--河北工业大学 <PyTorch深度学习实践>完结合集_哔哩哔哩_bilibili 目录 反向传播 笔记 作业 笔记 在之前课程中介绍的线性 ...

  5. 获取HTML中所有图片的 URL

    /// <summary> /// 获取HTML中所有图片的 URL /// </summary> /// <param name="strHtml" ...

  6. Python中的os.environ系列的用法

    >>> import os >>> os.environ.keys() ['LC_NUMERIC', 'GOPATH', 'GOROOT', 'GOBIN', 'L ...

  7. php 23种设计模型 - 抽象工厂模式

    抽象工厂模式(AbstractFactory) 抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创 ...

  8. CF258D题解

    太厉害啦 首先做期望题最不能忘记的就是期望的线性性. 所以我们直接将全局逆序对对数拆成两个数其中一个比另一个大的期望(概率),设为 \(f[i][j]\),初值为 \([a_i>b_j]\). ...

  9. LGP7884题解

    是的,这是一篇使用 min25 筛的题解... 本题解参考command_block大佬的博客,代码是对其在 LOJ 上的提交卡常后写出来的. ML 板子把数据开到 \(10^{13}\) 速度还和供 ...

  10. 女朋友问我深浅copy到底是什么?

    深浅拷贝 列表存放值的时候,是先申请一块内存空间,存放索引和内存地址的对应关系,其实通俗的来说列表内不存真正的值,是一种间接存放的对应关系: 列表内存不可变类型的数据 就比如说,如果现在将L列表索引0 ...