Leetcode: Wiggle Sort II

本文介绍了一种名为摆动排序的数组排序方法,该方法通过将数组分为大小两半并交错放置来实现特定的排序效果。文章详细解释了排序原理,并提供了一个具体的Java实现示例。
Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]....

Example:
(1) Given nums = [1, 5, 1, 1, 6, 4], one possible answer is [1, 4, 1, 5, 1, 6]. 
(2) Given nums = [1, 3, 2, 2, 3, 1], one possible answer is [2, 3, 1, 3, 1, 2].

Note:
You may assume all input has valid answer.

Follow Up:
Can you do it in O(n) time and/or in-place with O(1) extra space?

这道题应该是hard,首先思想上面参考了https://discuss.leetcode.com/topic/32861/3-lines-python-with-explanation-proof

I put the smaller half of the numbers on the even indexes and the larger half on the odd indexes, both from right to left:

Example nums = [1,2,...,7]      Example nums = [1,2,...,8] 

Small half:  4 . 3 . 2 . 1      Small half:  4 . 3 . 2 . 1 .
Large half:  . 7 . 6 . 5 .      Large half:  . 8 . 7 . 6 . 5
--------------------------      --------------------------
Together:    4 7 3 6 2 5 1      Together:    4 8 3 7 2 6 1 5

I want:

  • Odd-index numbers are larger than their neighbors.

Since I put the larger numbers on the odd indexes, clearly I already have:

  • Odd-index numbers are larger than or equal to their neighbors.

Could they be "equal to"? That would require some number M to appear both in the smaller and the larger half. It would be the largest in the smaller half and the smallest in the larger half. Examples again, where S means some number smaller than M and L means some number larger than M.

Small half:  M . S . S . S      Small half:  M . S . S . S .
Large half:  . L . L . M .      Large half:  . L . L . L . M
--------------------------      --------------------------
Together:    M L S L S M S      Together:    M L S L S L S M

You can see the two M are quite far apart. Of course M could appear more than just twice, for example:

Small half:  M . M . S . S      Small half:  M . S . S . S .
Large half:  . L . L . M .      Large half:  . L . M . M . M
--------------------------      --------------------------
Together:    M L M L S M S      Together:    M L S M S M S M

You can see that with seven numbers, three M are no problem. And with eight numbers, four M are no problem. Should be easy to see that in general, with n numbers, floor(n/2) times M is no problem. Now, if there were more M than that, then my method would fail. But... it would also be impossible:

  • If n is even, then having more than n/2 times the same number clearly is unsolvable, because you'd have to put two of them next to each other, no matter how you arrange them.
  • If n is odd, then the only way to successfully arrange a number appearing more than floor(n/2) times is if it appears exactly floor(n/2)+1 times and you put them on all the even indexes. And to have the wiggle-property, all the other numbers would have to be larger. But then we wouldn't have an M in both the smaller and the larger half.

So if the input has a valid answer at all, then my code will find one.

 

然后根据https://discuss.leetcode.com/topic/41464/step-by-step-explanation-of-index-mapping-in-java

Assume your original array is {6,13,5,4,5,2}. After you get median element, the 'nums' is partially sorted such that the first half is larger or equal to the median, the second half is smaller or equal to the median, i.e

13   6   5   5   4   2

         M

In the post https://leetcode.com/discuss/76965/3-lines-python-with-explanation-proof, we have learned that , to get wiggle sort, you want to put the number in the following way such that

(1) elements smaller than the 'median' are put into the even slots(starting from right, left side may have left-overs, which will be stuffed by median)

(2) elements larger than the 'median' are put into the odd slots(starting from left, right side may have left-overs, which will be filled by median number)

(3) the medians are put into the remaining slots.

Index :       0   1   2   3 4 5 Small half: M S S Large half: L L M 

M - Median, S-Small, L-Large. In this example, we want to put {13, 6, 5} in index 1,3,5 and {5,4,2} in index {0,2,4}

可惜每太看懂O(1)space的方法,我的方法用了O(N)space

 1 public class Solution {
 2     public void wiggleSort(int[] nums) {
 3         int median = findKthLargest(nums, (nums.length+1)/2);
 4         int odd = 1, even = (nums.length%2==0? nums.length-2 : nums.length-1);
 5         int[] arr = new int[nums.length];
 6         for (int num : nums) {
 7             if (num > median) {
 8                 arr[odd] = num;
 9                 odd += 2;
10             }
11             else if (num < median) {
12                 arr[even] = num;
13                 even -= 2;
14             }
15         }
16         while (odd < arr.length) {
17             arr[odd] = median;
18             odd += 2;
19         }
20         while (even >= 0) {
21             arr[even] = median;
22             even -= 2;
23         }
24         for (int i=0; i<arr.length; i++) {
25             nums[i] = arr[i];
26         }
27     }
28     
29     public int findKthLargest(int[] nums, int k) {
30         int len = nums.length;
31         return findKthSmallest(nums, 0, len-1, len-k+1);
32     }
33     
34     public int findKthSmallest(int[] nums, int start, int end, int k) {
35         int l = start;
36         int r = end;
37         int pivot = end;
38         while (l < r) {
39             while (l<r && nums[l] < nums[pivot]) {
40                 l++;
41             }
42             while (l<r && nums[r] >= nums[pivot]) {
43                 r--;
44             }
45             if (l == r) break;
46             swap(nums, l, r);
47         }
48         swap(nums, l, pivot);
49         if (l+1 == k) return nums[l];
50         else if (l+1 < k) return findKthSmallest(nums, l+1, end, k);
51         else return findKthSmallest(nums, start, l-1, k);
52     }
53     
54     public void swap(int[] nums, int l, int r) {
55         int temp = nums[l];
56         nums[l] = nums[r];
57         nums[r] = temp;
58     }
59 }

 

转载于:https://www.cnblogs.com/EdwardLiu/p/6181802.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值