本文主要是介绍前端算法题----三数求和问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
算法题讲解
真题描述:
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
思路分析
首先大家要记住一个结论:几乎所有的求和问题,都可以转化为求差问题。
接下来就我们可以把求和问题变成求差问题——我们先固定其中一个数,在剩下的数中寻找是否有两个数和这个固定数相加是等于0的。虽然这道题看起来好像需要三层循环才能解决的样子,但是我们可以使用双指针法,可以大大提高定位效率。
注意:双指针法用在涉及求和、比大小类的数组题目里的前提是,该数组必须有序。否则双指针根本无法帮助我们缩小定位的范围,压根没有意义。因此这道题的第一步是将数组排序。
然后,遍历给定数组。对于当前遍历到的数字,将其固定,然后用左指针指向该数字后面一个位置,右指针指向数组末尾。接下来,让左右指针从起点和终点开始向中间靠拢,每次移动一个位置,并计算两个指针指向数字之和加上固定的数字之后是否等于0。如果等于0,则表示找到了一个目标组合;否则,根据计算结果分为两种情况:
- 相加之和大于0,说明右侧的数偏大了,因此需要将右指针左移。
- 相加之和小于0,说明左侧的数偏小了,因此需要将左指针右移。
需要注意的是,题目要求找出不重复的三元组,因此在实现时需要处理重复元素的情况。
方法一
代码
/*** @param {number[]} nums1* @param {number} m* @param {number[]} nums2* @param {number} n* @return {void} Do not return anything, modify nums1 in-place instead.*/
const merge = function(nums1, m, nums2, n) {// 初始化两个指针的指向,初始化 nums1 尾部索引klet i = m - 1, j = n - 1, k = m + n - 1// 当两个数组都没遍历完时,指针同步移动while(i >= 0 && j >= 0) {// 取较大的值,从末尾往前填补if(nums1[i] >= nums2[j]) {nums1[k] = nums1[i] i-- k--} else {nums1[k] = nums2[j] j-- k--}}// nums2 留下的情况,特殊处理一下 while(j>=0) {nums1[k] = nums2[j] k-- j--}
};
这个函数的时间复杂度为O(m+n),空间复杂度为O(1)。
代码讲解:
- 首先初始化三个指针:
i
指向nums1
的末尾元素,j
指向nums2
的末尾元素,k
指向合并后的nums1
的末尾。 - 当
i
和j
都大于等于 0 时,进行循环,同时移动指针i
和j
,每次取nums1[i]
和nums2[j]
中较大的值填入nums1[k]
中,并将指针i
和k
同时向前移动,或者将nums2[j]
填入nums1[k]
中,并将指针j
和k
同时向前移动。 - 如果
nums2
中还有元素未被处理,就需要将其全部填入nums1
中。 - 最终,
nums1
中存储的就是合并后的有序数组。
双指针法中的“对撞指针”法
“对撞指针法”
是一种特殊的双指针形态,通常应用于“有序数组”问题中。当我们看到有序数组这个关键条件时,就应该尝试使用对撞指针解决问题。
如果题目中没有给出数组有序的条件,我们可以手动对数组进行排序,再尝试使用对撞指针。对撞指针可以帮助我们缩小问题的范围,以便于把时间花在真正有意义的计算和对比上,同时降低问题的复杂度,提高解题速度。在“三数求和”问题中,我们可以用两个指针“画地为牢”圈出一个范围,范围以外的值不是太大就是太小、直接被排除在我们的判断逻辑之外,从而节省计算时间,提高解题效率。
总结
- 双指针法,它可以做到空间换时间;另一方面,它也可以帮我们降低问题的复杂度
- 双指针法用在涉及求和、比大小类的数组题目里时,大前提往往是,该数组必须有序。否则双指针根本无法帮助我们缩小定位的范围,压根没有意义
- 当我们看到有序数组这个关键条件时,就应该尝试使用对撞指针解决问题。
写在最后
伙伴们,如果你觉得我写的文章对你有帮助就给zayyo点一个赞👍或者关注➕都是对我最大的支持。当然你也可以加我微信:IsZhangjianhao,邀你进我的前端学习交流群,一起学习前端,成为更优秀的工程师~
这篇关于前端算法题----三数求和问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!