华为OD机试 - 根据某条件聚类最少交换次数 - 滑动窗口(Java 2024 E卷 100分)

文章讲述了在Java中使用滑动窗口算法解决数字K下整数组合最小交换次数的问题,提供了解题步骤和示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、题目描述

给出数字K,请输出所有结果小于K的整数组合到一起的最少交换次数。

组合一起是指满足条件的数字相邻,不要求相邻后在数组中的位置。

数据范围

-100 <=K <= 100

-100 <= 数组中数值 <= 100

二、输入描述

第一行输入数组:1 3 1 4 0

第二行输入K数值:2

三、输出描述

第一行输出最少较好次数:1

备注:

小于2的表达式是 1 1 0,共三种可能将所有符合要求数字组合在一起,最少交换1次

四、测试用例

测试用例1

1、输入

1 3 1 4 0
2

2、输出

1

3、说明

满足条件(< 2)的数字为:1, 1, 0,共 3 个。

滑动窗口情况:

窗口 [1,3,1]:满足 2 个
窗口 [3,1,4]:满足 1 个
窗口 [1,4,0]:满足 2 个

最大为 2,则交换次数 = 3 - 2 = 1

测试用例2

1、输入

5 1 3 2 4
4

2、输出

0

3、说明

满足条件(< 4)的数字为:1, 3, 2,共 3 个。

可选窗口:[1,3,2]已经连续,交换次数 = 3 - 3 = 0

五、解题思路

题目要求将数组中所有满足“数字 < K”的元素组合到一起(即在最终排列中相邻,原位置不要求连续),要求求出最少交换次数。核心思路是:

1、统计满足条件的元素个数(记为 targetCount)

这些元素最终要组合到一起,所以在数组中必然有一段连续区间长度为 targetCount。

2、滑动窗口求最大匹配数

用一个长度为 targetCount 的窗口,在数组上滑动,统计窗口内已有多少个满足“< K”的数字。

假设窗口内最多包含 maxCount 个满足条件的数字,那么只需要交换(targetCount – maxCount)个数字即可把窗口内“不满足”的数字换成满足条件的数字,从而将所有满足条件的数字组合在一起。

3、时间复杂度 O(n)

用数组、计数器与滑动窗口完成,不需要额外复杂数据结构。

4、具体解题步骤

  1. 确定滑动窗口大小,滑动窗口的大小取决于有多少个数小于k,假定总共有m个数小于k,这个数值即为滑动窗口的长度;
  2. 让滑动窗口从数组起始端向右滑动,每滑动一位,就计算出当前窗口内有多少个数小于k,将这些统计数字做比较,找出最大的,假定窗口内最多有n个数小于k;
  3. m与n的差值就是需要交换的次数。

六、Java算法源码

package com.guor.od;

import java.util.*;

public class OdTest02 {

    /**
     * 给出数字K,请输出所有结果小于K的整数组合到一起的最少交换次数
     */
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int[] arr = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
        int K = sc.nextInt();

        // 遍历数组,找出数组里面有多少个数字小于K,确定滑动窗口大小
        int target = 0;
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] < K) {
                target++;
            }
        }

        // 滑动窗口左起点
        int left = 0;
        // 滑动窗口右终点
        int right = target - 1;
        // 记录当前窗口范围内有多少个数字小于K
        int okSum = 0;
        // 再遍历一次,确定初始窗口内有多少个数小于K
        for (int i = 0; i <= right; i++) {
            if (arr[i] < K) {
                okSum++;
            }
        }

        // max用来记录窗口内最多有多少个数小于K
        int max = okSum;
        // 窗口不停的向右滑动
        while (right < arr.length - 1) {
            // 左边滑出
            if (arr[left++] < K) {
                okSum--;
            }
            // 右边滑入
            if (arr[++right] < K) {
                okSum++;
            }
            if (okSum > max) {
                max = okSum;
            }
        }
        System.out.println(target - max);
    }
}

七、效果展示

1、输入

1 2 3 4 2
3

2、输出

1

3、说明

(1)根据解题思路:

  1. 确定滑动窗口大小,滑动窗口的大小取决于有多少个数小于k,假定总共有m个数小于k,这个数值即为滑动窗口的长度;
  2. 让滑动窗口从数组起始端向右滑动,每滑动一位,就计算出当前窗口内有多少个数小于k,将这些统计数字做比较,找出最大的,假定窗口内最多有n个数小于k;
  3. m与n的差值就是需要交换的次数。

(2)具体解题思路:

  1. 滑动窗口的大小取决于有多少个数小于k --> m = 3;
  2. 滑动窗口大小为3,每三个一滑,计算当前窗口内有多少个数小于k;
    • 1 2 3 --> 2个
    • 2 3 4 --> 1个
    • 3 4 2 --> 1个
  3. 将这些统计数字做比较,找出最大的n=2。
  4. m与n的差值就是需要交换的次数,即1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值