资讯动态

PTA 一维数组 7-3 动态删除重复元素实战

发布时间:2026/8/13 19:28:03 来源:尧图企业网站定制
1. 动态删除重复元素的场景需求在实际编程中处理数组数据时经常会遇到需要删除重复元素的情况。比如统计用户输入的数字时去除重复项或者处理传感器采集的数据时过滤掉重复值。PTA平台的这道题目正是模拟了这种常见需求。我刚开始学习数组操作时最头疼的就是如何在删除元素后保持数组的正确性。传统做法是创建一个新数组来存储非重复元素但这样会浪费内存空间。而题目要求的是原地修改数组这就需要更巧妙的算法设计。2. 题目分析与输入输出说明题目要求实现一个动态删除重复元素的程序。具体来说输入分为三部分第一行是一个整数n0n≤1000表示数组元素个数第二行是n个整数用空格分隔第三行是要删除的值m输出要求每次删除一个m后输出当前数组状态如果没有m则直接输出原数组例如输入样例110 5 8 7 12 17 15 3 7 7 10 7对应的输出应该是5 8 12 17 15 3 7 7 10 5 8 12 17 15 3 7 10 5 8 12 17 15 3 103. 基础解法思路与实现最直观的解法是遍历数组遇到要删除的元素时就将其后面的所有元素前移一位。这种方法虽然简单但效率较低时间复杂度为O(n²)。#includestdio.h void deleteElement(int arr[], int *n, int index) { for(int i index; i *n - 1; i) { arr[i] arr[i1]; } (*n)--; } int main() { int n, m; scanf(%d, n); int arr[n]; for(int i 0; i n; i) { scanf(%d, arr[i]); } scanf(%d, m); int count 0; for(int i 0; i n; i) { if(arr[i] m) count; } if(count 0) { for(int i 0; i n; i) { printf(%d , arr[i]); } return 0; } while(count--) { for(int i 0; i n; i) { if(arr[i] m) { deleteElement(arr, n, i); break; } } for(int i 0; i n; i) { printf(%d , arr[i]); } printf(\n); } return 0; }这个基础版本虽然能解决问题但每次删除都要移动大量元素效率不高。在实际项目中如果数组很大这种方法的性能会成为瓶颈。4. 优化解法双指针技巧更高效的解法是使用双指针技巧。我们维护两个指针一个快指针用于遍历数组一个慢指针用于指向下一个非删除元素的位置。#includestdio.h int main() { int n, m; scanf(%d, n); int arr[n]; for(int i 0; i n; i) { scanf(%d, arr[i]); } scanf(%d, m); int count 0; for(int i 0; i n; i) { if(arr[i] m) count; } if(count 0) { for(int i 0; i n; i) { printf(%d , arr[i]); } return 0; } int validSize n; for(int k 0; k count; k) { int slow 0; int deleted 0; for(int fast 0; fast validSize; fast) { if(arr[fast] m !deleted) { deleted 1; continue; } arr[slow] arr[fast]; } validSize--; for(int i 0; i validSize; i) { printf(%d , arr[i]); } printf(\n); } return 0; }这个优化版本的时间复杂度降到了O(n)因为每个元素最多被移动一次。我在实际项目中处理大规模数据时这种方法的性能提升非常明显。5. 边界条件与错误处理编写这类数组操作程序时特别需要注意边界条件空数组处理题目已经保证n0所以不需要额外处理没有要删除的元素直接输出原数组数组元素全是要删除的值需要确保程序不会崩溃内存边界确保不会访问越界测试用例应该包括普通情况有多个重复值没有要删除的值所有值都要删除只有一个元素且需要删除大数组测试接近1000个元素6. 实际应用中的扩展思考在实际开发中我们可能会遇到更复杂的需求删除所有重复值不是特定值保持原数组顺序或允许改变顺序处理更复杂的数据结构而非简单整数例如删除所有重复元素的算法可以这样实现void removeDuplicates(int arr[], int *n) { if(*n 0) return; int newSize 1; for(int i 1; i *n; i) { int j; for(j 0; j newSize; j) { if(arr[i] arr[j]) break; } if(j newSize) { arr[newSize] arr[i]; } } *n newSize; }这个算法的时间复杂度是O(n²)如果需要更高效率可以先排序O(nlogn)然后再去重O(n)。7. 性能对比与算法选择让我们比较几种不同解法的性能基础解法每次发现目标就移动后面所有元素最好情况O(n)没有要删除的元素最坏情况O(n²)所有元素都要删除双指针解法时间复杂度O(n)空间复杂度O(1)使用额外数组时间复杂度O(n)空间复杂度O(n)在PTA这类编程题中通常数据规模不大n≤1000所以基础解法也能通过。但在实际工程中面对百万级数据时双指针解法的优势就非常明显了。8. 常见错误与调试技巧新手在实现这类算法时容易犯的错误包括数组越界访问特别是在删除元素后没有及时调整数组大小漏删或多删元素循环条件或指针移动不当导致输出格式错误多余的空格或换行符调试技巧使用小规模测试数据手工模拟程序执行打印中间结果观察数组变化过程使用调试工具单步执行观察变量变化例如可以在每次删除操作后打印数组状态printf(After deletion %d: , k1); for(int i 0; i validSize; i) { printf(%d , arr[i]); } printf(\n);9. 举一反三类似题目练习为了巩固数组操作技巧可以尝试PTA上的这些类似题目7-1 将数组中的数逆序存放7-2 交换最小值和最大值7-4 数组循环左移7-7 冒泡法排序这些题目都涉及数组的遍历、元素交换和位置调整是很好的练习材料。我在初学阶段通过反复练习这些题目逐渐掌握了数组操作的要点。10. 工程实践中的注意事项在实际项目中使用这类算法时还需要考虑内存管理特别是动态分配数组时异常处理无效输入的处理代码可读性添加适当注释单元测试覆盖各种边界情况例如更健壮的实现可以添加输入验证if(scanf(%d, n) ! 1 || n 0 || n 1000) { printf(Invalid input size!\n); return 1; }记住编程题和工程实践的区别在于编程题通常假设输入是合法的而实际项目必须考虑各种异常情况。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价