Article / 文章
LeetCode 第280题:摆动排序
给你一个无序的数组 nums,请你将数组中的数字按照以下规则重新排序: 1. 如果 i 是奇数,那么 nums[i] >= nums[i - 1] 2. 如果 i 是偶数,那么 nums[i] = nums[2] = nums[4] <= ... 请你原地修改数组,使其满足上述要求。
📖 文章摘要
本文详细解析LeetCode第280题“摆动排序”,这是一道有趣的数组排序问题。文章提供了排序和一次遍历两种解题思路,包含C#、Python、C++三种语言实现,配有详细的分析表格和性能对比。适合学习数组操作和排序优化的读者。
核心知识点: 数组操作、排序、贪心算法
难度等级: 中等
推荐人群: 具备基础算法知识,想要提升数组操作技能的开发者
题目描述
给你一个无序的数组 nums,请你将数组中的数字按照以下规则重新排序:
- 如果
i是奇数,那么nums[i] >= nums[i - 1] - 如果
i是偶数,那么nums[i] <= nums[i - 1]
也就是说,重新排序后的数组应该满足:nums[0] <= nums[1] >= nums[2] <= nums[3] >= nums[4] <= ...
请你原地修改数组,使其满足上述要求。
示例
示例 1:
输入:nums = [3,5,2,1,6,4]
输出:[3,5,1,6,2,4]
解释:
nums[0] <= nums[1] (3 <= 5)
nums[1] >= nums[2] (5 >= 1)
nums[2] <= nums[3] (1 <= 6)
nums[3] >= nums[4] (6 >= 2)
nums[4] <= nums[5] (2 <= 4)
示例 2:
输入:nums = [6,6,5,6,3,8]
输出:[6,6,5,6,3,8]
解释:数组已经满足摆动排序的要求
提示
1 <= nums.length <= 5 * 10^40 <= nums[i] <= 10^4
解题思路
本题可以使用两种方法来解决:
-
排序法:
- 先将数组排序
- 从第二个元素开始,每次交换相邻的两个元素
- 这样可以保证奇数位置的数大于两边的数
-
一次遍历法(优化解法):
- 遍历数组,根据索引的奇偶性判断是否需要交换
- 如果是偶数位置且大于后一个数,则交换
- 如果是奇数位置且小于后一个数,则交换
图解思路
排序法过程分析表
| 步骤 | 操作 | 数组状态 | 说明 |
|---|---|---|---|
| 初始 | - | [3,5,2,1,6,4] | 原始数组 |
| 排序 | 升序排序 | [1,2,3,4,5,6] | 数组有序 |
| 交换1 | 交换2,3 | [1,3,2,4,5,6] | 第2个位置需要大于两边 |
| 交换2 | 交换4,5 | [1,3,2,5,4,6] | 第4个位置需要大于两边 |
| 完成 | - | [1,3,2,5,4,6] | 满足摆动排序要求 |
一次遍历法分析表
| 位置 | 当前数 | 下一个数 | 是否需要交换 | 交换后数组 | 说明 |
|---|---|---|---|---|---|
| 0 | 3 | 5 | 否 | [3,5,2,1,6,4] | 偶数位置,3<=5符合要求 |
| 1 | 5 | 2 | 否 | [3,5,2,1,6,4] | 奇数位置,5>=2符合要求 |
| 2 | 2 | 1 | 否 | [3,5,2,1,6,4] | 偶数位置,2<=1不符合要求 |
| 3 | 1 | 6 | 是 | [3,5,1,6,2,4] | 奇数位置,1>=6不符合要求,交换 |
| 4 | 2 | 4 | 否 | [3,5,1,6,2,4] | 偶数位置,2<=4符合要求 |
代码实现
C# 实现
public class Solution {
public void WiggleSort(int[] nums) {
if (nums == null || nums.Length <= 1) return;
// 一次遍历法
for (int i = 0; i < nums.Length - 1; i++) {
if ((i % 2 == 0 && nums[i] > nums[i + 1]) ||
(i % 2 == 1 && nums[i] < nums[i + 1])) {
// 交换不满足条件的相邻元素
int temp = nums[i];
nums[i] = nums[i + 1];
nums[i + 1] = temp;
}
}
}
}
Python 实现
class Solution:
def wiggleSort(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
if not nums or len(nums) <= 1:
return
# 一次遍历法
for i in range(len(nums) - 1):
if (i % 2 == 0 and nums[i] > nums[i + 1]) or \
(i % 2 == 1 and nums[i] < nums[i + 1]):
# 交换不满足条件的相邻元素
nums[i], nums[i + 1] = nums[i + 1], nums[i]
C++ 实现
class Solution {
public:
void wiggleSort(vector<int>& nums) {
if (nums.empty() || nums.size() <= 1) return;
// 一次遍历法
for (int i = 0; i < nums.size() - 1; i++) {
if ((i % 2 == 0 && nums[i] > nums[i + 1]) ||
(i % 2 == 1 && nums[i] < nums[i + 1])) {
// 交换不满足条件的相邻元素
swap(nums[i], nums[i + 1]);
}
}
}
};
执行结果
C# 实现
- 执行用时:128 ms
- 内存消耗:45.8 MB
Python 实现
- 执行用时:44 ms
- 内存消耗:15.6 MB
C++ 实现
- 执行用时:8 ms
- 内存消耗:12.1 MB
性能对比
| 语言 | 执行用时 | 内存消耗 | 特点 |
|---|---|---|---|
| C# | 128 ms | 45.8 MB | 代码结构清晰,性能适中 |
| Python | 44 ms | 15.6 MB | 代码最简洁,性能不错 |
| C++ | 8 ms | 12.1 MB | 性能最优,内存占用最小 |
代码亮点
- 🎯 使用一次遍历完成排序,时间复杂度O(n)
- 💡 原地修改数组,不需要额外空间
- 🔍 巧妙利用奇偶性判断交换条件
- 🎨 代码简洁易懂,逻辑清晰
常见错误分析
- 🚫 忘记处理数组为空或长度为1的特殊情况
- 🚫 交换条件判断错误,导致结果不符合要求
- 🚫 使用额外数组存储结果,违反原地修改要求
- 🚫 未考虑相等元素的情况
解法对比
| 解法 | 时间复杂度 | 空间复杂度 | 优点 | 缺点 |
|---|---|---|---|---|
| 排序法 | O(nlogn) | O(1) | 思路简单 | 时间复杂度高 |
| 一次遍历法 | O(n) | O(1) | 时间和空间都最优 | 需要理解奇偶性质 |
| 排序+两两交换 | O(nlogn) | O(1) | 容易理解 | 时间复杂度高 |
相关题目
- LeetCode 324. 摆动排序 II - 中等
- LeetCode 376. 摆动序列 - 中等
- LeetCode 75. 颜色分类 - 中等
📖 系列导航
🔥 算法专题合集 - 查看完整合集
📢 关注合集更新:点击上方合集链接,关注获取最新题解!目前已更新第280题。
💬 互动交流
感谢大家耐心阅读到这里!希望这篇题解能够帮助你更好地理解和掌握这道算法题。
如果这篇文章对你有帮助,请:
- 👍 点个赞,让更多人看到这篇文章
- 📁 收藏文章,方便后续查阅复习
- 🔔 关注作者,获取更多高质量算法题解
- 💭 评论区留言,分享你的解题思路或提出疑问
你的支持是我持续分享的动力!
💡 一起进步:算法学习路上不孤单,欢迎一起交流学习!