【PHP解法==LeetCode查找类型问题2(N数之和)】15.三数之和 && 16.最接近的三数之和 && 18.四数之和 && 454.四数相加II
2019-01-24 15:54
525 查看
目录
N数之和的都可以利用暴力解,但是复杂度肯定都会过高
因此可以先利用map存储一部分,或者利用双指针等方法,去优化解决方法,降低时间复杂度
15.三数之和
给定一个包含 n 个整数的数组
nums,判断
nums中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
[code]例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4], 满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
解法:先对数组进行排序,再利用双指针的思想,构建三元组
- 取一个固定值,用双指针寻找另外两个值,直至找到两个值之和等于固定值的负数,因为a+b+c=0===》a+b=-c
- 当两值之和小于固定值的负数时,左指针右移
- 当两值之和大于固定值的负数时,右指针左移
- 当两值之和等于固定值的负数时,要进行去重处理,防止最后出现重复的结果:判断 left+1的值,right-1的值,是否与上一个一样,相同的话,左右指针分别移动
[code] class Solution { function threeSum($nums) { //查找数 //先排序,再双指针 sort($nums); $len = count($nums); $result = []; //小于3根本构不成三元组,直接返回错误 if ($len<3) return $result; //遍历数组,固定一个值,在剩下的列表中,用双指针寻找两个值的和是否是固定值的负值 foreach ($nums as $key => $value) { $target = -$value;//取固定值-c $left = $key+1;//左指针 $right = $len-1;//右指针 //固定值一开始为正,或者最后一个都为负数,则不能组成=0的三元组 if($value>0 || $nums[$right]<0) break; //跳过,该值与上一值相同时,则构成的三元组重复 if($key>0 && $value==$nums[$key-1]) continue; while ($left<$right) { if ($nums[$right] < 0) break; //满足条件 if($nums[$left] + $nums[$right] == $target) { $result[] = [$value,$nums[$left],$nums[$right]]; //排除重复值,跳过处理 while ($left<$right &&$nums[$left] == $nums[$left+1]) $left += 1; while ($left<$right &&$nums[$right] == $nums[$right-1]) $right -= 1; //左右指针的都移动 $left += 1; $right -= 1; }elseif($nums[$left] + $nums[$right] < $target) //a+b+c=0====>a+b=-c $left += 1; else $right -= 1; } } return $result; } }
16.最接近的三数之和
给定一个包括 n 个整数的数组
nums和 一个目标值
target。找出
nums中的三个整数,使得它们的和与
target最接近。返回这三个数的和。假定每组输入只存在唯一答案。
[code]例如,给定数组 nums = [-1,2,1,-4], 和 target = 1. 与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
该题15题类似,只是不用返回整个三元组,只需求出一个最接近的答案即可
[code]class Solution { function threeSumClosest($nums, $target) { //先排序,再双指针 sort($nums); $len = count($nums); //小于3根本构不成三元组,直接返回错误 if ($len<3) return 0; $result = 0;//存储结果答案 $flag = 1;//第一次循环 foreach ($nums as $key => $value) { $left = $key+1;//左指针 $right = $len-1;//右指针 //跳过,该值与上一值相同时,则构成的三元组重复 if($key>0 && $value==$nums[$key-1]) continue; while ($left<$right) { $sum = $value + $nums[$left] + $nums[$right]; $tmp = $sum-$target;//求三元组相加与目标值的差距值 if(abs($tmp)<$max || $flag==1){ $flag=0; $max = abs($tmp); //目前最大差距 $result = $sum; //当为0时,已经满足最小条件,无需继续循环,直接返回 if($tmp==0) return $sum; } if($tmp<0) //a+b+c=0====>a+b=-c $left += 1; elseif($tmp>0) $right -= 1; } } return $result; } }
18.四数之和
给定一个包含 n 个整数的数组
nums和一个目标值
target,判断
nums中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与
target相等?找出所有满足条件且不重复的四元组。
注意:答案中不可以包含重复的四元组。
示例:
[code]给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。 满足要求的四元组集合为: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]
该题与15题题解一模一样,只需多套一层循环即可
[code]class Solution { function fourSum($nums, $target) { //查找数 //先排序,再双指针 sort($nums); $len = count($nums); $result = []; //小于3根本构不成三元组,直接返回错误 if ($len<4) return $result; //在三数之和的基础上多套一层循环 for($i = 0;$i<$len-3;++$i){ //去重操作 if($i>0 && $nums[$i] == $nums[$i-1]) continue; for($j = $i+1;$j<$len-2;++$j){ //去重操作 if($j>$i+1 && $nums[$j] == $nums[$j-1]) continue; $left = $j+1;//左指针 $right = $len-1;//右指针 while ($left<$right) { //四数相加 $sum = $nums[$i] + $nums[$j] + $nums[$left] + $nums[$right]; if($sum == $target){ //满足条件时,将四元组压入结果数组 $result[] = [$nums[$i],$nums[$j],$nums[$left],$nums[$right]]; //排除重复值,跳过处理 while ($left<$right &&$nums[$left] == $nums[$left+1]) $left += 1; while ($left<$right &&$nums[$right] == $nums[$right-1]) $right -= 1; //左右指针的都移动 $left += 1; $right -= 1; }elseif($sum < $target) //a+b+c=0====>a+b=-c $left += 1; else $right -= 1; } } } return $result; } }
454.四数相加II
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组
(i, j, k, l),使得
A[i] + B[j] + C[k] + D[l] = 0。
为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。
例如:
[code]输入: A = [ 1, 2] B = [-2,-1] C = [-1, 2] D = [ 0, 2] 输出:2 解释:两个元组如下: 1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
该题暴力解法即可解决,但是时间复杂度为O(n2)
因此可以利用查找表的方法,构建一个A+B的所有结果集的map,在C+D中找到是否存在0-(C+D)的键值
[code]class Solution { function fourSumCount($A, $B, $C, $D) { $map = []; //记录A+B的每一种可能 foreach($A as $a){ foreach($B as $b){ if(isset($map[$a + $b])) //因为同一结果可能有多种可能,所以要+1 $map[$a + $b]++; else $map[$a + $b] = 1; } } //记录结果数量 $result = 0; foreach($C as $c){ foreach($D as $d){ //a+b=-(c+d) if(isset($map[0-($c+$d)])) //加上map中对应的次数,才是最终的可能结果 $result+=$map[0-($c+$d)]; } } return $result; } }
LeetCode上类似N数之和,利用双指针,查找类型的还有1
相关文章推荐
- 【PHP解法==LeetCode查找类型问题3(距离计算)】447.回旋镖的数量 && 149.直线上最多的点数(hard)
- LeetCode- 16. 最接近的三数之和 (Medium)python和c++实现
- LeetCode 81 Search in Rotated Sorted Array II(循环有序数组中的查找问题)
- LeetCode Single Number I & II 都符合两个问题额外要求的 通用解法 与 思考过程
- leetcode 16 最接近的三数之和
- [LeetCode] 16. 3Sum Closest 最接近的三数之和 @python
- LeetCode Single Number I & II 都符合两个问题额外要求的 通用解法 与 思考过程
- LeetCode Single Number I & II 都符合两个问题额外要求的 通用解法 与 思考过程
- Combination Sum II问题及解法
- 【郝斌数据结构自学笔记】16-23_链表的定义与分类_链表节点插入与删除_每一个链表节点的数据类型该如何表示的问题
- leetcode 462. Minimum Moves to Equal Array Elements II 换一个角度思考问题 + 寻找中位数
- leetcode第16题,最接近的三数之和,python实现
- LeetCode-Find Minimum in Rotated Sorted Array II-旋转排序数组找最小-二分查找
- leetcode之137. Single Number II(C++解法 哈希表计数)
- 求连续子数组最大和问题的两种解法_PHP实现
- PHP 变量类型中的一些问题
- My Calendar II问题及解法
- PHPExcel解决内存占用过大问题-dw 查找memoryCacheSize把1M改为2048M
- 【Leetcode 15】3Sum 三数和问题 C++
- Leetcode之Pascal's Triangle II 问题