全网最全面的华为OD机试真题汇总,100%原题题库,不需要开会员即可查看全部内容,更多考题请查看真题库。
真题库:https://www.yuque.com/codernav.com/od
题目:优雅数组
知识点双指针数组滑窗
时间限制:1s 空间限制:256MB 限定语言:不限
题目描述:
如果一个数组中出现次数最多的元素出现大于等于k次,被称为`k-优雅数组`,k也可以被称为`优雅阈值`。
例如,数组`[1, 2, 3, 1, 2, 3, 1]`,它是一个`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中的元素A[i]满足:1 <= A[i] <= n
输出描述:
数据一个整数,表示数组A中`k-优雅子数组`的数量
行尾不要有多余空格
示例1
输入:
7 3
1 2 3 1 2 3 1
输出:
1
说明:
只有子数组[1, 2, 3, 1, 2, 3, 1]是`3-优雅数组`
示例2
输入:
7 2
1 2 3 1 2 3 1
输出:
10
说明:
10个优雅子数组分别是(下标从0计数):
长度为4:[1, 2, 3, 1](下标0~3), [2, 3, 1, 2](下标1~4), [3, 1, 2, 3](下标2~5), [1, 2, 3, 1](下标3~6)
长度为5:[1, 2, 3, 1, 2](下标0~4), [2, 3, 1, 2, 3](下标1~5), [3, 1, 2, 3, 1](下标2~6)
长度为6:[1, 2, 3, 1, 2, 3](下标0~5), [2, 3, 1, 2, 3, 1](下标1~6)
长度为7:[1, 2, 3, 1, 2, 3, 1](下标0~6)
解题思路:
这道题使用滑窗和数组比较方便:
a、滑窗的左右指针就是数组的下标,用来截取数组。
b、数组用来记录截取数组中的各个元素的个数。
当left=0,right=0,lenInts[1] = 0 +1; lenInts=[0,1,0,0,0,0,0,0]; max=1<2,不符合右滑块向右滑动,left=0,right=1,lenInts[2] = 0 +1; lenInts=[0,1,1,0,0,0,0,0];max=1<2,不符合要求
右滑块向右滑动,left=0,right=2,lenInts[3]= 0+1; lenInts=[0,1,1,1,0,0,0,0];max=1<2,不符合要求
右滑块向右滑动,left=0,right=3,lenInts[1] = 1+1; lenInts=[0,2,1,1,0,0,0,0];max=2==2,符合要求。且后面的都符合要求,len - right= 7-3 =4
左滑块向右滑动,left=1,right=3,lenInts[1] = 2-1; lenInts=[0,1,1,1,0,0,0,0];max=1<2,不符合要求。
右滑块向右滑动,left=1,right=4,lenInts[2] =1+1; lenInts=[0,1,2,1,0,0,0,0];max=2==2,符合要求。且后面的都符合要求,len - right= 7-4 = 3
左滑块向右滑动,left=2,right=4,lenInts[2] = 2-1; lenInts=[0,1,1,1,0,0,0,0];max=1<2,不符合要求。
右滑块向右滑动,left=2,right=5,lenInts[3] = 1+1; lenInts=[0,1,1,2,0,0,0,0];max=2==2,符合要求。且后面的都符合要求,len - right= 7-5 = 2
左滑块向右滑动,left=3,right=5,lenInts[3] = 2-1; lenInts=[0,1,1,1,0,0,0,0];max=1<2,不符合要求。
右滑块向右滑动,left=3,right=6,lenInts[1] = 1+1; lenInts=[0,2,1,1,0,0,0,0];max=2==2,符合要求。且后面的都符合要求,len - right= 7-6= 1
代码实现:
package com.codernav.demo.hwod.exam; import java.util.Arrays; import java.util.Scanner; /** * @title 优雅数组 * @Description 如果一个数组中出现次数最多的元素出现大于等于k次,被称为`k-优雅数组`,k也可以被称为`优雅阈值`。 * 例如,数组`[1, 2, 3, 1, 2, 3, 1]`,它是一个`3-优雅数组`, * 因为元素`1`出现次数大于等于3次,数组`[1, 2, 3, 1, 2]`就不是一个`3-优雅数组`, * 因为其中出现次数最多的元素时`1`和`2`,只出现了2次。 * 给定一个数组A和k,请求出A有多少子数组是`k-优雅子数组`。 * 子数组是数组中一个或多个连续元素组成的数组。。 * @Author 开发者导航 * @website https://codernav.com * @date 2023/5/28 */ public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int k = sc.nextInt(); int[] ints = new int[n]; for (int i = 0; i < n; i++) { ints[i] = sc.nextInt(); } /** * 将数组中的数字作为index新建一个长度为A的lenInts数组(数组中元素<=n) * lenInts数组中的数字则为index出现的次数 */ int[] lenInts = new int[n + 1]; int res = 0; int right = 0; for (int i = 0; i < n; i++) { //相当于左滑块 if (i > 0) { lenInts[ints[i - 1]]--; //i==0时数组中没有数据所以需要区别开 } else { lenInts[ints[i]]++; } int max = Arrays.stream(lenInts).max().getAsInt(); //最大值为数组中元素出现的最多次数 if (max == k) { res += n - right; //最大次数已满足则后面自然都满足 continue; } for (int j = right + 1; j < n; j++) { //相当于右滑块 lenInts[ints[j]]++; max = Arrays.stream(lenInts).max().getAsInt(); if (max == k) { res += n - j; right = j; break; } } } System.out.println(res); } }
代码实现二:Java满分代码实现
package com.codernav.demo.hwod.exam; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Scanner; /** * @title 优雅数组 * @Description 如果一个数组中出现次数最多的元素出现大于等于k次,被称为`k-优雅数组`,k也可以被称为`优雅阈值`。 * 例如,数组`[1, 2, 3, 1, 2, 3, 1]`,它是一个`3-优雅数组`, * 因为元素`1`出现次数大于等于3次,数组`[1, 2, 3, 1, 2]`就不是一个`3-优雅数组`, * 因为其中出现次数最多的元素时`1`和`2`,只出现了2次。 * 给定一个数组A和k,请求出A有多少子数组是`k-优雅子数组`。 * 子数组是数组中一个或多个连续元素组成的数组。。 * @Author 开发者导航 * @website https://codernav.com * @date 2023/5/28 */ public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String[] input1 = sc.nextLine().split(" "); int n = Integer.parseInt(input1[0]); int k = Integer.parseInt(input1[1]); String[] input2 = sc.nextLine().split(" "); int[] num = Arrays.stream(input2).mapToInt(Integer::parseInt).toArray(); int len = num.length; // 记录有效优雅数组个数 int count = 0; // map存储已经滑动窗口内重复元素的个数 Map<Integer, Integer> map = new HashMap<>(); int index = -1; // 记录上一次r位置 int l = 0; for (int r = 0; r < len; r++) { // 寻找满足条件的右指针 map.put(num[r], map.getOrDefault(num[r], 0) + 1); if (map.get(num[r]) == k) { // 寻找满足条件的左指针 while (l < r) { if (num[l] == num[r]) { break; } // 左指针l移动过程中删除窗口外记录 map.put(num[l], map.get(num[l]) - 1); l++; } count += (num.length - r) * (l - index); // 记录左指针 index = l; // 移除左指针元素 map.put(num[r], map.get(num[r]) - 1); l++; } } System.out.println(count); } }