376. 摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为 摆动序列 。第一个差(如果存在的话)可能是正数或负数。仅有一个元素或者含两个不等元素的序列也视作摆动序列。
- 例如, [1, 7, 4, 9, 2, 5] 是一个 摆动序列 ,因为差值 (6, -3, 5, -7, 3) 是正负交替出现的。
- 相反,[1, 4, 7, 2, 5] 和 [1, 7, 4, 5, 5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
子序列 可以通过从原始序列中删除一些(也可以不删除)元素来获得,剩下的元素保持其原始顺序。
给你一个整数数组 nums ,返回 nums 中作为 摆动序列 的 最长子序列的长度 。
示例 1:
输入:nums = [1,7,4,9,2,5] 输出:6 解释:整个序列均为摆动序列,各元素之间的差值为 (6, -3, 5, -7, 3) 。
示例 2:
输入:nums = [1,17,5,10,13,15,10,5,16,8] 输出:7 解释:这个序列包含几个长度为 7 摆动序列。 其中一个是 [1, 17, 10, 13, 10, 16, 8] ,各元素之间的差值为 (16, -7, 3, -3, 6, -8) 。
示例 3:
输入:nums = [1,2,3,4,5,6,7,8,9] 输出:2
提示:
- 1 <= nums.length <= 1000
- 0 <= nums[i] <= 1000
进阶:你能否用 O(n) 时间复杂度完成此题?
思路:
贪心,选所有的局部极值点
证明:离散化的费马引理,除首尾外最优解的元素个数不会超过局部极值点的总数,而我们选取了所有极值点,其个数大于等于最优解元素个数,又因为贪心的方法找到的元素数一定小于等于最优解,故贪心解是最优解
class Solution {
public int wiggleMaxLength(int[] nums) {
int n = nums.length;
int cnt = 1;
int pre = 0;
for (int i = 1; i < n ; i++) {
int x = nums[i] - nums[i - 1];
if ((pre == 0 && x != 0) || (pre > 0 && x < 0) || (pre < 0 && x > 0)) {
pre = x;
cnt++;
}
}
return cnt;
}
}
324. 摆动排序 II
给你一个整数数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]… 的顺序。
你可以假设所有输入数组都可以得到满足题目要求的结果。
示例 1:
输入:nums = [1,5,1,1,6,4] 输出:[1,6,1,5,1,4] 解释:[1,4,1,5,1,6] 同样是符合题目要求的结果,可以被判题程序接受。
示例 2:
输入:nums = [1,3,2,2,3,1] 输出:[2,3,1,3,1,2]
提示:
- 1 <= nums.length <= 5 * 104
- 0 <= nums[i] <= 5000
- 题目数据保证,对于给定的输入 nums ,总能产生满足题目要求的结果
进阶:你能用 O(n) 时间复杂度和 / 或原地 O(1) 额外空间来实现吗?
思路:
如何构造?
排序
将排序后的中位数尽可能分开
不能先放偶数下标,再放奇数下标,对应原数组中的下标递增
例如:4 5 5 6
放完后是4 5 5 6
不满足要求
必须先放奇数下标,再放偶数下标,对应原数组中的下标递减
例如:4 5 5 6
放完后是5 6 4 5
满足要求
class Solution {
public void wiggleSort(int[] nums) {
int n = nums.length;
int[] a = new int[n];
for (int i = 0; i < n; i++)
a[i] = nums[i];
Arrays.sort(a);
int j = n - 1;
for (int i = 1; i < n; i += 2) {
nums[i] = a[j];
j--;
}
for (int i = 0; i < n; i += 2) {
nums[i] = a[j];
j--;
}
}
}
如何优化 ?
第k大数(快速选择) + 三数排序 + 映射 + 构造A[i] = (2 * i + 1) % (n | 1)
例:可将0 1 2 3 4 5 6
映射到1 3 5 0 2 4 6
找到第n / 2
大数,以此为依据进行三数排序(倒排),根据映射关系放到对应位置构造出目标结果
class Solution {
int n;
public void wiggleSort(int[] nums) {
n = nums.length;
int mid = quickSort(nums, 0, n - 1, n / 2);
// System.out.println(mid);
for (int i = 0, l = 0, r = n - 1; i <= r; ) {
if (nums[A(i)] > mid) {
swap(nums, A(i), A(l));
i++;
l++;
} else if (nums[A(i)] < mid) {
swap(nums, A(i), A(r));
r--;
} else {
i++;
}
}
}
int A(int x) {
return (2 * x + 1) % (n | 1);
}
int quickSort(int[] q, int l, int r, int k) {
if (l >= r)
return q[l];
int x = q[l + r >> 1], i = l - 1, j = r + 1;
while (i < j) {
while (q[++i] < x);
while (q[--j] > x);
if (i < j) {
swap(q, i, j);
}
}
if (j >= k)
return quickSort(q, l, j, k);
else
return quickSort(q, j + 1, r, k);
}
void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}