问题:
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
解法:
一、暴力法
class Solution {
/**
* @param Integer[] $nums
* @param Integer $target
* @return Integer[]
*/
function twoSum($nums, $target) {
for($i=0;$i<count($nums);$i++){
$numsTemp=$nums;
unset($numsTemp[$i]);
$two=array_search($target-$nums[$i],$numsTemp);
if( $two!==false){
return [$i,$two];
}
}
}
}
二、双指针法
解题思路
从两边向中心移动,遇到不符条件的字符跳过,时间复杂度为O(nlogn) 。
function twoSum($nums, $target) {
$nums_c = $nums; //保留原数组,sort函数会修改原数组
sort($nums);
$start = 0;
$end = $count = count($nums);
//两边逼近
while($start < $end){
//右边逼近左边,当右边+最小的数<=target时,结束
while($nums[$start] + $nums[--$end] > $target);
//如果是等于的话,结束循环
if ($nums[$start] + $nums[$end] == $target) {
break;
}
//左边逼近右边,当左边+右边最小数>=时,结束,记录当前两个指针的值。
while($nums[++$start] + $nums[$end] < $target);
//如果是等于的话,结束循环
if ($nums[$start] + $nums[$end] == $target) {
break;
}
}
//从原始数组里查找对应值的key
$result = [];
for($i=0; $i < $count; $i++) {
if ($nums_c[$i] == $nums[$start] || $nums_c[$i] == $nums[$end]) {
$result[] = $i;
}
}
return $result;
}
三、哈希法
牺牲一些存储空间,临时定义一个 map 数组,记录 $nums 的 值 => 索引。一次 foreach 循环中,即判断是否含有条件合适的值,也进行 map 映射。使得时间复杂度保持在 O(n) 及以下。
class Solution {
/**
* @param Integer[] $nums
* @param Integer $target
* @return Integer[]
*/
function twoSum($nums, $target) {
$found = [];
foreach ($nums as $key => $val) {
$diff = $target - $val;
if (!isset($found[$diff])) {
$found[$val] = $key;
continue;
}
return [$found[$diff], $key];
}
}
}
优化一下:
function twoSum($nums, $target) {
foreach ($nums as $k=> $v){
if(isset($result[$target - $v]) && $nums[$result[$target - $v]] + $v === $target) {
return [$result[$target - $v],$k];
}
$result[$v] = $k;
}
}