为什么这段代码能让数组变成“节奏大师”?摆动排序揭秘

在这里插入图片描述
在这里插入图片描述

摘要

在这篇文章中,我们将一起拆解 LeetCode 第 280 题《摆动排序》,并用 Swift 编写一个简单又高效的解法。我们会从题目描述开始,逐步分析解题思路,提供代码实现,并解释其中的逻辑。最后还会结合实际场景,谈谈这个“看似无用”的题目,其实在某些交互排序中非常有用。

描述

题目来自 LeetCode 280:Wiggle Sort(摆动排序)。

给你一个整数数组 nums,请重新排列它们,使得:

  • nums[0] <= nums[1] >= nums[2] <= nums[3]... 依此类推。

简单点说,就是让数组在数值上形成一种“波浪”型的排序。高低交错,看起来像这样:

输入: [3, 5, 2, 1, 6, 4]
输出: [3, 5, 1, 6, 2, 4]

注意:

  • 可以有多个合法解,题目只要求 满足条件即可,并不要求特定顺序。

  • 要求 就地排序(in-place),不额外开辟空间。

题解答案

直觉上我们会想用排序再调换位置的办法,但其实我们完全可以用一轮遍历就搞定这个问题,而且效率非常高。

基本思路:

  • 遍历数组的每一对相邻元素。

  • 在奇数索引位,确保 nums[i] >= nums[i - 1]

  • 在偶数索引位,确保 nums[i] <= nums[i - 1]

  • 如果不符合,就交换它们。

题解代码分析

func wiggleSort(_ nums: inout [Int]) {
    for i in 1..<nums.count {
        if (i % 2 == 1 && nums[i] < nums[i - 1]) ||
           (i % 2 == 0 && nums[i] > nums[i - 1]) {
            nums.swapAt(i, i - 1)
        }
    }
}

代码逐行解析:

  • for i in 1..<nums.count:从第 1 个元素开始遍历,因为我们需要和前一个元素进行比较。

  • i % 2 == 1:如果当前是奇数索引位,应该是高峰,nums[i] >= nums[i - 1]

  • i % 2 == 0:偶数位是低谷,应该满足 nums[i] <= nums[i - 1]

  • 如果违反这些条件,我们用 swapAt() 交换这两个数。

这段代码只需要一次遍历,所以非常高效!

示例测试及结果

来看看几组实际测试结果:

var test1 = [3, 5, 2, 1, 6, 4]
wiggleSort(&test1)
print(test1) // 输出示例: [3, 5, 1, 6, 2, 4]

var test2 = [1, 2, 3, 4, 5, 6]
wiggleSort(&test2)
print(test2) // 输出示例: [1, 3, 2, 5, 4, 6]

var test3 = [6, 5, 4, 3, 2, 1]
wiggleSort(&test3)
print(test3) // 输出示例: [5, 6, 3, 4, 1, 2]

输出是否唯一并不重要,只要符合交错条件即可。

时间复杂度

  • 时间复杂度:O(n)
    只遍历了一次数组,没有多余的操作或嵌套循环。

空间复杂度

  • 空间复杂度:O(1)
    采用就地交换,不依赖额外空间,非常节省内存资源。

总结

这道题虽然简单,但确实考验了我们对条件的理解能力和代码实现的简洁度。在实际开发中,这类“局部有序”的场景常出现在数据可视化展示、图形控件排布等需要一定“节奏感”的排序中,摆动排序就是一种低成本高表现的方式。

实际场景类比

想象你在开发一个电商商品列表页,要展示用户喜好度的走势图——这个走势就不希望一条直线或者单调增减,而是要有节奏的“起伏”才更直观。

或者你在做一个推荐引擎排序优化,希望将热门和冷门内容交错展示以提升点击率,也可以用类似的摆动策略来打散排序。

未来展望

可以继续延伸这道题,比如:

  • 如果数组中有重复值,会不会影响结果?

  • 如果要求 nums[0] > nums[1] < nums[2] > nums[3]... 呢?

  • 如果我们希望构造最大的摆动幅度,应该怎么做?

这些都可以作为后续思考题,进一步挑战自己。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网罗开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值