C语言 | LeetCode 414. 第三大的数
💡 C语言 | LeetCode 414. 第三大的数 —— 快速排序实现与算法分析(附完整源码)
✍️ 作者:凡间的八戒
📅 时间:2025-11-12
🏷️ 标签:C语言、算法题解、LeetCode、快速排序、数组、排序算法
🧠 一、题目描述
LeetCode 第 414 题:第三大的数(Third Maximum Number)
给你一个非空整数数组,返回其中的第三大的数。
如果不存在,则返回数组中最大的数。
🔍 示例:
输入: [3, 2, 1]
输出: 1
解释: 第三大的数是 1。
输入: [1, 2]
输出: 2
解释: 第三大的数不存在,返回最大的数 2。
输入: [2, 2, 3, 1]
输出: 1
解释: 在所有不同数字中,第三大的数是 1。
💭 二、思路分析
这道题如果直接看题目,会想到三种方法:
| 思路 | 描述 | 时间复杂度 |
|---|---|---|
| 1️⃣ 排序法 | 将数组排序,去重后取第三个最大值 | O(nlogn) |
| 2️⃣ 集合法 | 使用哈希表保存不同数,再排序 | O(nlogn) |
| 3️⃣ 一次遍历法 | 用三个变量维护前三大值 | O(n) |
本文选择**手写快速排序(Quick Sort)**来实现排序法方案。
同时,这也是一次对快排核心逻辑的复习与实战演练。
⚙️ 三、算法原理 —— 快速排序回顾
快速排序是一种 分治(Divide and Conquer)思想 的算法。
流程如下:
- 选取一个基准元素(pivot);
- 将小于 pivot 的放左边,大于 pivot 的放右边;
- 递归处理左右子数组。
📘 平均时间复杂度:O(nlogn)
📘 最坏情况(已排序):O(n²)
🔧 四、手写快速排序实现
1️⃣ 交换函数 swap()
使用异或方式交换两个整数:
void swap(int* a, int* b) {if (a == b) return; // 避免同地址交换*a = *a ^ *b;*b = *a ^ *b;*a = *a ^ *b;
}
2️⃣ 分区函数 selecPivot()
将数组按基准值划分为两部分:
int selecPivot(int* nums, int left, int right) {int pivot = nums[left]; // 以最左元素为基准int i = left;int j = right;while (i < j) {while (i < j && nums[j] >= pivot) j--; // 从右找比基准小的while (i < j && nums[i] <= pivot) i++; // 从左找比基准大的swap(&nums[i], &nums[j]);}swap(&nums[left], &nums[i]); // 归位基准return i;
}
3️⃣ 主体函数 quickSort()
递归排序左右子区间:
void quickSort(int* nums, int left, int right) {if (left < right) {int pivotIdx = selecPivot(nums, left, right);quickSort(nums, left, pivotIdx - 1);quickSort(nums, pivotIdx + 1, right);}
}
💻 五、完整代码(含快排 + 调试输出)
#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include <stdio.h>// 快速排序算法实现void swap(int* a, int* b) {if (a == b) return; // 避免同地址失效*a = *a ^ *b;*b = *a ^ *b;*a = *a ^ *b;
}int selecPivot(int* nums, int left, int right) {int pivot = nums[left];int i = left, j = right;while (i < j) {while (i < j && nums[j] >= pivot) j--;while (i < j && nums[i] <= pivot) i++;swap(&nums[i], &nums[j]);}swap(&nums[left], &nums[i]);return i;
}void quickSort(int* nums, int left, int right) {if (left < right) {int pivotIdx = selecPivot(nums, left, right);quickSort(nums, left, pivotIdx - 1);quickSort(nums, pivotIdx + 1, right);}
}int main() {int nums[] = { 5,4,3,8,9,4,54,9,45,49 };int n = sizeof(nums) / sizeof(nums[0]);quickSort(nums, 0, n - 1);printf("排序结果:\n");for (int i = 0; i < n; i++) {printf("%d ", nums[i]);}printf("\n");return 0;
}
🧩 六、运行结果
排序结果:
3 4 4 5 8 9 9 45 49 54
这说明快排逻辑正确,将数组从小到大排序。
若用于求「第三大的数」,则可反向取第3个不同元素即可。
⏱️ 七、复杂度分析
| 分类 | 平均 | 最坏 | 空间复杂度 |
|---|---|---|---|
| 时间 | O(nlogn) | O(n²) | O(logn) |
若要在 O(n) 时间解决,可使用一次遍历维护 top3,但本文重点在于复习快速排序原理。
🧠 八、总结与思考
- 快速排序是经典的分治算法,实现简单、性能优越。
- 本题通过快排求第三大数,不仅复习了排序逻辑,也理解了数组划分与指针移动技巧。
- 若面试要求更优算法,可尝试“一次遍历求 top3” 的线性复杂度实现。
。
*后续更新线性算法
