数组和问题

数组和问题

主要是围绕数组中一些数做操作,以达到某个目标,如目标和等。

1.两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 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]

暴力法:

显然,可以用两个for循环,复杂度为 O ( n 2 ) O(n^2) O(n2)

双指针

首先将问题转化为公式,即 x + y = t a r g e t x + y = target x+y=target。其中, x , y x,y x,y 是可变的,那么,当 x x x 的值减少的时候, y y y 的值必须增加,反之亦然,这样才有可能得到 t a r g e t target target。而通过遍历的方式选择增减,自然想到的就是让一个数组有序。这样,通过左移或者右移,就能控制增减。x = nums[left], y = nums[right], 若和大于 t a r g e t target target则可排除当前的 y y y,因为当前结果已经是含 y y y的两数之和中最小的了。反之亦然,这样就能通过一次遍历得到下标[left, right]。复杂度为 O ( n log ⁡ n ) O(n\log n) O(nlogn)(快排)+ O ( n ) = O ( n log ⁡ n ) O(n) = O(n\log n) O(n)=O(nlogn)

再进阶

由于上述方法需要排序,时间复杂度不是 O ( n ) O(n) O(n)。这种时候,应该学会对式子进行一定的转换,如逆向思维等。如 x + y = t a r g e t    ⟺    x = t a r g e t − y x + y = target \iff x = target - y x+y=targetx=targety,即给定一个 y y y,则符合条件的 x x x是固定的,只要存在则该对数字就满足条件。而看某个数是否存在,最便捷的就是使用Set()数据结构,因为查找的复杂度为 O ( 1 ) O(1) O(1)。但由于本题需要的答案是下标而不是数值,因此应该使用Map()。遍历数组时,将当前数据看作 x x x,查看当前数据是否在Map()中,若在则当前下标与Map()中记录的下标组合就是答案;若不存在则将当前数据看作 y y y,将需要的 x = t a r g e t − y x = target - y x=targety 存入Map()中。

15.三数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]

暴力法

三个for循环搞定,复杂度 O ( n 3 ) O(n^3) O(n3)。但由于本题要求不重复,因此要需要做去重。去重可以有两种方式,第一种是在循环的时候注意去重,这时候往往想到的就是排序;第二种是得到所有选择后进行去重,这也可以通过排序得到,即将得到的三元组排序后放入Set()中。

排序+双指针

首先, a + b + c = 0    ⟺    b + c = 0 − a a+b+c=0 \iff b + c = 0 - a a+b+c=0b+c=0a,是不是和两数之和一样了?即 t a r g e t = 0 − a target = 0 - a target=0a。那么,只需要枚举每一个 a a a, 求对应的 b , c b,c b,c 即可。因此复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn) + O ( n ) O(n) O(n)(枚举 a a a)* O ( n ) O(n) O(n)(双指针求 b , c b,c b,c) = O ( n 2 ) O(n^2) O(n2)

拓展

该类问题有引出一个编程思想,即逆向思维。很多题目正着做看似很复杂,但其实换个角度就发现很简单。

417. 太平洋大西洋水流问题
字节跳动2018校招算法方向(第一批)第1题
2021阿里编程2星第1题
2021阿里编程4星第5题
1591. 奇怪的打印机 II(推荐)主要是理解思想

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值