Problem Statement
You are given an integer array nums
of length n
, and an integer array queries
of length m
.
For each queries[i]
, you need to determine the maximum length of a subsequence of nums
such that the sum of the subsequence is less than or equal to queries[i]
.
A subsequence is derived from the array by deleting some or no elements without changing the order of the remaining elements.
Return an array result
of length m
where result[i]
is the answer to the i-th
query.
Examples
Example 1:
Input: nums = [4, 2, 1, 5], queries = [3, 7, 9]
Output: [2, 3, 4]
Explanation:
For queries[0] = 3, the longest subsequence we can pick is [2, 1] with sum = 3, so the result is 2.
For queries[1] = 7, the longest subsequence we can pick is [4, 2, 1] with sum = 7, so the result is 3.
For queries[2] = 9, the longest subsequence we can pick is [4, 2, 1, 5] with sum = 9, so the result is 4.
Example 2:
Input: num = [2, 3, 4, 5], queries = [1]
Output: [0]
Explanation:
No subsequence can be formed with sum <= 1
Different Approaches
1️⃣ Brute Force Approach (Greedy + Sorting)
Intuition:
- The main idea is to first sort the
nums
array to handle smaller numbers first, as smaller numbers are easier to fit into the subsequence without exceeding the sum limit. - For each query, we can check how many elements from the sorted
nums
can be added until the sum exceeds the query value.
Steps:
- Sort the
nums
array. - For each query:
- Start adding the elements from the sorted
nums
until the sum exceeds the query value. - Count the number of elements added that remain under the query sum limit.
- Start adding the elements from the sorted
Approach:
- Sort the
nums
array in non-decreasing order. - For each query:
- Traverse through the sorted array and keep a running sum.
- If adding an element does not exceed the query, continue adding it to the subsequence.
- Stop when the sum exceeds the query and return the count of elements added.
Code:
#include <vector>
#include <algorithm>
using namespace std;
vector<int> answerQueries(vector<int>& nums, vector<int>& queries) {
// Sort the nums array to process the smallest elements first
sort(nums.begin(), nums.end());
vector<int> result; // This will store the result for each query
// Process each query one by one
for (int query : queries) {
int count = 0;
int sum = 0;
// Traverse through the sorted nums array and check how many can be added
for (int num : nums) {
sum += num;
if (sum <= query) {
count++; // We can add this element to the subsequence
} else {
break; // If sum exceeds the query, stop
}
}
// Store the result for this query
result.push_back(count);
}
return result;
}
Complexity Analysis:
- Time Complexity:
O(n log n + m*n)
- Sorting the
nums
array takesO(n log n)
. - For each query, we iterate through the sorted
nums
array, which takesO(n)
for each query. Since there arem
queries, this part takesO(m * n)
. - Total Complexity:
O(n log n + m * n)
.
- Sorting the
- Space Complexity:
O(n)
- Due to sorting the array in place.
2️⃣ Prefix Sum + Binary Search
Intuition:
- Once the array is sorted, we can calculate the prefix sum. The idea is to utilize the fact that prefix sums allow us to quickly check the sum of any subsequence that includes the smallest elements of the sorted array.
- For each query, we can binary search on the prefix sums to find the longest subsequence whose sum is less than or equal to the query value.
Steps:
- Sort the
nums
array. - Calculate the prefix sum array.
- For each query, perform a binary search on the prefix sum array to find the maximum length of the subsequence that satisfies the query.
Approach:
- Sort the
nums
array. - Create a prefix sum array where each element at index
i
represents the sum of the firsti
elements of the sortednums
. - For each query, use binary search to find the largest index
k
such that the prefix sum is less than or equal to the query.
Code:
#include <vector>
#include <algorithm>
using namespace std;
// Custom binary search to find the upper bound manually
int upperBound(const vector<int>& prefixSums, int target) {
int low = 0;
int high = prefixSums.size() - 1;
int ans = prefixSums.size(); // If target is larger than any prefix sum, return size of array
while (low <= high) {
int mid = low + (high - low) / 2;
if (prefixSums[mid] <= target) {
low = mid + 1; // Move to the right half if current sum is ≤ target
} else {
ans = mid; // Store current index as potential answer
high = mid - 1; // Move to the left half
}
}
return ans;
}
vector<int> answerQueries(vector<int>& nums, vector<int>& queries) {
// Step 1: Sort the nums array
sort(nums.begin(), nums.end());
// Step 2: Build prefix sums
int n = nums.size();
vector<int> prefixSums(n, 0);
prefixSums[0] = nums[0];
for (int i = 1; i < n; i++) {
prefixSums[i] = prefixSums[i-1] + nums[i];
}
vector<int> result;
// Step 3: Process each query using binary search on the prefix sums
for (int query : queries) {
// Use manual binary search to find the largest subsequence length
int maxLength = upperBound(prefixSums, query);
result.push_back(maxLength);
}
return result;
}
Complexity Analysis:
- Time Complexity:
O(n log n)
- Sorting takes
O(n log n)
- Constructing the prefix sum array takes
O(n)
- For each query, binary search takes
O(log n)
, so the total complexity isO(n log n + m log n)
.
- Sorting takes
- Space Complexity:
- The space complexity is
O(n)
for storing the prefix sum array.
- The space complexity is