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. 【C#基础概念】Ineterface 接口的设计原则

    接口设计方式 自顶向下 (如图所示),自底向上(发现类需要结构了就声明一个接口). 接口的作用 用来解耦.继承 接口的本质

  2. Linux Shell 变量自加

    转至:https://blog.csdn.net/dj0379/article/details/50946398/ declare -i iv=$svnvlet iv+=1shell中变量自增的实现方 ...

  3. 60天shell脚本计划-12/12-渐入佳境

    --作者:飞翔的小胖猪 --创建时间:2021年3月23日 --修改时间:2021年3月27日 说明 每日上传更新一个shell脚本,周期为60天.如有需求的读者可根据自己实际情况选用合适的脚本,也可 ...

  4. node-java的使用及源码分析

    上篇文章简单提了下node调用java的方法但也只属于基本提了下怎么输出helloworld的层度,这次将提供一些案例和源码分析让我们更好地了解如何使用node-java库. 前置知识: 1.桥接模式 ...

  5. pyinstaller:各种错误及解决方法

    1.DLL load failed 说明没有找到某个DLL 解决方法: 在 D:\Anaconda\Anaconda3\Library\bin 下找到缺失的DLL,复制到dist下 2.No modu ...

  6. consul-常用命令

    1.consul 是B/C架构.服务端和客户端包是一样的.差别在于启动时候的参数. --客户端 ./consul agent -join=172.29.2.65:8301 -bind=172.29.3 ...

  7. shell日常积累

    Linux shell脚本中shift的用法说明 https://blog.csdn.net/zhu_xun/article/details/24796235

  8. k8s-coredns 介绍和部署

    1.k8s-coredns 实现了集群内部通过服务名进行可以访问.添加服务后,会自动添加一条解析记录 cat /etc/resolv.conf nameserver 10.0.0.2 search k ...

  9. java中如何将嵌套循环性能提高500倍

    java中如何将嵌套循环性能提高500倍 转载请注明出处https://www.cnblogs.com/funnyzpc/p/15975882.html 前面 似乎上一次更新在遥远的九月份,按照既定的 ...

  10. LeetCode-059-螺旋矩阵 II

    螺旋矩阵 II 题目描述:给你一个正整数 n ,生成一个包含 1 到 \(n^{2}\) 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix . 示例说明请见LeetCode ...