青训营刷题-32

164 阅读6分钟

32 叠盘子

小明是个讲究生活质量的人,家里的一切都井井有条,比如说家中的盘子都是一个系列,每个盘子都标有唯一的一个整数作为标识。在每次吃完饭后,小明都会将这些盘子按照特定的顺序叠放收拾起来,收拾的规则如下:

  • 盘子叠放后会被分为多堆,每一堆都可能是由一个或多个盘子组成。
  • 叠放在同一堆的盘子的序号都是不间断递增的(例如 1,2,3 为不间断递增,而 1,3,4 则只是普通的递增),并且这些盘子的数量至少是 3 个。
  • 这些盘子的序号在被叠放之前就是递增的。

请你编写一个程序,帮助小明算一算盘子该如何叠放。

输入格式

输入由一行或多行组成,所有的数字以空格分隔:

  • 一行包含多个整数,表示盘子的序号,按叠放顺序排列。

注意:盘子的序号可能为负数,且不一定完全连续。

输出格式

输出一个字符串,每个堆被逗号分隔开:

  • 如果堆中只有一个盘子,就用序号表达。
  • 如果堆中有多个盘子(至少 3 个),用『起始编号』+『-』+『终止编号』来表达。

注意:每两个数之间用一个空格隔开,且最后一个数后面没有空格。

示例

示例 1

输入

-3 -2 -1 2 10 15 16 18 19 20

输出

-3--1,2,10,15,16,18-20

说明

  • 初始状态-3, -2, -1, 2, 10, 15, 16, 18, 19, 20

  • 分组过程

    • -3, -2, -1:连续递增且数量 ≥ 3,表示为 -3--1
    • 2:单独一个盘子,表示为 2
    • 10:单独一个盘子,表示为 10
    • 15, 16:仅两个连续盘子,数量 < 3,分别表示为 15,16
    • 18, 19, 20:连续递增且数量 ≥ 3,表示为 18-20
  • 最终分组-3--1,2,10,15,16,18-20

  • 输出结果-3--1,2,10,15,16,18-20

示例 2

输入

-6 -3 -2 -1 0 1 3 4 5 7 8 9 10 11 14 15 17 18 19 20

输出

-6,-3-1,3-5,7-11,14,15,17-20

说明

  • 初始状态-6, -3, -2, -1, 0, 1, 3, 4, 5, 7, 8, 9, 10, 11, 14, 15, 17, 18, 19, 20

  • 分组过程

    • -6:单独一个盘子,表示为 -6
    • -3, -2, -1, 0, 1:连续递增且数量 ≥ 3,表示为 -3-1
    • 3, 4, 5:连续递增且数量 ≥ 3,表示为 3-5
    • 7, 8, 9, 10, 11:连续递增且数量 ≥ 3,表示为 7-11
    • 14:单独一个盘子,表示为 14
    • 15:单独一个盘子,表示为 15
    • 17, 18, 19, 20:连续递增且数量 ≥ 3,表示为 17-20
  • 最终分组-6,-3-1,3-5,7-11,14,15,17-20

  • 输出结果-6,-3-1,3-5,7-11,14,15,17-20

示例 3

输入

1 2 7 8 9 10 11 19

输出

1,2,7-11,19

说明

  • 初始状态1, 2, 7, 8, 9, 10, 11, 19

  • 分组过程

    • 1:单独一个盘子,表示为 1
    • 2:单独一个盘子,表示为 2
    • 7, 8, 9, 10, 11:连续递增且数量 ≥ 3,表示为 7-11
    • 19:单独一个盘子,表示为 19
  • 最终分组1,2,7-11,19

  • 输出结果1,2,7-11,19

解题思路

本问题要求将一组盘子序号按照特定规则叠放,并以特定格式输出叠放后的结果。具体规则如下:

  1. 连续递增:盘子在同一堆中必须是连续递增的,即每个盘子的编号比前一个盘子编号大 1

  2. 最少数量:一个堆中至少包含 3 个盘子。

  3. 输出格式

    • 如果一个堆中只有一个盘子,直接输出其编号。
    • 如果一个堆中有多个盘子(至少 3 个),输出为 起始编号-终止编号

具体步骤

  1. 输入解析

    • 将输入的字符串按空格分隔,转换为整数数组 plateNums
  2. 排序

    • 虽然题目中提到盘子的序号在被叠放之前就是递增的,但为了确保数据的正确性,建议对 plateNums 进行排序。
  3. 分组

    • 遍历排序后的 plateNums,将连续递增的盘子分为一组。
    • 判断当前盘子是否与前一个盘子连续递增(即当前盘子编号等于前一个盘子编号加 1)。
    • 如果连续递增,则将当前盘子加入当前分组。
    • 否则,结束当前分组,将其加入结果列表,开始新的分组。
  4. 格式化输出

    • 遍历所有分组:

      • 如果分组中盘子的数量 ≥ 3,则格式化为 起始编号-终止编号
      • 否则,逐个输出盘子的编号。
    • 使用逗号 , 分隔各个堆。

  5. 边界条件

    • 空输入:如果没有盘子,输出为空。
    • 单个盘子:直接输出盘子的编号。
    • 全部盘子连续递增:输出为 起始编号-终止编号

复杂度分析

  • 时间复杂度

    • 排序:O(n log n),其中 n 是盘子的数量。
    • 分组与格式化:O(n)
    • 总体时间复杂度:O(n log n)
  • 空间复杂度

    • 需要额外的空间存储分组结果,O(n)

算法实现

import java.util.*;
public class Main {
    public static String solution(String plates) {
        // Please write your code here
        // 将输入的字符串转换为整数数组
        String[] plateStrs = plates.split(" ");
        int[] plateNums = new int[plateStrs.length];
        for (int i = 0; i < plateStrs.length; i++) {
            plateNums[i] = Integer.parseInt(plateStrs[i]);
        }

        // 用于存储分组的列表
        List<List<Integer>> groups = new ArrayList<>();
        List<Integer> currentGroup = new ArrayList<>();
        
        for (int i = 0; i < plateNums.length; i++) {
            // 如果是第一个数字,直接添加到当前分组
            if (i == 0) {
                currentGroup.add(plateNums[i]);
                continue;
            }

            // 如果当前数字与前一个数字连续
            if (plateNums[i] == plateNums[i - 1] + 1) {
                currentGroup.add(plateNums[i]);
            } else {
                groups.add(currentGroup);
                // 创建新的分组
                currentGroup = new ArrayList<>();
                currentGroup.add(plateNums[i]);
            }
        }
        if(currentGroup.size() > 0){
            groups.add(currentGroup);
        }

        // 构建输出字符串
        StringBuilder sb = new StringBuilder();

        for (List<Integer> group : groups) {
            if(group.size() >= 3){
                //
                sb.append(group.get(0)).append("-").append(group.get(group.size()-1)).append(",");
            }else{
                for(int num : group){
                    sb.append(num).append(",");
                }
            }
        }
        if(sb.length() > 0){
            sb.deleteCharAt(sb.length() - 1);
        }
        // System.out.println(sb.toString());
        return sb.toString();
    }

    public static void main(String[] args) {
        //  You can add more test cases here
        System.out.println(solution("-3 -2 -1 2 10 15 16 18 19 20").equals("-3--1,2,10,15,16,18-20"));
        System.out.println(solution("-6 -3 -2 -1 0 1 3 4 5 7 8 9 10 11 14 15 17 18 19 20").equals("-6,-3-1,3-5,7-11,14,15,17-20"));
        System.out.println(solution("1 2 7 8 9 10 11 19").equals("1,2,7-11,19"));
    }
}