题目:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。说明:你能够假设每种输入只会对应一个答案。可是,你不能重复利用这个数组中一样的元素。php
示例:
给定 nums = [2, 7, 11, 15],target = 9
由于 nums[0] + nums[1] = 2 + 7 = 9
因此返回 [0, 1]git
暴力法很简单,遍历每一个元素 x,并查找是否存在一个值与 target−x 相等的目标元素
/** * @param Integer[] $nums * @param Integer $target * @return Integer[] */ function twoSum($nums, $target) { for($i=0;$i<count($nums);$i++){ for($j=$i+1;$j<count($nums);$j++){ if($nums[$i] + $nums[$j] == $target){ return [$i,$j]; } } } }
时间复杂度:O(n^2) 对于每一个元素,咱们试图经过遍历数组的其他部分来寻找它所对应的目标元素,这将耗费 O(n) 的时间 空间复杂度:O(1)
为了对运行时间复杂度进行优化,咱们须要一种更有效的方法来检查数组中是否存在目标元素。若是存在,咱们须要找出它的索引。保持数组中的每一个元素与其索引相互对应的最好方法是什么?哈希表(hashTable)。经过以空间换取速度的方式,咱们能够将查找时间从 O(n) 下降到 O(1)。哈希表正是为此目的而构建的,它支持以 近似 恒定的时间进行快速查找。我用“近似”来描述,是由于一旦出现冲突,查找用时可能会退化到 O(n)。但只要你仔细地挑选哈希函数,在哈希表中进行查找的用时应当被摊销为 O(1)。github
一个简单的实现使用了两次迭代。在第一次迭代中,咱们将每一个元素的值和它的索引添加到表中。而后,在第二次迭代中,咱们将检查每一个元素所对应的目标元素(target - nums[i])是否存在于表中。注意,该目标元素不能是 nums[i] 自己!算法
采用数组函数 `array_keys()` 来解题, 返回包含数组中全部键名的一个新数组 `array_keys()` 是一个哈希函数
/** * @param Integer[] $nums * @param Integer $target * @return Integer[] */ function twoSum($nums, $target) { for($i=0;$i<count($nums);$i++){ $difNum = $target - $nums[$i]; $keys = array_keys($nums,$difNum); foreach($keys as $key){ if($key && $key != $i){ return [$i,$key]; } } } }
时间复杂度:O(n) 咱们把包含有 n 个元素的列表遍历两次。因为哈希表将查找时间缩短到 O(1) ,因此时间复杂度为 O(n) 空间复杂度:O(n) 所需的额外空间取决于哈希表中存储的元素数量,该表中存储了 n个元素
事实证实,咱们能够一次完成。在进行迭代并将元素插入到表中的同时,咱们还会回过头来检查表中是否已经存在当前元素所对应的目标元素。若是它存在,那咱们已经找到了对应解,并当即将其返回。
采用数组函数 `array_key_exists()` 来解题, 判断数组是否存在此键名 `array_key_exists()` 是一个哈希函数
/** * @param Integer[] $nums * @param Integer $target * @return Integer[] */ function twoSum($nums, $target) { $find = []; for($i=0;$i<count($nums);$i++){ $difNum = $target - $nums[$i]; if(array_key_exists($difNum,$find)){ return [$find[$difNum],$i]; } $find[$nums[$i]] = $i; } }
时间复杂度:O(n) 咱们只遍历了包含有 n个元素的列表一次。在表中进行的每次查找只花费 O(1)的时间 空间复杂度:O(n) 所需的额外空间取决于哈希表中存储的元素数量,该表最多须要存储 n个元素
`isset()`性能比`array_key_exists()`要好,由于`isset()`是语言结构,而`array_key_exists()`是函数,语言结构的解析运行要比函数快一点。
/** * @param Integer[] $nums * @param Integer $target * @return Integer[] */ function twoSum($nums, $target) { $find = []; for($i=0;$i<count($nums);$i++){ $difNum = $target - $nums[$i]; if(isset($find[$difNum])){ return [$find[$difNum],$i]; } $find[$nums[$i]] = $i; } }
时间复杂度:O(n) 空间复杂度:O(n)
小贴士: * isset()效率高于array_key_exists(), PHP7以后有30%左右的提高, php5.6有将近70%的提高 * isset()是语法结构, array_key_exists()是函数, 调用开销要小 * isset()经过 Z_TYPE_P 获取变量类型,而后再进行判断实现的; array_key_exists()则是经过hash查找来实现的 * 对于数组,isset()的性能要高于array_key_exists() 因此,若是数组比较大,咱们应该用以下方法保证性能和准确性 isset()
用一个排序都能把复杂度降到 O(nlogn),经过排序,而后用两个指针从先后扫描逼近真值。注意这个思想,可让 O(n^2) 的复杂度降为 O(n),充分利用排序,由于必定会有一个值知足,而后经过值去原数组里找对应的下标。数组
前提,该数组已是一个有序数组,必须先排序,再查找
/** * @param Integer[] $nums * @param Integer $target * @return Integer[] */ function twoSum($nums, $target) { $origin = $nums; sort($nums); $left = 0; $right = count($nums) - 1; while($left <= $right){ if($nums[$left] + $nums[$right] == $target){ $start = array_keys($origin,$nums[$left]); $end = array_keys($origin,$nums[$right]); return [reset($start),end($end)]; }elseif($nums[$left] + $nums[$right] > $target){ $right -= 1; }elseif($nums[$left] + $nums[$right] < $target){ $left += 1; } } }
时间复杂度:O(logn) 空间复杂度:O(1)
Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<O(n^2)<O(n^3)<…<Ο(2n)<Ο(n!)
通常算法是否最优,主要看时间复杂度,每每最优的算法须要牺牲空间复杂度 一遍哈希表 < 二分查找法 < 两遍哈希表 < 暴力法
LeetCode_PHP:https://github.com/zhangdejian/LeetCode_PHP
本身只能解出第一和第二种思路,原来还有其它思路解,soga,涨知识了。本身不属于那种最聪明的或最有天赋的人,只能后天靠努力来补啦哈,反正多刷刷算法题,准没错,可让本身的思惟和深度无限延伸。函数
题目来源:力扣(LeetCode)