leetcode:峰与谷问题(三)

769 阅读3分钟

题目:

在一个整数数组中,“峰”是大于或等于相邻整数的元素,相应地,“谷”是小于或等于相邻整数的元素。例如,在数组{5, 8, 4, 2, 3, 4, 6}中,{8, 6}是峰, {5, 2}是谷。现在给定一个整数数组,将该数组按峰与谷的交替顺序排序。

示例:

输入: [5, 3, 1, 2, 3]
输出: [5, 1, 3, 2, 3]

思路一

copyOf()出1个新数组,对其排序。

比如排序结果为:1, 2, 3, 4, 5

每次取1个最大值,再取1个最小值,如此往复直到取完即可:

简而言之就是头拿1个,尾拿1个即可。

例如:

先取最大值5,得到为5, 剩余1, 2, 3, 4 

再取最小值1,得到5, 1,剩余2, 3, 4 

再取最大值4,得到5, 1, 4, 剩余2, 3 

再取最小值2,得到5, 1,4, 2, 剩余3 

再取最大值3,得到5, 1,4, 2, 3,无剩余

class Solution {
    public void wiggleSort(int[] nums) {
        int idx = 0, len = nums.length;
        if (len < 3) return;
        int low = 0, high = len - 1;
        int[] sorted = Arrays.copyOf(nums, len);
        Arrays.sort(sorted);
        while (low < high) {
            nums[idx++] = sorted[high--];
            nums[idx++] = sorted[low++];
        }
        if (len % 2 > 0)
            nums[idx] = sorted[low];
    }
}

思路二:从局部谷-峰-谷 到 全局谷-峰-谷

简单来说即先确认数组的形式: 峰-谷-峰 谷-峰-谷 ,本例采用后者。  

现有数组[3,5,2,1,6,4]: 

先维护一个局部谷-峰-谷,初始为[3],接着从左往右遍历数据,将新元素加入局部谷-峰-谷的最右侧。 

将5加入局部谷-峰-谷,得到[3 < 5],无需调整。  

将2加入局部谷-峰-谷,得到[3 < 5 > 2],无需调整。 

 将1加入局部谷-峰-谷,得到[3 < 5 > 2 > 1],此时存在5 > 2 > 1,需要调整。 

已知1的位置应当是峰,但出现了2 > 1; 

又已知加入新元素前的子数组[3 < 5 > 2]是局部谷-峰-谷,即5 > 2是隐含条件。 

既然5 > 2成立,5 > 1也必然成立;

同时2 > 1,因此将5 > 2 > 1变成5 > 1 < 2即可。 

调整完毕后的局部谷-峰-谷为[3 < 5 > 1 < 2]。 

 将6加入局部谷-峰-谷,得到[3 < 5 > 1 < 2 < 6],此时存在1 < 2 < 6,需要调整。

 已知6的位置应当是谷,但出现了2 < 6; 

又已知加入新元素前的子数组[3 < 5 > 1 < 2]是局部谷-峰-谷,即1 < 2是隐含条件。 

既然1 < 2成立,1 < 6也必然成立;

同时6 > 2,因此将1 < 2 < 6变成1 < 6 > 2即可。 

调整完毕后的局部谷-峰-谷为[3 < 5 > 1 < 6 > 2]。

 将4加入局部谷-峰-谷,得到[3 < 5 > 1 < 6 > 2 < 4],无需调整。  

总结:当出现问题时,要么是出现了a < b < c,要么是出现了a > b > c。 最终只要调整为a < c > b或a > c < b即可。

class Solution {
    public void wiggleSort(int[] nums) {
        int n = nums.length;
        for (int i = 1; i < n; ++i)
            if ((i & 1) == 1 ? nums[i] < nums[i - 1] : nums[i] > nums[i - 1])
                swap(nums, i, i - 1);
    }

    private void swap(int[] nums, int idx1, int idx2) {
        nums[idx1] ^= nums[idx2];
        nums[idx2] ^= nums[idx1];
        nums[idx1] ^= nums[idx2];
    }
}//by gyu

java知识点的一些总结:

^=:

public static strictfp void main(String[] args) {
    int a = 5; // 0000 0101
    int b = 3; // 0000 0011
    a ^= b; // 0000 0110
    System.out.println(a);
}

平常情况下都是使用中间变量进行交换两个数值,但是这会额外多出空间,但是使用异或(^)则会节省空间且并不会影响数值精度,关于异或交换数值的方法如下:

a^=b

b^=a

a^=b

java里的c=a>b?a:b是什么意思:

java里唯一的三元运算符,这的符号的意思是: 如果?前面的式子为真,那么就返回冒号:左边的值;否则返回右边的值, 这个题目的意思就是:如果a大于b,那么c就等于a; 如果a小于b,那么c就等于b, 也就是把a和b中较大的数赋值给c

Java中&叫做按位与,&&叫做短路与,它们的区别是

& 既是位运算符又是逻辑运算符,&的两侧可以是int,也可以是boolean表达式,当&两侧是int时,要先把运算符两侧的数转化为二进制数再进行运算,而短路与(&&)的两侧要求必须是布尔表达式,一般用于if条件里的逻辑判断中!

看清其背后的数学问题是关键!