编写数组排列校验函数遇问题:非排列数组被误判
数组排列校验函数的问题修复
你的代码逻辑完全偏离了排列校验的需求,导致误判,核心问题如下:
- 循环里的
if (i == n)永远不会触发,因为循环条件是i < n,i的最大值是n-1,这个判断完全多余。 arr[n]属于数组越界访问,数组下标范围是0到n-1,访问这个位置会引发未定义行为。- 整个逻辑没有贴合排列的定义:排列要求数组包含
1到n(或0到n-1)的每个整数恰好一次,你的代码根本没做这个核心校验。
正确实现方案
以下两种方法均针对包含1到n的每个整数恰好一次的排列做校验,如果是0到n-1的排列,只需微调范围判断即可。
方法一:哈希集合校验(直观易读)
#include <stdbool.h> #include <stdlib.h> bool permutationChecker(int arr[], int n) { // 用数组模拟哈希集合,记录已出现的元素 int* seen = calloc(n + 1, sizeof(int)); if (!seen) return false; // 处理内存分配失败的情况 for (int i = 0; i < n; i++) { int num = arr[i]; // 检查元素是否在合法范围 if (num < 1 || num > n) { free(seen); return false; } // 检查元素是否重复出现 if (seen[num]) { free(seen); return false; } seen[num] = 1; } free(seen); return true; }
方法二:原地标记校验(空间复杂度O(1))
利用数组本身空间做标记,无需额外内存(会修改原数组,若需保留原数组优先用方法一):
#include <stdbool.h> #include <stdlib.h> bool permutationChecker(int arr[], int n) { for (int i = 0; i < n; i++) { int num = abs(arr[i]); // 先取绝对值,避免已标记的负数干扰 // 检查元素范围合法性 if (num < 1 || num > n) { return false; } // 对应位置已为负数,说明元素重复 if (arr[num - 1] < 0) { return false; } // 标记为负数,表示该元素已出现过 arr[num - 1] *= -1; } // 可选:恢复数组原状态(如果需要保留原数组数据) for (int i = 0; i < n; i++) { arr[i] = abs(arr[i]); } return true; }
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

