力扣2389,和有限的最长子序列

题目

给你一个长度为 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 。

答案

    vector<int> answerQueries(vector<int>& nums, vector<int>& queries) {
        vector<int> res;
        int n = nums.size();
        int m = queries.size();
        //nums从小到大排序
        sort(nums.begin(),nums.end());
        vector<int> f(n+1);
        //存储前缀和
        for(int i=0;i<n;i++){
            f[i+1] = f[i] + nums[i];
        }
        //找第一个大于目标序列的值
        for(int i=0;i<m;i++){
            int r = upper_bound(f.begin(),f.end(),queries[i])-f.begin()-1;
            res.push_back(r);
        }
        return res;
    }

知识点1

	//前缀和 
	void addTotal(){
		vector<int> nums = {1,2,3,4,5,6};
		vector<int> res(6+1);
		for(int i=0;i<nums.size();i++){
			//res第一个为0,res[1]为nums前1个的和,res[2]为nums前2个的和 
			res[i+1] = res[i] + nums[i];
		}
		for(int i=0;i<res.size();i++){
			cout<<res[i]<<" ";
		}
	} 

在这里插入图片描述

知识点2

upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
ower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。

# 计算出前缀和数组中第一个大于queries[i]的数据索引位置
int r = upper_bound(f.begin(),f.end(),queries[i])-f.begin()-1;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值