X sum 类型题解题套路

X sum 类型题解题套路

刷leetcode大概碰到的第一道就是Two Sum了,当时迅速解完的一丝得意,不过也在后面看到3Sum,4Sum以后被耗光了,实际上,这类题是遵循某种规律的,下面就详细来说说。

入门级别

从最简单的Two Sum说起,题目详见leetcode 1.Two Sum。

要从数组中找到某两个相加为target的元素的下标,常规做法想到的是O(n^2)

的做法,两个for循环,对每个数组元素a都遍历位置在它后面的元素看是否有元素和a相加结果为target

一种用空间换时间的做法就是,只需要一次遍历数组,在遍历的过程中把当前元素和target之间差的值作为key,当前元素下标i记录到哈希表中,在每次访问元素前首先需要在该哈希表中查找当前元素是否已经作为之前某个元素的diff存放在哈希表中了,如果是,直接返回答案即可。

注:在C++中推荐使用unordered_map作为哈希表(替代原来的hash_map

有必要提到的一点是,如果这道题不是要求返回相加为target的数组的下标,而是返回所有相加为target的数组集合(改成这样是为了和下面的3Sum和4Sum做铺垫),也可以按照以下思路来求解。

先对数组按照从小到大的顺序排序,然后使用两个指针分别指向数组的头和尾,分为以下三种情况:

  • 若nums[start]+nums[end]start++操作。
  • 若nums[start]+nums[end]>target,表示nums[end]过大,所以进行end--操作。
  • 如果nums[start]+nums[end]==target,则找到了一组结果,同时start++end—,并跳过循环重复值,避免结果冗余。

这样最终得到的就是结果相加为target的数组集合。

最后提到的这种思路的具体应用可参考leetcode 167. Two Sum II - Input array is sorted

3Sum

在Two Sum的基础上引入3Num,题目详见leetcode 15. 3Sum

要在给定数组中找到所有三个元素相加为0的组合,且结果不能有重复。

常规做法,需要三层循环,时间复杂度为O(n^3)
实际上按照Two Sum最后给出的拓展思路,可以很容易将这道题转换为,从数组中选出一个元素nums[i],然后就变成了target为-nums[i]的Two Sum问题。排序后按之前的思路进行即可。由于数组是排序后的,所以在最外层循环的时候只需要循环nums中小于0的部分元素即可。一定要注意跳过重复值,避免结果中出现冗余。这种做法,预处理数组(即对数组进行排序)的时间复杂度为O(nlogn),而遍历只需要两层循环,时间复杂度为O(n^2)即这也是该解法最终的时间复杂度。

3Sum问题还有一变形,详见3Sum Closest,大致思路类似,就不赘述了,主要就是保存和target差距diff,最终得到diff最小的一个解,不过要注意的是由于这里target不为0了,所以在最外层循环时也就不能只处理小于0的部分了。

4Num

在3Sum的基础上引入4Sum问题,题目详见leetcode 18. 4Sum

给定一个数组,返回所有四个元素相加为target的不重复组合,实际上和3Sum的套路完全一样,就是把4Sum转换为3Sum再转换为2Sum,最终返回正确答案。利用这种方法就可以把原本暴力解的复杂度为O(n^4)
转化为最终的复杂度为O(n^3)

总结

实际上X Sum问题没有想象中的那么难,只要掌握的它的规律,进行一个预排序后,就可以一层层的向下转换,即将X Sum转为(x-1) Sum...最终转为2Sum后得到最终答案,不过一定要注意跳过重复元素,否则会造成最终结果的冗余。

你可能感兴趣的:(X sum 类型题解题套路)