leetcode
leetcode 2001 ~ 2050
统计得分小于 K 的子数组数目

统计得分小于 K 的子数组数目

难度:

标签:

题目描述

代码结果

运行时间: 135 ms, 内存: 28.0 MB


/*
 * 思路:
 * 使用Java Stream API来计算满足条件的子数组数量。
 * 这里使用滑动窗口的方法,遍历每一个子数组并计算分数。
 */

import java.util.stream.IntStream;

public class Solution {
    public long numSubarrayScoreLessThanK(int[] nums, long k) {
        int n = nums.length;
        return IntStream.range(0, n)
                        .flatMap(start -> IntStream.range(start, n)
                                                   .map(end -> {
                                                       int sum = 0;
                                                       for (int i = start; i <= end; i++) {
                                                           sum += nums[i];
                                                       }
                                                       return (sum * (end - start + 1) < k) ? 1 : 0;
                                                   }))
                        .sum();
    }
}

解释

方法:

这是一道使用双指针技术解决的问题。我们初始化两个指针left和right,分别代表子数组的左右边界。我们从左到右遍历数组,每次将right指向的元素加到当前的分数中,然后检查当前子数组的分数是否小于k。如果分数大于或等于k,我们就移动left指针,直到分数再次小于k。每次迭代中,以right为右端点的符合条件的子数组数量就是right - left + 1,我们将这个值累加到最终答案中。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
题解中提到,当分数大于等于k时,left指针向右移动,这是否意味着只有当添加新元素导致总分数超过k时,我们才调整left指针?
是的,题解中的策略是每次向子数组中添加一个新元素(即右移right指针),然后检查当前子数组的得分乘以长度是否大于或等于k。如果是,这意味着当前的子数组不符合条件,需要通过右移left指针来减少子数组的长度和得分,直到子数组的得分乘以长度再次小于k。因此,只有在添加新元素后导致总得分超过k时,我们才调整left指针,以尝试找到一个有效的子数组。
🦆
在计算子数组的分数时,为何使用累加的方式更新score而不是每次都重新计算子数组的和?这种方法在什么情况下可能导致错误?
使用累加方式更新score而不是每次重新计算子数组的和是为了提高算法的效率。如果每次重新计算,则每次移动指针时的时间复杂度为O(n),这会使得整体算法的时间复杂度变得很高。通过累加方式更新,我们可以在O(1)的时间内更新score,从而保持整体算法的时间复杂度为O(n)。这种方法通常不会导致错误,只要我们正确地在移动左指针时减去左端点的值。如果忘记在移动左指针时更新score,那么计算结果将会错误。
🦆
类Solution中的while循环条件是`score * lens >= k`,那么在score非常大或lens非常大的情况下,这种方法是否还是有效的?
这种方法在数值非常大的情况下仍然有效,因为它依赖的是数学条件的正确性:只要子数组的得分乘以长度大于或等于k,就需要减小子数组的大小。然而,在实际的计算机程序中,特别是在处理非常大的数值时,需要注意整数溢出的问题。在某些编程语言中,得分和长度的乘积可能超过整数类型的最大值,导致溢出。在这种情况下,可以考虑使用更大范围的整数类型或适时地进行类型转换。
🦆
题解中的算法是否考虑了所有子数组的边界条件,例如最小子数组和最大子数组?
是的,题解中的算法考虑了所有子数组的边界条件。算法从每个可能的右端点开始,逐步尝试包含不同长度的子数组,从最小的子数组(只包含一个元素)到最大可能的子数组(从当前left到right的全部元素)。算法通过动态调整left和right指针来确保每个子数组都被计算和考虑,因此它涵盖了从最小到最大的所有子数组。

相关问题