华为OD题目:优雅数组

华为OD题目:优雅数组

知识点双指针数组Q滑窗
时间限制: 1s 空间限制: 256MB 限定语言: 不限
题目描述:
如果一个数组中出现次数最多的元素出现大于等于k次,被称为k-优雅数组,k也可以被称为 优雅闻值
例如,数组“1,2,3,1,2,3,1J,它是一个3-优雅数组,因为元素1出现次数大于等于3次,数组1,2,3,1,2]就不是一个3-优雅数组,因为其中出现次数最多的元素时~1和2,只出现了2次。
给定一个数组A和k,请求出A有多少子数组是k-优雅子数组~。
子数组是数组中一个或多个连续元素组成的数组。
例如,数组[1,2, 3,4包含10个子数组,分别是:[1],[1,2],[1,2, 3],[1,2,3,4,[2],[2,3].
[2, 3, 4],[3],[3, 4],[4]。

输入描述:
第一行输入两个整数n和k,n是数组A的长度,k是优雅闻值.
第二行输入n个整数,表示给定的数组A。
1 <= n <= 10000.1 <= k <= n
数组A中的元素AW满足: 1 <= AW <= n
输出描述:
数据一个整数,表示数组A中~k-优雅子数组的数量行尾不要有多余空格

示例1
输入:
7 3
1 2 3 1 2 3 1
输出:
1
说明:
只有子数组[1,2,31,2,3,1]是“3-优雅数组
示例2
输入:
7 2
1 2 3 1 2 3 1
输出:
10
说明:
10个优雅子数组分别是 (下标从0计数) :
长度为4: [1,2,3,11(下标03),2,3,1,2(下标14),13,12.31(下标2~5),[1,2. 3.11下标3~6)长度为5: 1,2,3,1,2,2,3,1,2,3,[3,1,2,3,11(下标2~6)
长度为6: [1.2.3.1.2.31(下标05),[2.3,1.2.3.11(下标16)
长度为7: 1,2,3,1,2,3,1

输入:
9 3
9 5 2 1 2 3 1 1 2
输出:
8

解题思路:

  • 本题比较巧妙,暴力解法通过率比较低
  • 本题比较巧妙,得记一下
  • 1: 最开始移动右指针,直到窗口里能有子数组满足K个值相同,那么所有能覆盖此子数组的所有的子数组都满足
  • 2:将左指针移动到刚好满足此数组达到K个值相同的最小子数组,
  • 可以得出 能够覆盖此最小子数组的所有个数是 (nums.length-right) * (left-preRight);
  • 其中 preRight记录上一次right指针的位置,为了方便计算,初始值设置为-1
  • 这个要多在纸上画图计算
public class My {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.nextLine();
        String[] strings = str.split(" ");
        int n = Integer.parseInt(strings[0]);
        int k = Integer.parseInt(strings[1]);
        String line = sc.nextLine();
        String[] split = line.split(" ");
        int[] nums = Arrays.stream(split).mapToInt(Integer::parseInt).toArray();

        //左指针
        int i = 0;
        int res = 0;
        Map<Integer, Integer> map = new HashMap<>();

        // 记录上一次r位置,为了方便计算,初始值设置为-1
        int preLeft = -1;
        for (int j = 0; j < nums.length; j++) {
            int val = nums[j];
            //指针到这时,窗口里val 的个数
            int sameNum = map.getOrDefault(val, 0) + 1;
            map.put(val, sameNum);
            //如果相同的个数>=k,那么所有能够覆盖此数组的都满足条件
            if (sameNum == k) {
                //不断的移动左指针,指针指向与有指针指向的值相同
                while (i < j) {
                    if (nums[i] == nums[j]) {
                        break;
                    }
                    // 左指针l移动过程中删除窗口外记录
                    map.put(nums[i], map.get(nums[i] - 1));
                    i++;
                }
                //算出还未统计的,且能覆盖此子数组的所有子数组个数(nums.length-j) * (i-preRight)
                res += (nums.length-j) * (i-preLeft);

                // 记录左指针
                preLeft = i;
                // 移除左指针元素
                map.put(val, map.get(val) - 1);
                i++;
            }
        }
        System.out.println(res);


    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值