• 华为OD机考算法题:根据某条件聚类最少交换次数


    目录

    题目部分

    解读与思路

    代码实现


    题目部分

    题目根据某条件聚类最少交换次数
    难度
    题目说明给出数字K,请输出所有结果小于K的整数组合到一起的最少交换次数。
    组合一起是指满足条件的数字相邻,不要求相邻后在数组中的位置。
    数据范围
    -100 <=K <= 100
    -100 <= 数组中数值 <= 100
    输入描述第一行输入数组:1 3 1 4 0
    第二行输入K数值:2
    输出描述第一行输出最少较好次数:1
    补充说明小于2的表达式是 1 1 0,共三种可能将所有符合要求数字组合在一起,最少交换1次。
    没有数字小于K,即不存在满足条件的数字时,返回 0。
    交换规则为,任意两个位置的数字可以相互交换。(笔者注)
    -----------------------------------------
    示例
    示例1
    输入1 3 1 4 0
    2
    输出1
    说明
    示例2
    输入0 0 0 1 0
    2
    输出0
    说明
    示例3
    输入2 3 2
    1
    输出0
    说明


    解读与思路

    题目解读

    第一行输入整形数字 K,第二行输入一串整形数字(假设这一串整形数字存放在一个数组中)。

    题目要求,从第二行整形数字中,找出所有小于 K 的数字。然后通过交换位置的方式,使找出的这些数字聚合在一块。

    • 聚合在一块的意思是,这些数字两两相邻,中间不存在不符合条件(大于或等于K)的数字。
    • 交换位置的规则是,数组(根据之前的假设,数字存放在数组中)中的任意两个下标的数字交换都可以交换位置。

    在示例 1 中,下标为0的数字 1和下标为3的数字4交换后,数字串变成了 4 3 1 0。此时,从第2个元素到第4个元素,这3个数字全都小于2(K等于2)。再次过程中,交换了1次。

    特别注意,在示例 3 中,没有数字小于K,即不存在满足条件的数字时,返回 0。

    此题立意很好,但在表述上还有很大的提升空间。
    题干应该准确描述背景、条件和要求。晦涩难懂或有歧义的题目容易产生误导。示例作用是进一步印证题干的描述,而不应用于补充题目说明。
    出题人在描述问题时,部分隐含条件没有描述出来(当找不到满足条件的交换次数时,返回值应该是多少),而且表述不够清晰(应明示交换规则为,任意两个位置的数字可以相互交换),需要结合示例才能准确理解题目意思。

    分析与思路

    第一行输入的数字设为 k。
    第二行输入的一串数字,把它存到一个整形数组 arr[] 中。

    先遍历数组 arr,统计 arr 中小于 k 的数字个数 count,并记录这些数字的最小下标 minIdx 和 最大下标 maxIdx。如果 count 为 0,则直接返回 0。

    题目要求小于 k 的数字聚合在一起,那么最终聚合的块的数字是连续的,假设聚合块中数字的最小下标为 iMin,最大小标为 iMax,那么 iMax - iMin == count - 1,且下标在iMin与iMax之间的所有数字都小于 k 。

    对于原始数组,如果某个小于 k 的数字,其在 arr 中的下标处于闭区间 [iMin, iMax] 中,那么它不需要交换;如果在此闭区间之外,需要和其他下标在 [ iMin, iMax ] 中且大于 k 的数字交换。显而易见,交换次数为 [iMin, iMax] 这个闭区间(闭区间为arr数组的下标)中大于 k 的数字的个数。

    由于 iMin >= minIdx,iMax >= maxIdx,此题的要求可以转换成,从 [minIdx, maxIdx] 这个闭区间中,找出一个长度为 count 的闭区间(闭区间为arr数组的下标),使 arr 数组中大于 k 的数字的个数最小。计算出的最小个数,即为最终的输出。

    此算法需要遍历数组两次(第二次只需要遍历 [ minIdx, maxIdx - count ]),其时间复杂度为 O(n)。实现过程中使用了辅助数组用于存储数字,空间复杂度为 O(n)。


    代码实现

    Java代码

    1. import java.util.Scanner;
    2. /**
    3. * 根据某条件聚类最少交换次数
    4. *
    5. * @since 2023.09.13
    6. * @version 0.2
    7. * @author Frank
    8. *
    9. */
    10. public class TogetherChgCnt {
    11. public static void main(String[] args) {
    12. Scanner sc = new Scanner(System.in);
    13. while (sc.hasNext()) {
    14. // 第一行输入一串数字,以空格分隔
    15. String stream = sc.nextLine();
    16. String[] strArr = stream.split(" ");
    17. int[] arr = new int[strArr.length];
    18. for (int i = 0; i < strArr.length; i++) {
    19. arr[i] = Integer.parseInt(strArr[i]);
    20. }
    21. // 第二行, k
    22. String strK = sc.nextLine();
    23. int k = Integer.parseInt(strK);
    24. processTogetherChgCnt(k, arr);
    25. }
    26. }
    27. private static void processTogetherChgCnt(int k, int[] arr) {
    28. int minIdx = -1;
    29. int maxIdx = -1;
    30. int count = 0;
    31. for (int i = 0; i < arr.length; i++) {
    32. if (arr[i] >= k) {
    33. continue;
    34. }
    35. count++;
    36. if (minIdx == -1) {
    37. minIdx = i;
    38. maxIdx = i;
    39. } else {
    40. maxIdx = i;
    41. }
    42. }
    43. if (count == 0) {
    44. System.out.println(0);
    45. return;
    46. }
    47. int curCnt = 0;
    48. for (int i = 0; i < count; i++) {
    49. if (arr[minIdx + i] >= k) {
    50. curCnt++;
    51. }
    52. }
    53. int rangeCnt = curCnt;
    54. int stepSize = maxIdx - minIdx - count + 1;
    55. // 在区间[ minIdx, maxIdx ]范围内,
    56. // 逐个向右移动,计算移动后的闭区间中大于 k 的个数 curCnt。
    57. for (int i = 0; i < stepSize; i++) {
    58. if (arr[minIdx + i] >= k) {
    59. curCnt--;
    60. }
    61. if (arr[minIdx + count + i] >= k) {
    62. curCnt++;
    63. }
    64. if (curCnt < rangeCnt) {
    65. rangeCnt = curCnt;
    66. }
    67. }
    68. System.out.println(rangeCnt);
    69. }
    70. }

    JavaScript代码

    1. const rl = require("readline").createInterface({ input: process.stdin });
    2. var iter = rl[Symbol.asyncIterator]();
    3. const readline = async () => (await iter.next()).value;
    4. void async function() {
    5. while (line = await readline()) {
    6. // 第一行数据转换成数组
    7. var arr = line.split(" ");
    8. for (var i = 0; i < arr.length; i++) {
    9. arr[i] = parseInt(arr[i]);
    10. }
    11. // 第二行数据,k
    12. line = await readline();
    13. var k = parseInt( line );
    14. processTogetherChgCnt(k, arr);
    15. }
    16. }();
    17. function processTogetherChgCnt(k, arr) {
    18. var minIdx = -1;
    19. var maxIdx = -1;
    20. var count = 0;
    21. for (var i = 0; i < arr.length; i++) {
    22. if (arr[i] >= k) {
    23. continue;
    24. }
    25. count++;
    26. if (minIdx == -1) {
    27. minIdx = i;
    28. maxIdx = i;
    29. } else {
    30. maxIdx = i;
    31. }
    32. }
    33. if (count == 0) {
    34. console.log(0);
    35. return;
    36. }
    37. var curCnt = 0;
    38. for (var i = 0; i < count; i++) {
    39. if (arr[minIdx + i] >= k) {
    40. curCnt++;
    41. }
    42. }
    43. var rangeCnt = curCnt;
    44. var stepSize = maxIdx - minIdx - count + 1;
    45. for (var i = 0; i < stepSize; i++) {
    46. if (arr[minIdx + i] >= k) {
    47. curCnt--;
    48. }
    49. if (arr[minIdx + count + i] >= k) {
    50. curCnt++;
    51. }
    52. if (curCnt < rangeCnt) {
    53. rangeCnt = curCnt;
    54. }
    55. }
    56. console.log(rangeCnt);
    57. }

    (完)

  • 相关阅读:
    IDEA web工程入门笔记
    Git Cherry-pick使用
    【FastAPI】实现服务器向客户端发送SSE(Server-Sent Events)广播
    《GB/T 8566-2022/ISO/IEC/IEEE:系统与软件工程生存周期过程》国家标准解读,附下载地址
    UE4创建一个左右摇摆的“喷泉”
    springcloud7:服务注册与发现总结篇
    从运维到运维大神,只需要一个正确的选择
    Github每日精选(第40期):为 Windows 带来 macOS “快速查看”功能QuickLook
    为什么u盘在mac上显示不出来
    【开发问题系列】CSV转Excel
  • 原文地址:https://blog.csdn.net/ZiJinShi/article/details/132685954