当前位置: 首页 > news >正文

华为OD机试:按个位数稳定排序数组的实现

1. 题目解析与需求拆解

这道华为OD机试题的核心要求是:对整型数组按照元素的个位数(十进制最低位)进行升序排序,同时保持个位数相同的元素在原数组中的相对顺序不变。这实际上考察了两个关键点:

  1. 稳定排序算法的应用:需要确保相同个位数的元素保持原始相对顺序
  2. 自定义排序规则的实现:需要提取数字的个位数作为排序依据

举个例子,给定数组[12, 34, 56, 72, 28, 91],其个位数分别是[2,4,6,2,8,1],排序后应该得到[91, 12, 72, 34, 56, 28]。注意其中12和72的个位数都是2,它们在结果中保持了原始输入时的相对顺序。

2. 算法设计与实现思路

2.1 核心算法选择

这类自定义排序问题通常有两种实现路径:

  1. 修改比较函数:在标准排序算法中注入自定义比较逻辑
  2. 装饰-排序-去装饰模式:为每个元素计算排序键值,排序后再去除键值

考虑到题目要求保持相同键值元素的相对顺序,我们需要选择稳定排序算法。各语言内置的排序方法稳定性如下:

语言排序方法是否稳定
Pythonsorted()
JSArray.sort()实现相关
C++std::stable_sort
Cqsort()

2.2 各语言实现方案

2.2.1 Python实现

Python的sorted()函数天然稳定,且支持自定义键函数:

def sort_by_last_digit(arr): return sorted(arr, key=lambda x: x % 10)

关键点:x % 10获取个位数,lambda函数作为key参数传递给sorted()

2.2.2 JavaScript实现

现代JS引擎的Array.sort()通常是稳定的,但需要注意比较函数的写法:

function sortByLastDigit(arr) { return arr.slice().sort((a, b) => (a % 10) - (b % 10)); }

注意:这里使用slice()创建副本以避免修改原数组

2.2.3 C++实现

使用std::stable_sort保证稳定性:

#include <algorithm> #include <vector> std::vector<int> sortByLastDigit(std::vector<int>& arr) { std::stable_sort(arr.begin(), arr.end(), [](int a, int b) { return (a % 10) < (b % 10); }); return arr; }
2.2.4 C语言实现

由于qsort()不稳定,需要手动实现稳定排序:

#include <stdlib.h> typedef struct { int value; int index; } Element; int compare(const void* a, const void* b) { Element* ea = (Element*)a; Element* eb = (Element*)b; int lastA = ea->value % 10; int lastB = eb->value % 10; if (lastA != lastB) return lastA - lastB; return ea->index - eb->index; } void sortByLastDigit(int* arr, int size) { Element* elements = malloc(size * sizeof(Element)); for (int i = 0; i < size; i++) { elements[i].value = arr[i]; elements[i].index = i; } qsort(elements, size, sizeof(Element), compare); for (int i = 0; i < size; i++) { arr[i] = elements[i].value; } free(elements); }

3. 边界条件与测试用例

3.1 常见边界情况

  1. 负数处理-123的个位数应该是3(-123 % 10在多数语言中得-3,需要特殊处理)
  2. 大数处理:当数字超过INT_MAX时的处理
  3. 空数组输入:应该返回空数组而非报错
  4. 全相同个位数:应保持原数组顺序不变

3.2 测试用例设计

输入数组预期输出测试要点
[12, 34, 56, 72, 28, 91][91, 12, 72, 34, 56, 28]基本功能验证
[-123, 45, -67, 89][45, -123, -67, 89]负数处理
[111, 222, 333, 444][111, 222, 333, 444]全相同个位数
[][]空数组处理
[5, 15, 25, 35, 45][5, 15, 25, 35, 45]已排序数组保持顺序

4. 性能分析与优化

4.1 时间复杂度分析

各语言实现的时间复杂度主要取决于使用的排序算法:

  • Python/Timsort: O(n log n)
  • JavaScript: 通常为O(n log n)
  • C++ std::stable_sort: O(n log n)
  • C语言实现: O(n log n)

4.2 空间复杂度优化

对于C语言的实现,可以通过以下方式优化空间使用:

  1. 原位排序:修改原始数组而非创建副本
  2. 索引数组:只存储原始索引而非整个Element结构
  3. 基数排序:针对个位数排序的特殊性,可以使用基数排序的变种

优化后的C实现示例:

