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. vs2022 如何让.net库文件参与程序调试【可以.net库文件的源代码中设置断点,单步跟踪】

    由于.net core 是开源的.所以可以让.net库文件参与程序调试.具体vs2022配置如下 1.设置VS2022 加载程序数据文件(.pdb俗称符号文件) 1)选择工具>选项>调试& ...

  2. MSBuild 和项目文件

    Microsoft 生成引擎(MSBuild)项目文件位于生成和部署过程的核心. 本主题以 MSBuild 和项目文件的概念性概述开头. 它介绍了在处理项目文件时将遇到的关键组件,并通过一个示例来演示 ...

  3. Windows操作下各种工具常用快捷键

    目录 Windows快捷键 谷歌浏览器快捷键 Nodepad++快捷键 Mobaxterm快捷键 Markdown快捷键 Windows快捷键 Win + E打开文件系统 Win + L锁屏 谷歌浏览 ...

  4. (第二章第一部分)TensorFlow框架之文件读取流程

    本章概述:在第一章的系列文章中介绍了tf框架的基本用法,从本章开始,介绍与tf框架相关的数据读取和写入的方法,并会在最后,用基础的神经网络,实现经典的Mnist手写数字识别. 有四种获取数据到Tens ...

  5. Ribbon&OpenFeign配置使用

    目录 Ribbon 是什么 工作流程 怎么用 负载算法 官方提供算法 使用方法 自定义负载算法 在rule包下新建MyRule 修改自定义策略类RbRule 测试 OpenFeign 是什么 怎么用 ...

  6. Laravel 8 图片上传七牛云

    1.利用 composer 下载依赖包 composer require itbdw/laravel-storage-qiniu 2.打开 config 文件夹下的 app.php 文件,在 prov ...

  7. idea Alt+Insert:构造函数

    Alt+Insert:构造函数 包含参数: Constructor:全参构造 Getter:必须的 return 字段名 Setter:this 值 Getter and Setter:选择字段以生成 ...

  8. 在数据结构与算法中 传值方式(C语言)

    传值方式 前言 当初学顺序链表的时候,书上就出现了这样的语言,如下所示: Status InitList_Sq(SqList &L) { //构造一个空的线性表L. L.elem = (Ele ...

  9. 前端—我的第一篇博客 梦开始的地方(面向对象版tab栏)

    这是我的第一篇博客 博客生涯才开始 但是人生已经过去了二十个年头了 才开始弄这个 也没搞得太懂 我原本的想法是想搞个源代码上来 但是看了半天好像就只能传html源代码 那我还有css js的部分呢 我 ...

  10. python 生产数据表脚本

    # -*- coding: utf-8 -*-import re"""建立相关表的字段从源表创建指定的MySQL建表脚本"""# 目标表名称 ...