小预告:文末有两份福利,记得看到最后哦~

2 Sum 这题是 Leetcode 的第一题,相信大部分小伙伴都听过的吧。

作为一道标着 Easy 难度的题,它真的这么简单吗?

我在之前的刷题视频里说过,大家刷题一定要吃透一类题,为什么有的人题目做着越来越少,有的人总觉得刷不完的题,就是因为没有分类吃透。

单纯的追求做题数量是没有意义的,Leetcode 的题目只会越来越多,就像高三时的模考试卷一样做不完,但分类总结,学会解决问题的方式方法,才能遇到新题也不手足无措。

2 Sum

这道题题意就是,给一个数组和一个目标值,让你在这个数组里找到两个数,使得它俩之和等于这个目标值的。

比如题目中给的例子,目标值是 9,然后数组里 2 + 7 = 9,于是返回 2 和 7 的下标。

方法一

在我多年前还不知道时空复杂度的时候,我想这还不简单嘛,就每个组合挨个试一遍呗,也就是两层循环。

后来我才知道,这样时间复杂度是很高的,是 O(n^2);但另一方面,这种方法的空间复杂度最低,是 O(1)

所以,面试时一定要先问面试官,是希望优化时间还是优化空间

一般来说我们追求优化时间,但你不能默认面试官也是这么想的,有时候他就是想考你有没有这个意识呢。

如果一个方法能够兼具优化时间和空间那就更好了,比如斐波那契数列这个问题中从递归到 DP 的优化,就是时间和空间的双重优化,不清楚的同学后台回复「递归」快去补课~

我们来看下这个代码:

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[]{-1, -1};
    }
}
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

喏,这速度不太行诶。

方法二

那在我学了 HashMap 这个数据结构之后呢,我又有了新的想法。

HashMap 或者 HashSet 的最大优势就是能够用 O(1) 的时间获取到目标值,那么是不是可以优化方法一的第二个循环呢?

有了这个思路,假设当前在看 x,那就是需要把 x 之前或者之后的数放在 HashSet 里,然后看下 target - x 在不在这个 hashSet 里,如果在的话,那就匹配成功~

诶这里有个问题,这题要求返回这俩数的下标,可是 HashSet 里的数是无序的...

那就用升级版——HashMap 嘛~~还不了解 HashMap 的原理的同学快去公众号后台回复「HashMap」看文章啦。

HashMap 里记录下数值和它的 index 这样匹配成功之后就可以顺便得到 index 了。

这里我们不需要提前记录所有的值,只需要边过数组边记录就好了,为了防止重复,我们只在这个当前的数出现之前的数组部分里找另一个数。

总结一下,

  • HashMap 里记录的是下标 i 之前的所有出现过的数;
  • 对于每个 nums[i] ,我们先检查 target - nums[i] 是否在这个 map 里;
  • 如果在就直接返回了,如果不在就把当前 i 的信息加进 map 里。
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(target - nums[i])) {
                res[0] = map.get(target - nums[i]);
                res[1] = i;
                return res;
            }
            map.put(nums[i], i);
        }
        return res;
    }
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

喏,速度提升至 beat 99.96%

拓展

这是最基本的 2 Sum 问题,这个题可以有太多的变种了:

  • 如果这个数组里有不止一组结果,要求返回所有组合,该怎么做?

  • 如果这个数组里有重复元素,又该怎么做?

  • 如果这个数组是一个排好序了的数组,那如何利用这个条件呢?- Leetcode 167

  • 如果不是数组而是给一个 BST ,该怎么在一棵树上找这俩数呢?- Leetcode 653

...

这里讲一下排序数组这道题,之后会在 BST 的文章里会讲 653 这题。

排序数组

我们知道排序算法中最快的也需要 O(nlogn),所以如果是一个 2 Sum 问题,那没必要专门排序,因为排序会成为运算的瓶颈。

但如果题目给的就是个排好序了的数组,那肯定要好好收着了呀!

因为当数组是排好序的时候,我们可以进一步优化空间,达到 O(n) 的时间和 O(1) 的空间。

该怎么利用排好序这个性质呢?

那就是说,在 x 右边的数,都比 x 要大;在 x 左边的数,都比 x 要小。

  • 如果 x + y > target,那么就要 y 往左走,往小的方向走;

  • 如果 x + y < target,那么就要 x 往右走,往大的方向走。

这也就是典型的 Two pointer 算法,两个指针相向而行的情况,我之后也会出文章详细来讲哒。

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int left = 0;
        int right = numbers.length - 1;
        while (left < right) {
            int sum = numbers[left] + numbers[right];
            if (sum == target) {
                return new int[]{left + 1, right + 1}; //Your returned answers are not zero-based.
            } else if (sum < target) {
                left ++;
            } else {
                right --;
            }
        }
        return new int[]{-1, -1};
    }
}

3 Sum

3 Sum 的问题其实就是一个 2 Sum 的升级版,因为 1 + 2 = 3 嘛。。

那就是外面一层循环,固定一个值,在剩下的数组里做 2 Sum 问题。

反正 3 Sum 怎么着都得 O(n^2) ,就可以先排序,反正不在乎排序的这点时间了,这样就可以用 Two pointer 来做了。

