满足条件的子序列数目
难度:
标签:
题目描述
代码结果
运行时间: 210 ms, 内存: 25.8 MB
/*
* 思路:
* 虽然流式API不适合双指针这种复杂控制流的实现,
* 但我们可以用流来排序和计算power数组,然后用循环实现主逻辑。
*/
import java.util.Arrays;
import java.util.stream.IntStream;
public class Solution {
public int numSubseq(int[] nums, int target) {
int MOD = 1_000_000_007;
Arrays.sort(nums);
int left = 0, right = nums.length - 1;
int result = 0;
int[] power = IntStream.range(0, nums.length)
.map(i -> (int) Math.pow(2, i) % MOD)
.toArray();
while (left <= right) {
if (nums[left] + nums[right] <= target) {
result = (result + power[right - left]) % MOD;
left++;
} else {
right--;
}
}
return result;
}
}
解释
方法:
首先,将数组 nums 排序。这样做的目的是为了能快速找到任意子序列的最小和最大元素。定义两个指针 left 和 right,分别代表当前考虑的子序列的最小元素和最大元素的位置。初始化 left 为 0,right 为 nums 长度减一。在遍历数组时,如果 nums[left] + nums[right] 小于等于 target,意味着从 left 到 right 之间的所有子序列都满足条件,因为 nums[left] 是可能的最小值,而 nums[right] 是可能的最大值。每次这样的情况出现时,可以用 pow(2, right - left, mod) 来计算当前 left 和 right 之间的所有子序列的数量(即 2 的 (right-left) 次幂),因为每个元素可以选择包含或不包含。如果 nums[left] + nums[right] 大于 target,由于数组是排序的,需要将 right 指针左移,以尝试减小最大元素的值。循环直到 left 超过 right。最后,返回 count 对 mod 的余数作为结果。
时间复杂度:
O(n log n)
空间复杂度:
O(n)
代码细节讲解
🦆
在算法描述中,为什么首先需要对数组进行排序?排序的目的和对算法逻辑的影响是什么?
▷🦆
当左右指针指向的元素之和小于等于目标时,为什么可以直接计算从left到right之间所有子序列的数量而不遗漏任何可能的序列?
▷🦆
算法中提到使用pow(2, right - left, mod)来计算子序列数量。这个计算过程是基于什么理论或性质?
▷🦆
如果nums[left] + nums[right]大于target,为什么只有移动右指针而不考虑移动左指针?
▷