324. 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?

Solution:

solve it in O(n) space is easy, we could first find the median of the nums, and partition the array by smaller | median | larger, it takes O(1) time,

we want to put median numbers in the smallest odd positions and largest even positions to separate them as far as possible to avoid nums[i] == nums[i + 1];

for the index 

0 1 2 3 4 5 6 they will end to be

1 3 5 0 2 4 6

How to get this?  from https://discuss.leetcode.com/topic/41464/step-by-step-explanation-of-index-mapping-in-java/14

This is to explain why mapped index formula is (1 + 2*index) % (n | 1)

Notice that by placing the median in it's place in the array we divided the array in 3 chunks: all numbers less than median are in one side, all numbers larger than median are on the other side, median is in the dead center of the array.

We want to place any a group of numbers (larger than median) in odd slots, and another group of numbers (smaller than median) in even slots. So all numbers on left of the median < n / 2 should be in odd slots, all numbers on right of the median > n / 2 should go into even slots (remember that median is its correct place at n / 2)

PS: I'm ignoring the discussion of odd/even array length for simplicity.

So let's think about the first group in the odd slots, all numbers is the left side of the array should go into these odd slots. What's the formula for it? Naturally it would be:
(1 + 2 x index) % n

All these indexes are less than n / 2 so multiplying by 2 and add 1 (to make them go to odd place) and then mod by n will always guarantee that they are less than n.

Original Index => Mapped Index
0 => (1 + 2 x 0) % 6 = 1 % 6 = 1
1 => (1 + 2 x 1) % 6 = 3 % 6 = 3
2 => (1 + 2 x 2) % 6 = 5 % 6 = 5

These are what's less than median, if we continue this with indexes 3, 4, 5 we will cycle again:
3 => (1 + 2 x 3) % 6 = 7 % 6 = 1
4 => (1 + 2 x 4) % 6 = 9 % 6 = 3
5 => (1 + 2 x 5) % 6 = 11 % 6 = 5

and we don't want that, so for indexes larger than n/2 we want them to be even, (n|1) does that exactly. What n|1 does it that it gets the next odd number to n if it was even
if n = 6 for example 110 | 1 = 111 = 7
if n = 7 for example 111 | 1 = 111 = 7

and this is what we want, instead of cycling the odd numbers again we want them to be even, and odd % odd number is even so updating the formula to :
(1 + 2*index) % (n | 1)

Then we have:
3 => (1 + 2 x 3) % 7 = 7 % 7 = 0
4 => (1 + 2 x 4) % 7 = 9 % 7 = 2
5 => (1 + 2 x 5) % 7 = 11 % 7 = 4

And we want to finish the conversion while the partition, so we compute each mapped index in the partition method.

Code:

public class Solution {
    public void wiggleSort(int[] nums) {
        int mid = findKth(nums,(nums.length - 1)/ 2,0,nums.length-1);
        partition(nums,mid);
    }
    
    public int mapIndex(int len, int i){
        return (2*i + 1) % (len | 1);
    }
    
    public void partition(int[] nums, int val){
        int len = nums.length;
        int l = 0;
        int r = nums.length - 1;
        int i = 0;
        while(i <= r){
            int curIndex = mapIndex(len,i);
            if(nums[curIndex] > val){
                swap(nums,curIndex,mapIndex(len,l));
                i++;l++;
            } else if(nums[curIndex] == val){
                i++;
            } else {
                swap(nums,curIndex,mapIndex(len,r));
                r--;
            }
        }
    }
    
    public void swap(int[] nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
    
    public int findKth(int[] nums, int k, int start, int end){
        int index= partition(nums,start,end);
        if(index == k) return nums[k];
        else if(index > k) return findKth(nums,k,start,index - 1);
        else return findKth(nums,k,index + 1, end);
    }
    
    public int partition(int[] nums, int start, int end){
        if(start == end) return start;
        int p = nums[start];
        while(start < end){
            while(start < end && nums[end] > p){
                end--;
            }
            nums[start] = nums[end];
            while(start < end && nums[start] <= p){
                start++;
            }
            nums[end] = nums[start];
        }
        nums[start] = p;
        return start;
    }
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值