好子序列的个数
难度:
标签:
题目描述
代码结果
运行时间: 77 ms, 内存: 17.0 MB
/*
题目思路:
给定一个数组 nums 和一个整数 k,要求找出数组中所有长度为 k 的子序列,使得子序列中最大元素和最小元素之差不超过 1。
使用 Java Stream API,我们可以更简洁地实现这一功能。
1. 首先,我们需要生成所有长度为 k 的子序列。
2. 对于每一个生成的子序列,判断其最大值和最小值之差是否不超过 1。
3. 统计所有符合条件的子序列的数量。
*/
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class GoodSubsequencesStream {
public static int countGoodSubsequences(int[] nums, int k) {
List<List<Integer>> subsequences = generateSubsequences(nums, k);
return (int) subsequences.stream()
.filter(subseq -> {
int max = subseq.stream().mapToInt(v -> v).max().orElse(Integer.MIN_VALUE);
int min = subseq.stream().mapToInt(v -> v).min().orElse(Integer.MAX_VALUE);
return max - min <= 1;
})
.count();
}
private static List<List<Integer>> generateSubsequences(int[] nums, int k) {
return IntStream.range(0, 1 << nums.length)
.mapToObj(i -> IntStream.range(0, nums.length)
.filter(j -> (i & (1 << j)) != 0)
.mapToObj(j -> nums[j])
.collect(Collectors.toList()))
.filter(list -> list.size() == k)
.collect(Collectors.toList());
}
public static void main(String[] args) {
int[] nums = {1, 2, 3, 4};
int k = 3;
System.out.println(countGoodSubsequences(nums, k)); // 示例输出
}
}
解释
方法:
这个题解通过预计算阶乘和阶乘的逆来计算组合数C(n, k),用于计算每个字符出现次数的所有可能的组合方式。解法首先统计字符串中每个字符的出现次数,并将这些数值排序存储。对每种可能的出现次数cnt从最大值向1迭代,计算在至少有cnt个字符的情况下,可以形成的所有子序列的方式,并累加到答案中。这种方法通过动态规划的方式,利用组合数学的知识来高效计算结果。
时间复杂度:
O(N + M*K)
空间复杂度:
O(N)
代码细节讲解
🦆
为什么在计算组合数C(n, k)时需要使用逆阶乘,直接使用阶乘相除会有什么问题?
▷🦆
解法中提到的字符频率为何需要排序?排序的目的是什么,对算法的影响如何?
▷🦆
在计算组合数时,您检查了n < 0, k < 0 或 n < k的情况,这些条件是如何影响组合数计算的?
▷🦆
在主函数中减去1的操作是为了去除哪种特殊情况?为什么要特别去除这种情况?
▷