本文正在参与掘金团队号上线活动,点击 查看大厂春招职位
一、题目描述:
二、思路分析:
今天给大家分享的是力扣春季杯个人赛的第一题,可惜当时报名了没参加,现在来回顾一下看看。第一印象一看,咦,这不是找一个长度为2的子集,要是其和满足小于等于target就是一个满足条件的吗?哈哈哈哈,我在这里没尝试,不过感觉可能会超时?[狗头]
二分
定睛一看,看到题目的数据量10^5,应该往NlogN复杂度上靠。一个for循环,里面一个二分,正好吗这不是。
-
首先对原数组排序,然后开始依次遍历所有元素,要是当前元素已经大于等于target了,直接结束遍历。否则,进入二分查找有多少元素满足和当前元素加起来和小于等于target的数量。
-
二分,传入的是left,right边界,然后查找有多少元素小于等于target,注意,这里的target不是题目要找的target。找到满足条件的最右边界后,直接返回即可。
-
时间复杂度:O(NlogN),这里 N 是数组的长度。
-
空间复杂度:O(1)
三、AC 代码:
class Solution {
/**
* @param Integer[] $nums
* @param Integer $target
* @return Integer
*/
function purchasePlans($nums, $target) {
$len_n = count($nums);
sort($nums);
$ret = 0;
for ($i = 0; $i < $len_n - 1; $i++) {
if ($nums[$i] >= $target) {
break;
}
$t = $this->find($nums, $i + 1, $len_n - 1, $target - $nums[$i]);
echo "nums{$nums[$i]}, t:$t".PHP_EOL;
$ret += $t;
}
return $ret % (1000000007);
}
protected function find(&$nums, $left, $right, $target) {
$start = $left;
if ($nums[$left] > $target) {
return 0;
}
while ($left < $right) {
$mid = $left + (int)(($right - $left + 1) / 2);
if ($nums[$mid] > $target) {
$right = $mid - 1;
} else {
$left = $mid;
}
}
//循环结束是left == right,left 是最后一个满足要求的元素的位置,所以返回即可
return $left - $start + 1;
}
}
四、总结:
有时候根据题目提供的数据量选择合适的算法也是一个小技巧吧。