74.叠盘子排序学习历程分享 | 豆包MarsCode AI刷题

50 阅读9分钟

74叠盘子排序

作者情况:本人代码能力较弱,代码思维欠缺,所以正在进行简单题型的训练,在做题过程中找到知识漏洞加以补充。

问题描述

在每次吃完饭后,小明都会将这些盘子按照特定的顺序叠放收拾起来,收拾的规则如下:

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

请问你可以编写一个程序,帮助小明算一算盘子该如何叠放么?

输入格式

空格分隔输入所有的数字

输出格式

一个字符串,每个堆被逗号分隔开,如果堆中只有一个盘子,就用序号表达;如果堆中有多个盘子,用『起始编号』+『-』+『终止编号』来表达。

输入样例(1)

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

输出样例(1)

"-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

输出样例(2)

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

我的尝试解题过程

1.我的代码

c
 代码解读
复制代码
  #include <iostream>
  #include <string>
  #include <vector>std::string solution(std::vector<int> &plates, int n) {
    //plates序列已经是递增的序列
    //初始化
    std::vector<std::string> plate_pile; 
    int size = plates.size();
    int cnt = 0;
    int i, temp;
    std::string result_str;
    while(i < size - 2){
      if((plates[i] + 1 != plates[i + 1]) && (plates[i + 1] + 1 != plates[i + 2])){
        //单个盘子;
        plate_pile.push_back(std::to_string(plates[i]));
      }else{
        cnt = 3;//已经有三个不间断递增的盘子,从i到i+2
        result_str = std::to_string(plates[i]) + "-" + std::to_string(plates[i + 1]) + "-" + std::to_string(plates[i + 2]);
        temp = i + 3;
        while(plates[temp] == plates[temp - 1] + 1){
          cnt++;
          result_str += std::to_string(plates[temp]);
          temp++;
        }   
        plate_pile.push_back(result_str);
      }
    }
      
    //写到这里有点写不下去了
  ​
    //连接起来
    return "";
  }
  ​
  int main() {
    //  You can add more test cases here
    std::vector<int> plates1 = {-3, -2, -1, 2, 10, 15, 16, 18, 19, 20};
    std::cout << (solution(plates1, 10) == "-3--1,2,10,15,16,18-20") << std::endl;
  ​
    std::vector<int> plates2 = {-6, -3, -2, -1, 0,  1,  3,  4,  5,  7,
                                8,  9,  10, 11, 14, 15, 17, 18, 19, 20};
    std::cout << (solution(plates2, 20) == "-6,-3-1,3-5,7-11,14,15,17-20")
              << std::endl;
  ​
    std::vector<int> plates3 = {1, 2, 7, 8, 9, 10, 11, 19};
    std::cout << (solution(plates3, 8) == "1,2,7-11,19") << std::endl;
  ​
    return 0;
  }
  ​

写到这里相信大家能够看出来我的思路非常直接,几乎没有任何技巧可言,而且此时我对于如何判断plates数组最后三个元素之间是否满足不间断递增关系没有很好的思路,我想,与其浪费时间在这个问题上面,不如选择借助ai工具将其中的问题看明白,并拓宽新的思路。

于是,我对ai说:

请帮我在现有的代码上补充完整,另外提供其他更优质的解决思路。

2.我的代码(ai补全版)

c
 代码解读
复制代码
  #include <iostream>
  #include <string>
  #include <vector>std::string solution(std::vector<int> &plates) {
      std::vector<std::string> plate_pile; 
      int size = plates.size();
      int i = 0;
  ​
      while (i < size) {
          if (i + 2 < size && plates[i] + 1 == plates[i + 1] && plates[i + 1] + 1 == plates[i + 2]) {
              // 找到一个不间断递增的序列
              int start = i;
              while (i + 1 < size && plates[i] + 1 == plates[i + 1]) {
                  i++;
              }
              plate_pile.push_back(std::to_string(plates[start]) + "-" + std::to_string(plates[i]));
          } else {
              // 单个盘子
              plate_pile.push_back(std::to_string(plates[i]));
          }
          i++;
      }
  ​
      // 连接起来
      std::string result_str;
      for (size_t j = 0; j < plate_pile.size(); ++j) {
          if (j > 0) result_str += ",";
          result_str += plate_pile[j];
      }
      return result_str;
  }
  //测试代码...