void sortByLastDigitOptimized(int* arr, int size) { int* indices = malloc(size * sizeof(int)); for (int i = 0; i < size; i++) indices[i] = i; // 使用插入排序保持稳定性 for (int i = 1; i < size; i++) { int key = arr[i] % 10; int orig_idx = indices[i]; int j = i - 1; while (j >= 0 && (arr[j] % 10) > key) { arr[j + 1] = arr[j]; indices[j + 1] = indices[j]; j--; } arr[j + 1] = arr[i]; indices[j + 1] = orig_idx; } free(indices); }

5. 实际编码中的常见问题

5.1 负数处理陷阱

许多初学者会忽略负数取模的问题。在C/C++中,-123 % 10得到的是-3而非7。正确的处理方式应该是:

def get_last_digit(x): return abs(x) % 10 # 处理负数情况

5.2 稳定性误解

有些开发者会误认为所有语言的sort()都是稳定的。实际上:

JavaScript在ES2019之前不要求sort()的稳定性,不同引擎实现可能不同

5.3 原地修改问题

在JavaScript中,Array.sort()会修改原数组。良好的实践应该是:

const sorted = [...arr].sort(compareFn); // 使用扩展运算符创建副本

5.4 大数处理

当数字非常大时(超过2^53),JavaScript会出现精度问题。解决方案:

function getLastDigitBigInt(x) { return Number(BigInt(x) % 10n); }

6. 扩展思考与变种题目

6.1 变种题目示例

  1. 按十位数排序:修改为(x // 10) % 10
  2. 多级排序:先按个位数,再按十位数
  3. 字符串数字排序:处理字符串形式的数字

6.2 实际应用场景

  1. 文件排序:按文件大小末位数字分类
  2. 哈希分片:根据ID末位进行数据分片
  3. 视觉布局:按某种特征值末位分组展示

6.3 算法选择进阶

对于超大规模数据(如1亿个数字),可以考虑:

  1. 基数排序:针对固定位数特别高效
  2. 并行排序:利用多线程/多进程加速
  3. 外排序:处理无法全部装入内存的数据

我在实际华为OD机试模拟中发现,这类题目往往有运行时间限制,因此选择最直接的实现方式(如Python的sorted)通常是最稳妥的选择,除非题目明确要求优化空间复杂度。对于C/C++实现,要特别注意内存管理和指针操作的正确性。

http://www.cnnetsun.cn/news/4214906.html

相关文章:

  • 2026年招聘趋势:从潜力到即战力的转变
  • Docker容器化部署宝塔面板:云服务器Web应用管理新方案
  • 专业临沂GEO优化公司 10项指标真实对比
  • 前端与后端性能优化实战技巧与面试要点
  • OpenCode桌面端:AI编程助手本地化部署与使用全指南
  • 【linux应用软件编程】文件操作学习3【目录IO、出错处理及framebuffer基础操作】
  • 当 AI 会写代码之后,软件还剩什么?
  • 2026年事业单位面试拉开帷幕,哪家机构师资强值得一探究竟!
  • 人形机器人技术进阶:从概念验证到综合工程能力实战
  • 热线知识库搭建方法论:结构化存储、智能检索、动态更新机制
  • 室内智能晾衣架系统
  • 2026软件测试面试八股文与实战技巧全解析
  • 大模型API实战评测:从参数配置到错误处理,避开工程深坑
  • 美团研发岗笔试解析:分布式系统与实时计算实战
  • 腾讯云直播审核异常处理:从断流回调到稳定架构的实战指南
  • XHS-Downloader V2.8 技术解析:从数据采集原理到工程实践
  • 智能体记忆架构:从向量检索到工程实践
  • 基于柏拉图分析与动态看板的制造业制程质量监控系统实战
  • Linux命令-xset(X11 用户偏好设置)
  • QY-ZF/F 双层不锈钢水面蒸发传感器的工作原理是什么
  • JVM逃逸分析实战:栈上分配、标量替换与锁消除优化详解
  • AI工程化:Harness如何为Agent提供生产级可靠性与可观测性
  • 硕士论文AI生成工具实测:AIBiye一周完成初稿
  • 硕士论文AI生成工具实测:一周从大纲到初稿
  • 2026年网络钓鱼防御实战:AI驱动攻击与云账户安全防护
  • OpenClaw配置教程安装部署图文指南,TopClaw满血内核6万技能
  • 分布式缓存与消息队列:Java面试高频考点解析
  • 性能优化面试全攻略:从理论到实战解析
  • RAG嵌入模型微调实战:提升垂直领域知识库检索精度
  • AI 前沿日报:2026年08月24日