leeCode题目324. Wiggle Sort II

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014110320/article/details/78794641

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?

Credits:
Special thanks to @dietpepsi for adding this problem and creating all test cases.

题目分析:该题目的关键是将找到中位数m,之后将大于中位数的数(我们假设为大数)放在奇数位,小于中位数的数(我们假设为小数)放在偶数位。

思路:我们已经发现了解改题目的基本思路,无非就是找到中位数,然后按照中位数将数分为大数部分和小数部分,以及等于数的部分,这让我们联想到3-way-partitation的方法,但是不同的是,3-wayu算法是将小数部分和大数部分分别放在了数组的两端,而我们这里确要把它岔开放,于是我们想到了将这个数组映射到新的数组A,并且有:
Accessing A(0) actually accesses nums[1].
Accessing A(1) actually accesses nums[3].
Accessing A(2) actually accesses nums[5].
Accessing A(3) actually accesses nums[7].
Accessing A(4) actually accesses nums[9].
Accessing A(5) actually accesses nums[0].
Accessing A(6) actually accesses nums[2].
Accessing A(7) actually accesses nums[4].
Accessing A(8) actually accesses nums[6].
Accessing A(9) actually accesses nums[8].
这样,我们只需按照3-way的方式操作数组A即可。

这里有一个关键的,num的index(oldI)与新数组index(newI)映射关系的函数,不容易想出来:

newI = (2 * oldI + 1) % (n | 1)

但是我们可以通过找规律找出来:

nums : 0 1 2 3 4 5
A: 1 3 5 0 2 4
即当0 <= oldI <= (len/2 - 1)时,newI = 2 * oldI + 1;
当 len/2 <= oldI <= (len-1)时,newI = 2 * oldI - len;
注意:这里len为技术还是偶数都是这个公式,不信的读者可以自己写写试试

所以,当之前的公式很难想出来的时候,用找规律的公式也是可以的。
下边的代码:

package sort;

import java.util.PriorityQueue;

/**
 * The method is based on the 3 tips:
 * 1) elements smaller than the 'median' are put into the last even slots.
 * 2) elements larger than the 'median' are put into the first odd slots.
 * 3) the medians are put into the remaining slots.
 * @author aerfalwl
 *
 */
public class _324WiggleSortII {
    private int n ;
    private int[] nums;
    public void wiggleSort(int[] nums) {
        if(nums.length == 0) {
            return ;
        }
        if(nums.length == 1) {
            return ;
        }
        this.nums = nums;
        PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
        for(Integer num : nums) {
            pq.add(num);
        }
        int midean = (nums.length + 1) / 2;
        for(int i = 0; i < midean - 1; i++) {
            pq.poll();
        }
        midean = pq.peek();
        n = nums.length;
        int left = 0;
        int right = n - 1;
        int i = 0;
        // The following function is same as 3-way partition.
        while(i <= right) {
            if(a(i) > midean) {
                swap(left, i);
                left++;
                i++;
            }else if(a(i)  < midean) {
                swap(right, i);
                right--;
            }else if(a(i) == midean) {
                i++;
            }
        }
    }
    /**
     * this function make a mapping from num to a;
     * Accessing A(0) actually accesses nums[1].
     *Accessing A(1) actually accesses nums[3].
     *Accessing A(2) actually accesses nums[5].
     *Accessing A(3) actually accesses nums[7].
     *Accessing A(4) actually accesses nums[9].
     *Accessing A(5) actually accesses nums[0].
     *Accessing A(6) actually accesses nums[2].
     *Accessing A(7) actually accesses nums[4].
     *Accessing A(8) actually accesses nums[6].
     *Accessing A(9) actually accesses nums[8].
     * @param index
     * @return
     */
    private int a(int index) {
        int i = (2 * index + 1) % (n | 1);
        return nums[i];
    }

    private void swap(int i, int j) {
        i = (2 * i + 1) % (n | 1);
        j = (2 * j + 1) % (n | 1);;
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

猜你喜欢

转载自blog.csdn.net/u014110320/article/details/78794641
今日推荐