可以看到,在我的思路上,ai做了一些改进,例如对plates最后两个元素的考虑上,并没有单独处理,而是跟着单个盘子一起处理。

代码对比

编辑区的代码指的是我写的那段代码;提供的代码指的是ai补全版。

  1. 函数参数

    • 编辑区的代码:std::string solution(std::vector<int> &plates, int n)
    • 提供的代码:std::string solution(std::vector<int> &plates)
    • 提供的代码去掉了多余的参数n,因为plates.size()可以直接获取数组大小。
  2. 变量初始化

    • 编辑区的代码:int cnt = 0; int i, temp;
    • 提供的代码:int i = 0;
    • 提供的代码更简洁,直接初始化了i,去掉了不必要的变量cnttemp
  3. 循环条件

    • 编辑区的代码:while(i < size - 2)

    • 提供的代码:while (i < size)

    • 提供的代码的循环条件更合理,确保遍历整个数组。

    1. 连续序列处理

      • 编辑区的代码:if((plates[i] + 1 != plates[i + 1]) && (plates[i + 1] + 1 != plates[i + 2]))
      • 提供的代码:if (i + 2 < size && plates[i] + 1 == plates[i + 1] && plates[i + 1] + 1 == plates[i + 2])
      • 提供的代码更清晰地检查连续序列的开始,并且避免了数组越界。
    2. 结果字符串拼接

      • 编辑区的代码:result_str = std::to_string(plates[i]) + "-" + std::to_string(plates[i + 1]) + "-" + std::to_string(plates[i + 2]);
      • 提供的代码:plate_pile.push_back(std::to_string(plates[start]) + "-" + std::to_string(plates[i]));
      • 提供的代码更简洁,直接拼接起始和结束位置的字符串。(这里感觉我真的太蠢了)
    3. 结果字符串连接

      • 编辑区的代码:未完成
      • 提供的代码:
      ini
       代码解读
      复制代码
        
        std::string result_str; 
        for (size_t j = 0; j < plate_pile.size(); ++j) {
            if (j > 0) result_str += ","; 
            result_str += plate_pile[j]; 
        }
      

    提供的ai补全版代码思路

    1. 初始化

      • 创建一个字符串向量plate_pile来存储每个盘子的表示。
      • 获取数组大小size
      • 初始化索引i为0。
    2. 遍历数组

      • 使用while循环遍历数组,直到i达到数组大小。
    3. 检查连续序列

      • 如果当前元素和接下来的两个元素构成连续递增序列(即plates[i] + 1 == plates[i + 1] && plates[i + 1] + 1 == plates[i + 2]),则进入连续序列处理
      • 记录连续序列的起始位置start
      • 使用while循环继续检查后续元素是否构成连续序列,直到不连续为止
      • 将连续序列的起始和结束位置拼接成字符串,并添加到plate_pile中。
    4. 处理单个盘子

      • 如果当前元素不构成连续序列,则直接将其转换为字符串并添加到plate_pile中。
    5. 连接结果字符串

      • 使用for循环将plate_pile中的所有字符串连接起来,中间用逗号分隔。
    6. 返回结果

      • 返回最终拼接好的字符串。

除此之外,ai提供了两个更优质的解决思路:

解法1:双指针法

双指针法可以更高效地处理连续递增序列的问题。一个指针用于遍历整个数组,另一个指针用于标记连续递增序列的起始位置。

c
 代码解读
