首页 > 代码库 > Leetcode: Wiggle Sort II

Leetcode: Wiggle Sort II

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 }

 

Leetcode: Wiggle Sort II