携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情
每日刷题 2022.08.28
- leetcode原题链接:leetcode.cn/problems/lo…
- 难度:简单
- 方法:前缀和、贪心+排序
题目
- 给你一个长度为 n 的整数数组 nums ,和一个长度为 m 的整数数组 queries 。
- 返回一个长度为 m 的数组 answer ,其中 answer[i] 是 nums 中 元素之和小于等于 queries[i] 的 子序列 的 最大 长度 。
- 子序列 是由一个数组删除某些元素(也可以不删除)但不改变剩余元素顺序得到的一个数组。
示例
- 示例1
输入:nums = [4,5,2,1], queries = [3,10,21]
输出:[2,3,4]
解释:queries 对应的 answer 如下:
- 子序列 [2,1] 的和小于或等于 3 。可以证明满足题目要求的子序列的最大长度是 2 ,所以 answer[0] = 2 。
- 子序列 [4,5,1] 的和小于或等于 10 。可以证明满足题目要求的子序列的最大长度是 3 ,所以 answer[1] = 3 。
- 子序列 [4,5,2,1] 的和小于或等于 21 。可以证明满足题目要求的子序列的最大长度是 4 ,所以 answer[2] = 4 。
- 示例2
输入:nums = [2,3,4,5], queries = [1]
输出:[0]
解释:空子序列是唯一一个满足元素和小于或等于 1 的子序列,所以 answer[0] = 0 。
提示
- n == nums.length
- m == queries.length
- 1 <= n, m <= 1000
- 1 <= nums[i], queries[i] <= 10^6
解题思路
- 根据题意分析可知:对于
queries数组中的每一个元素(记为:ele),都需要在nums数组中查找到对应的元素之和小于等于ele的最长子序列。 - 这里子序列的定义:不一定非要是连续的,可以是删除某些元素或者不删除之后形成的子序列。
- 坑点:思想上的困境,最长子序列的定义是可以不连续,并非不能给
nums数组中的元素进行排序。因为将nums数组排序后,连续选择的元素,也可以在元素中依次选择。 - 因为题目要求的是最长子序列,那么我们将
nums数组中的元素从小到大进行排序后,就可以贪心的从前往后依次选择,尽可能地多选择元素值小的,这样子序列就会更长。 - 对于排序后的
nums数组,求前缀和(记为:pre数组)。例如:pre[i] = nums[i - 1] + pre[i - 1],前缀和数组当前的i位置的元素和表示:从当前元素到数组头部的所有元素之和(包含当前元素)。 - 最后根据
queries中的每一个元素去二分查找,pre数组中小于等于的下标,就是当前可以形成饿最长子序列。
AC代码
var answerQueries = function(nums, q) {
let n = nums.length, m = q.length;
nums.sort((a, b) => a - b);
let pre = new Array(n + 1).fill(0);
for(let i = 1; i <= n; i++) {
pre[i] = nums[i - 1] + pre[i - 1];
}
// console.log(pre)
let ans = [];
for(let i = 0; i < m; i++) {
ans.push(binary(q[i]));
}
return ans;
function binary(tar) {
let l = 0, r = n + 2;
while(l + 1 != r) {
let mid = (l + r) >> 1;
if(pre[mid] <= tar) {
l = mid;
}else {
r = mid;
}
}
return l;
}
};