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补全版。
-
函数参数:
- 编辑区的代码:
std::string solution(std::vector<int> &plates, int n) - 提供的代码:
std::string solution(std::vector<int> &plates) - 提供的代码去掉了多余的参数
n,因为plates.size()可以直接获取数组大小。
- 编辑区的代码:
-
变量初始化:
- 编辑区的代码:
int cnt = 0; int i, temp; - 提供的代码:
int i = 0; - 提供的代码更简洁,直接初始化了
i,去掉了不必要的变量cnt和temp。
- 编辑区的代码:
-
循环条件:
-
编辑区的代码:
while(i < size - 2) -
提供的代码:
while (i < size) -
提供的代码的循环条件更合理,确保遍历整个数组。
-
连续序列处理:
- 编辑区的代码:
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]) - 提供的代码更清晰地检查连续序列的开始,并且避免了数组越界。
- 编辑区的代码:
-
结果字符串拼接:
- 编辑区的代码:
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])); - 提供的代码更简洁,直接拼接起始和结束位置的字符串。(这里感觉我真的太蠢了)
- 编辑区的代码:
-
结果字符串连接:
- 编辑区的代码:未完成
- 提供的代码:
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补全版代码思路
-
初始化:
- 创建一个字符串向量
plate_pile来存储每个盘子的表示。 - 获取数组大小
size。 - 初始化索引
i为0。
- 创建一个字符串向量
-
遍历数组:
- 使用
while循环遍历数组,直到i达到数组大小。
- 使用
-
检查连续序列:
- 如果当前元素和接下来的两个元素构成连续递增序列(即
plates[i] + 1 == plates[i + 1] && plates[i + 1] + 1 == plates[i + 2]),则进入连续序列处理。 - 记录连续序列的起始位置
start。 - 使用
while循环继续检查后续元素是否构成连续序列,直到不连续为止。 - 将连续序列的起始和结束位置拼接成字符串,并添加到
plate_pile中。
- 如果当前元素和接下来的两个元素构成连续递增序列(即
-
处理单个盘子:
- 如果当前元素不构成连续序列,则直接将其转换为字符串并添加到
plate_pile中。
- 如果当前元素不构成连续序列,则直接将其转换为字符串并添加到
-
连接结果字符串:
- 使用
for循环将plate_pile中的所有字符串连接起来,中间用逗号分隔。
- 使用
-
返回结果:
- 返回最终拼接好的字符串。
-
除此之外,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算法:
std::adjacent_find:这个算法用于在容器中查找相邻的元素,返回第一个满足条件的元素对的位置。我们可以用它来查找不连续的元素。std::transform:这个算法用于对容器中的每个元素应用一个函数,并将结果存储在另一个容器中。我们可以用它来将整数转换为字符串。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;
}
代码解释
std::adjacent_find:我们使用std::adjacent_find来查找不连续的元素。如果找到不连续的元素,我们就知道当前的连续序列结束了。std::accumulate:我们使用std::accumulate来将字符串容器中的元素连接起来。这个算法接受一个初始值(这里是空字符串)和一个二元操作符(这里是连接字符串的操作符)。
使用STL算法可以使代码更简洁、更易读,并且通常也更高效。在这个例子中使用了std::adjacent_find来查找连续序列的结束点,并使用std::accumulate来连接最终的结果字符串。
总结
在学习过程中,我们总眼高手低,或许造成我如今代码能力如此差劲的原因就是当时我没有勤加练习,导致如今许多知识零散分布在我的大脑中并没有形成完整的体系,也没有解决实际问题的能力。
不论如何,希望看到这篇题解的你不要灰心,我们一起加油。
作者:用户37563614972
链接:juejin.cn/post/743971…
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。