摆动排序 · Wiggle Sort 算法编程-数学归纳法和quick select的使用
280. 摆动排序
给你一个的整数数组 nums
, 将该数组重新排序后使 nums[0] <= nums[1] >= nums[2] <= nums[3]...
输入数组总是有一个有效的答案。
示例 1:
输入:nums = [3,5,2,1,6,4]
输出:[3,5,1,6,2,4]
解释:[1,6,2,5,3,4]也是有效的答案
示例 2:
输入:nums = [6,6,5,6,3,8] 输出:[6,6,5,6,3,8]
提示:
1 <= nums.length <= 5 * 104
0 <= nums[i] <= 104
-
输入的
nums
保证至少有一个答案。
进阶:你能在 O(n)
时间复杂度下解决这个问题吗?
-----
一个显而易见的解法是先将数组排序,再从第二个元素开始逐对交换元素的位置。如:
[1, 2, 3, 4, 5, 6]
↑ ↑ ↑ ↑
swap swap
=> [1, 3, 2, 5, 4, 6]
链接:https://leetcode.cn/problems/wiggle-sort/solution/bai-dong-pai-xu-by-leetcode/
1 2 3 4 5 6 7 8 9 10 11 | class Solution: def wiggleSort( self , nums: List [ int ]) - > None : """ Do not return anything, modify nums in-place instead. """ nums.sort() n = len (nums) j = 1 while j + 1 < n and j < n: nums[j], nums[j + 1 ] = nums[j + 1 ], nums[j] j + = 2 |
也可以不排序,直接交换:
1 2 3 4 5 6 7 8 9 10 | class Solution: def wiggleSort( self , nums: List [ int ]) - > None : """ Do not return anything, modify nums in-place instead. """ n = len (nums) for i in range ( 1 , n): 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] |
证明下,用数学归纳法:
(1)若i是偶数,则说明:nums[i-2],nums[i-1]是降序。
nums[i-1]和nums[i]的关系分为两种情况:
(1.a)nums[i-1] <= nums[i],这种情况,不需要做任何交换!因为:nums[i-2] >= nums[i-1] <= nums[i]
(1.b)nums[i-1] > nums[i],这种情况,需要交换!变为:nums[i-2] >=nums[i] > nums[i-1]则满足答案!可以用反证法证明:如果交换以后不满足答案,则说明:nums[i-2] < nums[i], 由于nums[i-2] >= nums[i-1],所以有nums[i-1]<=nums[i-2] < nums[i] ==> nums[i-1] < nums[i] ,这和最初的条件nums[i-1] > nums[i]矛盾!!!
画个图更直观:这种情况直接交换下nums[i-1] , nums[i]就好啦!
nums[i-2]
\
nums[i-1]
\
nums[i]
(2)若i是奇数,则说明:nums[i-2],nums[i-1]是升序。
(2.a)nums[i-1] >= nums[i],这种情况,不需要做任何交换!因为:nums[i-2] <= nums[i-1] >= nums[i]
(2.b)nums[i-1] < nums[i],这种情况,需要交换!变为:nums[i-2] <= nums[i] > nums[i-1]则满足答案!同样可以用反证法证明!
画个图: 这种情况直接交换下nums[i-1] , nums[i]就好啦!
nums[i]
/
nums[i-1]
/
nums[i-2]
324. 摆动排序 II
给你一个整数数组 nums
,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]...
的顺序。
你可以假设所有输入数组都可以得到满足题目要求的结果。
示例 1:
输入:nums = [1,5,1,1,6,4] 输出:[1,6,1,5,1,4] 解释:[1,4,1,5,1,6] 同样是符合题目要求的结果,可以被判题程序接受。
示例 2:
输入:nums = [1,3,2,2,3,1] 输出:[2,3,1,3,1,2]
提示:
1 <= nums.length <= 5 * 104
0 <= nums[i] <= 5000
- 题目数据保证,对于给定的输入
nums
,总能产生满足题目要求的结果
进阶:你能用 O(n) 时间复杂度和 / 或原地 O(1) 额外空间来实现吗?
这个题目,就不能用上面的思路了!!!
left 差不多就是中位数!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Solution { public void wiggleSort( int [] nums) { int [] clone = nums.clone(); Arrays.sort(clone); //两个指针 int left = (nums.length - 1 ) / 2 , right = nums.length - 1 ; for ( int i = 0 ; i < nums.length; i++) { if (i % 2 == 0 ) { nums[i] = clone[left]; left--; } else { nums[i] = clone[right]; right--; } } } } |
好了有了上面的铺垫,就可以使用quick select先找到中位数,再来交换了。
注意下面的:再将所有等于target都集中放到一起?为啥要做这步呢!!!
我们举例看看上面代码效果:
nums= [1, 2, 2, 5, 2, 1, 5, 2, 1, 3, 4, 4, 1, 5, 2]
1==> [1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 4, 2, 5, 5, 5]
2==> [1, 1, 1, 1, 2, 2, 2, 2, 2, 4, 4, 3, 5, 5, 5]
是不是2放到后面某一个地方去了。。。。
去掉代码,然后排序结果:
[2, 5, 2, 5, 2, 5, 2, 2, 1, 4, 1, 4, 1, 3, 1]
两个2连续放到一起了!!!
好了,完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | def quick_select(arr, l, r, index): q = partition(arr, l, r) if q == index: return arr[q] if q < index: return quick_select(arr, q + 1 , r, index) return quick_select(arr, l, q - 1 , index) def partition(nums, l, r): pivot = nums[l] index = l+ 1 for i in range(l+ 1 , r+ 1 ): if nums[i] < pivot: nums[i], nums[index] = nums[index], nums[i] index += 1 index -= 1 nums[index], nums[l] = nums[l], nums[index] return index class Solution: def wiggleSort(self, nums): n = len(nums) x = (n + 1 ) // 2 # 先找到中位数 target = quick_select(nums, 0 , n - 1 , x - 1 ) # print( "1==>" , nums) # 再将所有等于target都集中放到一起 index = x for i in range(x+ 1 , n): if nums[i] == target: nums[index], nums[i] = nums[i], nums[index] index += 1 # print( "2==>" , nums) arr = nums.copy() left = (n - 1 ) //2 right = n - 1 for i in range(n): if i % 2 == 0 : nums[i] = arr[left] left -= 1 else : nums[i] = arr[right] right -= 1 |
1 | <br><br><br> |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
2022-02-05 烂土豆提权——本质上是利用SMB中间人漏洞利用,伪造一个token实现提权
2022-02-05 61:权限提升-Redis&Postgre&令牌窃取&进程注入;令牌窃取相当于窃取session-token;进程注入提权就是利用system权限的进程“附身”
2022-02-05 redis提权——如果对方root运行,则容易中招,都是由于安全配置出问题导致
2022-02-05 oracle提权执行命令工具oracleShell v0.1
2022-02-05 MSSQL提权之xp_cmdshell、SP_OACreate、沙盒提权
2022-02-05 MYSQL提权之反弹SHELL——数据库提权属于webshell到管理员的纵向提权,本质还是利用udf提权,无非是在mysql自定义函数中使用了反弹shell而已
2022-02-05 MySQL提权之启动项提权——开机启动的程序,那时候启动的程序权限都是system