复制代码
  
  #include <iostream>
  #include <string>
  #include <vector>std::string solution(std::vector<int> &plates) {
      std::vector<std::string> plate_pile; 
      int size = plates.size();
      int i = 0;
  ​
      while (i < size) {
          int start = i;
          while (i + 1 < size && plates[i] + 1 == plates[i + 1]) {
              i++;
          }
          if (i - start >= 2) {
              plate_pile.push_back(std::to_string(plates[start]) + "-" + std::to_string(plates[i]));
          } else {
              for (int j = start; j <= i; ++j) {
                  plate_pile.push_back(std::to_string(plates[j]));
              }
          }
          i++;
      }
  ​
      // 连接起来
      std::string result_str;
      for (size_t j = 0; j < plate_pile.size(); ++j) {
          if (j > 0) result_str += ",";
          result_str += plate_pile[j];
      }
      return result_str;
  }
  //测试代码...

解法2:STL算法

STL算法介绍

C++标准库(STL)提供了许多强大的算法,可以帮助我们更高效地处理数据。在本题中,我们可以使用以下几个STL算法:

  1. std::adjacent_find:这个算法用于在容器中查找相邻的元素,返回第一个满足条件的元素对的位置。我们可以用它来查找不连续的元素。
  2. std::transform:这个算法用于对容器中的每个元素应用一个函数,并将结果存储在另一个容器中。我们可以用它来将整数转换为字符串。
  3. std::accumulate:这个算法用于将容器中的元素累加起来,并返回累加结果。我们可以用它来将字符串容器中的元素连接起来。

使用STL算法解决本题的示例

以下是使用STL算法解决本题的示例代码:

c
 代码解读
复制代码
  
  #include <iostream>
  #include <string>
  #include <vector>
  #include <algorithm>
  #include <numeric>std::string solution(std::vector<int> &plates) {
      std::vector<std::string> plate_pile; 
      int size = plates.size();
      int i = 0;
  ​
      while (i < size) {
          auto it = std::adjacent_find(plates.begin() + i, plates.end(), [](int a, int b) { return a + 1 != b; });
          if (it != plates.end()) {
              int start = i;
              int end = it - plates.begin();
              if (end - start >= 2) {
                  plate_pile.push_back(std::to_string(plates[start]) + "-" + std::to_string(plates[end]));
              } else {
                  for (int j = start; j <= end; ++j) {
                      plate_pile.push_back(std::to_string(plates[j]));
                  }
              }
              i = end + 1;
          } else {
              break;
          }
      }
  ​
      // 连接起来
      std::string result_str = std::accumulate(plate_pile.begin(), plate_pile.end(), std::string(),
          [](const std::string& a, const std::string& b) {
              return a.empty() ? b : a + "," + b;
          });
      return result_str;
  }
  ​
  int main() {
      std::vector<int> plates1 = {-3, -2, -1, 2, 10, 15, 16, 18, 19, 20};
      std::cout << (solution(plates1) == "-3--1,2,10,15,16,18-20") << std::endl;
  ​
      std::vector<int> plates2 = {-6, -3, -2, -1, 0,  1,  3,  4,  5,  7,
                                  8,  9,  10, 11, 14, 15, 17, 18, 19, 20};
      std::cout << (solution(plates2) == "-6,-3-1,3-5,7-11,14,15,17-20") << std::endl;
  ​
      std::vector<int> plates3 = {1, 2, 7, 8, 9, 10, 11, 19};
      std::cout << (solution(plates3) == "1,2,7-11,19") << std::endl;
  ​
      return 0;
  }
代码解释
  1. std::adjacent_find:我们使用std::adjacent_find来查找不连续的元素。如果找到不连续的元素,我们就知道当前的连续序列结束了。
  2. std::accumulate:我们使用std::accumulate来将字符串容器中的元素连接起来。这个算法接受一个初始值(这里是空字符串)和一个二元操作符(这里是连接字符串的操作符)。

使用STL算法可以使代码更简洁、更易读,并且通常也更高效。在这个例子中使用了std::adjacent_find来查找连续序列的结束点,并使用std::accumulate来连接最终的结果字符串。

总结

在学习过程中,我们总眼高手低,或许造成我如今代码能力如此差劲的原因就是当时我没有勤加练习,导致如今许多知识零散分布在我的大脑中并没有形成完整的体系,也没有解决实际问题的能力。

不论如何,希望看到这篇题解的你不要灰心,我们一起加油。

作者:用户37563614972
链接:juejin.cn/post/743971…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。