文章目录
题目
标题和出处
标题:优势洗牌
出处:870. 优势洗牌
难度
4 级
题目描述
要求
给定两个长度相等的数组 nums1 \texttt{nums1} nums1 和 nums2 \texttt{nums2} nums2。数组 nums1 \texttt{nums1} nums1 相对于数组 nums2 \texttt{nums2} nums2 的优势 为满足 nums1i > nums2i \texttt{nums1i} > \texttt{nums2i} nums1i>nums2i 的下标 i \texttt{i} i 的数目。
返回使 nums1 \texttt{nums1} nums1 相对于 nums2 \texttt{nums2} nums2 的优势最大化的 nums1 \texttt{nums1} nums1 的任意排列。
示例
示例 1:
输入: nums1 = 2,7,11,15, nums2 = 1,10,4,11 \texttt{nums1 = 2,7,11,15, nums2 = 1,10,4,11} nums1 = 2,7,11,15, nums2 = 1,10,4,11
输出: 2,11,7,15 \texttt{2,11,7,15} 2,11,7,15
示例 2:
输入: nums1 = 12,24,8,32, nums2 = 13,25,32,11 \texttt{nums1 = 12,24,8,32, nums2 = 13,25,32,11} nums1 = 12,24,8,32, nums2 = 13,25,32,11
输出: 24,32,8,12 \texttt{24,32,8,12} 24,32,8,12
数据范围
- 1 ≤ nums1.length ≤ 10 5 \texttt{1} \le \texttt{nums1.length} \le \texttt{10}^\texttt{5} 1≤nums1.length≤105
- nums2.length = nums1.length \texttt{nums2.length} = \texttt{nums1.length} nums2.length=nums1.length
- 0 ≤ nums1i, nums2i ≤ 10 9 \texttt{0} \le \texttt{nums1i, nums2i} \le \texttt{10}^\texttt{9} 0≤nums1i, nums2i≤109
前言
这道题的情形和田忌赛马很相似。田忌赛马出自《史记·孙子吴起列传》,原文如下。
孙武既死,后百余岁有孙膑。膑生阿、鄄之间,膑亦孙武之后世子孙也。孙膑尝与庞涓俱学兵法。庞涓既事魏,得为惠王将军,而自以为能不及孙膑,乃阴使召孙膑。膑至,庞涓恐其贤于己,疾之,则以法刑断其两足而黥之,欲隐勿见。
齐使者如梁,孙膑以刑徒阴见,说齐使。齐使以为奇,窃载与之齐。齐将田忌善而客待之。忌数与齐诸公子驰逐重射。孙子见其马足不甚相远,马有上、中、下辈。于是孙子谓田忌曰:"君弟重射,臣能令君胜。"田忌信然之,与王及诸公子逐射千金。及临质,孙子曰:"今以君之下驷与彼上驷,取君上驷与彼中驷,取君中驷与彼下驷。"既驰三辈毕,而田忌一不胜而再胜,卒得王千金。于是忌进孙子于威王。威王问兵法,遂以为师。
解法
思路和算法
定义「优势元素」如下:将 nums 1 \textit{nums}_1 nums1 排列之后,如果两个数组的下标 i i i 处的元素满足 nums 1 i > nums 2 i \textit{nums}_1i > \textit{nums}_2i nums1i>nums2i,则将 nums 1 i \textit{nums}_1i nums1i 称为 nums 2 i \textit{nums}_2i nums2i 的优势元素。
为了使 nums 1 \textit{nums}_1 nums1 相对于 nums 2 \textit{nums}_2 nums2 的优势最大,根据贪心思想,应按照 nums 2 \textit{nums}_2 nums2 的元素递增的顺序依次寻找 nums 2 \textit{nums}_2 nums2 中的每个元素在 nums 1 \textit{nums}_1 nums1 中的优势元素,对于 nums 2 \textit{nums}_2 nums2 的每个元素 x x x,选择 nums 1 \textit{nums}_1 nums1 的剩余元素中大于 x x x 的最小元素作为 x x x 的优势元素,理由如下。
将数组 nums 2 \textit{nums}_2 nums2 按升序排序之后,假设存在两个相邻元素 x 1 x_1 x1 和 x 2 x_2 x2,其中 x 1 ≤ x 2 x_1 \le x_2 x1≤x2, nums 1 \textit{nums}_1 nums1 的剩余元素中大于这两个元素的最小元素分别是 y 1 y_1 y1 和 y 2 y_2 y2,则必有 y 1 ≤ y 2 y_1 \le y_2 y1≤y2。当 nums 1 \textit{nums}_1 nums1 相对于 nums 2 \textit{nums}_2 nums2 的优势最大时,应将 y 1 y_1 y1 作为 x 1 x_1 x1 的优势元素,将 y 2 y_2 y2 作为 x 2 x_2 x2 的优势元素。假设 x 1 x_1 x1 的优势元素是 y 3 y_3 y3 且 y 3 > y 1 y_3 > y_1 y3>y1,考虑以下两种情况。
-
当 y 3 < y 2 y_3 < y_2 y3<y2 时,仍可以将 y 2 y_2 y2 作为 x 2 x_2 x2 的优势元素, nums 2 \textit{nums}_2 nums2 的其余更大元素的优势元素不变, nums 1 \textit{nums}_1 nums1 相对于 nums 2 \textit{nums}_2 nums2 的优势不变。
-
当 y 3 ≥ y 2 y_3 \ge y_2 y3≥y2 时,在 nums 2 \textit{nums}_2 nums2 的其余更大元素中, nums 1 \textit{nums}_1 nums1 相对于 nums 2 \textit{nums}_2 nums2 的优势不变或减 1 1 1,不可能有更大的优势。
因此,对于 nums 2 \textit{nums}_2 nums2 中的每个元素 x x x,选择 nums 1 \textit{nums}_1 nums1 的剩余元素中大于 x x x 的最小元素作为 x x x 的优势元素,该贪心策略可以使 nums 1 \textit{nums}_1 nums1 相对于 nums 2 \textit{nums}_2 nums2 的优势最大。
由于这道题需要得到使 nums 1 \textit{nums}_1 nums1 相对于 nums 2 \textit{nums}_2 nums2 的优势最大化的 nums 1 \textit{nums}_1 nums1 的任意排列,因此需要记录使优势最大化的 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 之间的元素对应关系,并记录 nums 2 \textit{nums}_2 nums2 的每个元素所在下标。
具体做法是,创建二维数组 numsIndices 2 \textit{numsIndices}_2 numsIndices2 记录 nums 2 \textit{nums}_2 nums2 每个元素及下标,其中 numsIndices 2 i 0 = nums 2 i \textit{numsIndices}_2i0 = \textit{nums}_2i numsIndices2i0=nums2i, numsIndices 2 i 1 = i \textit{numsIndices}_2i1 = i numsIndices2i1=i,将 nums 1 \textit{nums}_1 nums1 按升序排序、将 numsIndices 2 \textit{numsIndices}_2 numsIndices2 按元素值升序排序,然后从左到右遍历 nums 1 \textit{nums}_1 nums1,遍历过程中维护 numsIndices 2 \textit{numsIndices}_2 numsIndices2 的下标 j j j 和 k k k,初始时 j j j 和 k k k 分别位于 numsIndices 2 \textit{numsIndices}_2 numsIndices2 的左端和右端,对于每个 nums 1 i \textit{nums}_1i nums1i,执行如下操作。
-
如果 nums 1 i > numsIndices 2 j 0 \textit{nums}_1i > \textit{numsIndices}_2j0 nums1i>numsIndices2j0,则将 nums 1 i \textit{nums}_1i nums1i 作为 numsIndices 2 j 0 \textit{numsIndices}_2j0 numsIndices2j0 的优势元素,将 nums 1 i \textit{nums}_1i nums1i 填到结果排列的下标 numsIndices 2 j 1 \textit{numsIndices}_2j1 numsIndices2j1 处,然后将 j j j 向右移动一位。
-
如果 nums 1 i ≤ numsIndices 2 j 0 \textit{nums}_1i \le \textit{numsIndices}_2j0 nums1i≤numsIndices2j0,则 nums 1 i \textit{nums}_1i nums1i 不能作为 numsIndices 2 \textit{numsIndices}_2 numsIndices2 中的任意剩余元素的优势元素,将 nums 1 i \textit{nums}_1i nums1i 填到结果排列的下标 numsIndices 2 k 1 \textit{numsIndices}_2k1 numsIndices2k1 处,然后将 k k k 向左移动一位。
上述遍历过程中, numsIndices 2 j 0 \textit{numsIndices}_2j0 numsIndices2j0 和 numsIndices 2 k 0 \textit{numsIndices}_2k0 numsIndices2k0 分别是 numsIndices 2 \textit{numsIndices}_2 numsIndices2 的剩余元素中的最小元素与最大元素,因此符合贪心策略。
遍历结束之后,结果排列即为使 nums 1 \textit{nums}_1 nums1 相对于 nums 2 \textit{nums}_2 nums2 的优势最大的一种排列。
代码
java
class Solution {
public int[] advantageCount(int[] nums1, int[] nums2) {
int length = nums1.length;
int[][] numsIndices2 = new int[length][2];
for (int i = 0; i < length; i++) {
numsIndices2[i][0] = nums2[i];
numsIndices2[i][1] = i;
}
Arrays.sort(nums1);
Arrays.sort(numsIndices2, (a, b) -> a[0] - b[0]);
int[] permutation = new int[length];
int index1 = 0, index2Left = 0, index2Right = length - 1;
while (index1 < length && index2Left < length) {
if (nums1[index1] > numsIndices2[index2Left][0]) {
int currIndex = numsIndices2[index2Left][1];
permutation[currIndex] = nums1[index1];
index2Left++;
} else {
int currIndex = numsIndices2[index2Right][1];
permutation[currIndex] = nums1[index1];
index2Right--;
}
index1++;
}
return permutation;
}
}
复杂度分析
-
时间复杂度: O ( n log n ) O(n \log n) O(nlogn),其中 n n n 是数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的长度。创建包含 nums 2 \textit{nums}_2 nums2 的元素和下标信息的二维数组需要 O ( n ) O(n) O(n) 的时间,排序需要 O ( n log n ) O(n \log n) O(nlogn) 的时间,排序之后遍历两个数组需要 O ( n ) O(n) O(n) 的时间,因此时间复杂度是 O ( n log n ) O(n \log n) O(nlogn)。
-
空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums 1 \textit{nums}_1 nums1 和 nums 2 \textit{nums}_2 nums2 的长度。创建包含 nums 2 \textit{nums}_2 nums2 的元素和下标信息的二维数组需要 O ( n ) O(n) O(n) 的空间。