平均数大于k的最长子序列 | 豆包MarsCode AI刷题

3 阅读3分钟

题目描述:

小U手里有一个由N个正整数组成的数组。她希望能够从中找到一个子序列,使得这个子序列的平均数大于一个给定的值K。你的任务是帮助小U找到这样的子序列,并且求出其中最长的子序列长度。如果无法找到平均数大于K的子序列,那么输出-1。

例如:给定数组为 [3, 1, 1, 2, 3],并且K=2。你可以选择子序列 [3, 1, 2, 3],此时它的平均数为2.25,大于K,并且这是最长的满足条件的子序列。

测试样例:

样例1: 输入:n = 5 , k = 2 , a = [3, 1, 1, 2, 3] 输出:4

样例2: 输入:n = 3 , k = 5 , a = [1, 2, 3] 输出:0

样例3: 输入:n = 6 , k = 3 , a = [6, 5, 2, 7, 8, 9] 输出:6

解析思路与实现细节

  1. 排序数组: 使用 Arrays.sort(a) 对输入数组进行升序排列。这一步骤是为了后续操作提供便利,因为有序数组有助于快速定位可能符合要求的子序列。

  2. 检查最大值: 判断数组中的最大值是否小于或等于k。如果是,则意味着整个数组都不可能形成平均数大于k的子序列,因此直接返回0。

  3. 反向迭代计算: 从数组的最大值开始(即从数组的最后一个元素)向前迭代至第一个元素。对于每个元素,执行以下逻辑:

    • 计算包含该元素在内的子序列的平均值 (tmp)。
    • 检查此平均值是否小于k。如果小于k,则表明已经找到一个平均数大于k的子序列,返回当前已考虑的元素数量作为结果。
    • 否则,累加当前元素值到总和(res),并将计数器(num)增加1,以准备下一次循环。
  4. 返回结果: 如果循环结束仍未找到符合条件的子序列,则返回当前已考虑的元素总数。

算法核心思想

这种解法的核心在于利用数组排序后的特性,从大到小尝试构建子序列,从而避免了需要维护多个状态的复杂性。它巧妙地利用了数组排序后的单调递减性质,仅需单次线性扫描即可确定答案。

import java.util.Arrays;

public class Main {
    public static int solution(int n, int k, int[] a) {
        Arrays.sort(a); // Sort the array in ascending order.
        float res = 0; // Initialize sum of elements considered so far.
        float num = 0; // Initialize count of elements considered so far.

        // Check if the maximum value is less than or equal to k.
        if (a[a.length - 1] <= k) return 0;

        // Iterate from the end of the sorted array towards the beginning.
        for (int right = a.length - 1; right >= 0; right--) {
            float tmp = (res + a[right]) / (num + 1); // Calculate average with current element included.
            
            // If the calculated average is less than k, we found our sequence.
            if (tmp < k) return (int) num;
            
            // Otherwise, add this element's value and increment the count.
            res += a[right];
            num++;
        }

        // Return the total number of elements considered as the result.
        return (int) num;
    }

    public static void main(String[] args) {
        System.out.println(solution(5, 2, new int[]{3, 1, 1, 2, 3}) == 4);
        System.out.println(solution(3, 5, new int[]{1, 2, 3}) == 0);
        System.out.println(solution(6, 3, new int[]{6, 5, 2, 7, 8, 9}) == 6);
    }
}

这段代码的关键点在于把子序列灵活转化为一个被排序后的数组,并基于当前子序列的平均值决定何时停止搜索。这种方法不仅简洁而且效率高,因为它只需要O(n log n)的时间复杂度(主要来自于排序),而空间复杂度则是O(1),不依赖于额外的数据结构。