题目:
在一个整数数组中,“峰”是大于或等于相邻整数的元素,相应地,“谷”是小于或等于相邻整数的元素。例如,在数组{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条件里的逻辑判断中!
看清其背后的数学问题是关键!