还需要注意的是,这道题返回的是数值,而非 index,所以它不需要重复的数值——The solution set must not contain duplicate triplets.

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i + 2 < nums.length; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                 // skip same result
                continue;
            }
            int j = i + 1;
            int k = nums.length - 1;  
            int target = -nums[i];
            while (j < k) {
                if (nums[j] + nums[k] == target) {
                    res.add(Arrays.asList(nums[i], nums[j], nums[k]));
                    j++;
                    k--;
                    while (j < k && nums[j] == nums[j - 1]) {
                        j++;  // skip same result
                    }
                    while (j < k && nums[k] == nums[k + 1]) {
                        k--;  // skip same result
                    }
                } else if (nums[j] + nums[k] > target) {
                    k--;
                } else {
                    j++;
                }
            }
        }
        return res;
    }
}

4 Sum

最后就是 4 Sum 问题啦。

这一题如果只是 O(n^3) 的解法没什么难的,因为就是在 3 Sum 的基础上再加一层循环嘛。

但是如果在面试中只做出 O(n^3) 恐怕就过不了了哦

你真的会做 2 Sum 吗?| 含双重好礼的更多相关文章

  1. mysql真的不能做搜索引擎吗?

    大家都对电商的商品查询并不陌生,比如我们想根据商品名称查询所有商品信息. 有些技术的童鞋第一念头是搜索引擎:有些技术的童鞋第一念头是模糊查询,如like?(如果商品信息存放到mysql里,我们一般使用 ...

  2. 你真的会做数据分析吗?如果不会我推荐思迈特软件Smartbi

    你是否还在被以下问题所困扰? 辛苦辛苦地拿到了一堆数据,却不知道从何下手分析? 因为不会统计数据分析伤透脑筋,而打消考博的梦想? 数据分析求助无门,涌现出想要放弃学位的念头? 突然开天眼般的想到了一个 ...

  3. 「雕爷学编程」Arduino动手做(38)——joystick双轴摇杆模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  4. K Sum(2 Sum,3 Sum,4 Sum,3-Sum Closest)

    算是经典算法问题了.这里主要针对只存在一个解或者只需要求一个解的情况描述一下解题思路.若需要找到所有可能解,方法需要略作调整.如有问题,欢迎指正. 2 sum: 如果已排序,可直接用夹逼法,即两指针从 ...

  5. $NOIp$做题记录

    虽然去年做了挺多了也写了篇一句话题解了但一年过去也忘得差不多了$kk$ 所以重新来整理下$kk$ $2018(4/6$ [X]积木大赛 大概讲下$O(n)$的数学方法. 我是从分治类比来的$QwQ$. ...

  6. [LeetCode] Two Sum III - Data structure design 两数之和之三 - 数据结构设计

    Design and implement a TwoSum class. It should support the following operations:add and find. add - ...

  7. 异步编程系列第05章 Await究竟做了什么?

    p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...

  8. 想做Android Wear开发?你得先搞明白这四件事

    手环和手表的腕上穿戴之争,随着Apple Watch发布和Android Wear不断完善而告一段落.尽管续航上略有缺陷,但手表以其类似手机可扩展的生态环境赢得了众多巨头的支持. Google曾透露, ...

  9. 【剑指offer】不用加减乘除做加法

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/27966641 题目描写叙述: 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.* ...

随机推荐

  1. Python 实现将numpy中的nan和inf,nan替换成对应的均值

    nan:not a number inf:infinity;正无穷 numpy中的nan和inf都是float类型     t!=t 返回bool类型的数组(矩阵) np.count_nonzero( ...

  2. 水题----B - Badge CodeForces - 1020B

    In Summer Informatics School, if a student doesn't behave well, teachers make a hole in his badge. A ...

  3. CSMA/CD ,现在的交换式以太网还用吗?谈全双工,半双工与CSMA/CD的关系

    我们知道:以太网访问控制用的是CSMA/CD,即载波侦听多点接入/ 冲突检测,是以广播的方式将数据发送到所有端口: 我们还知道:交换机能主动学习端口所接设备的MAC地址,在获知该端口的MAC 地址后, ...

  4. Java线程池ThreadPoolExecutor面试总结思维导图速记

    优点 降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗. 提高响应速度,当任务到达时,可以不需要等待线程创建就能立即执行. 提高线程的可管理性 类关系 接 Executor 一个无返 ...

  5. emacs org-mode 中文手册精简版(纯小白)

    一只小白看了大佬的讲解视频结合其他大佬给整理的笔记再结合emacs 官方英文手册,觉得自己的知识好像增加了. 当时自己在全网搜索的时候没有看到那种纯小白的手册,本小白就写了这个,就当奉献社会了.若有不 ...

  6. 两数相加(B站看视频总结)

    ''' 两数相加: 给出两个 非空 的链表用来表示两个非负的整数 各自的位数是按照逆序的方式存储的 每一个节点只能保存 一位数 示例: 输入:(2->4->3) + (5->6-&g ...

  7. win10在html上运行java的applet程序

    Applet是采用Java编程语言编写的小应用程序,该程序可以包含在 HTML(标准通用标记语言的一个应用)页中,与在页中包含图像的方式大致相同. 含有Applet的网页的HTML文件代码中部带有 和 ...

  8. PHP count_chars() 函数

    实例 返回一个字符串,包含所有在 "Hello World!" 中使用过的不同字符(模式 3): <?php高佣联盟 www.cgewang.com$str = " ...

  9. Skill 脚本演示 ycChangeViaNumber.il

    https://www.cnblogs.com/yeungchie/ ycChangeViaNumber.il 使用鼠标滚轮快速修改 Via 的数量. 回到目录

  10. python数据可视化编程实战PDF高清电子书

    点击获取提取码:3l5m 内容简介 <Python数据可视化编程实战>是一本使用Python实现数据可视化编程的实战指南,介绍了如何使用Python最流行的库,通过60余种方法创建美观的数 ...