🚩传送门:牛客题目

题目

给定两个递增数组 [NC]36. 在两长度相等的有序数组中找中位数 - 图1 [NC]36. 在两长度相等的有序数组中找中位数 - 图2,已知两个数组的长度都为 [NC]36. 在两长度相等的有序数组中找中位数 - 图3,求两个数组中所有数的上中位数
上中位数:假设递增序列长度为 [NC]36. 在两长度相等的有序数组中找中位数 - 图4,为第 [NC]36. 在两长度相等的有序数组中找中位数 - 图5 个数

解题思路:双指针

假设将两个数组合并为一个数组,先算出上中位数在合并后的数组中的下标位置 。然后模拟二路归并,当下标到达上中位数时返回结果。

题目加速过程:

  1. 合并后数组的上中位数下标数值 [NC]36. 在两长度相等的有序数组中找中位数 - 图6可以理解为:**i** , **j**需要移动的次数
  2. 当有一方指针越界,另外一方可以直接求出 。

    举例子:现在假设 mid = 1

    1. 我们可以知道 上中位数 在合并后数组中的下标为 1
    2. [NC]36. 在两长度相等的有序数组中找中位数 - 图7[NC]36. 在两长度相等的有序数组中找中位数 - 图8需要移动的次数 为 1

    [NC]36. 在两长度相等的有序数组中找中位数 - 图9[NC]36. 在两长度相等的有序数组中找中位数 - 图10初始一定指向[NC]36. 在两长度相等的有序数组中找中位数 - 图11(且其中有一个在合并后数组中的位置为[NC]36. 在两长度相等的有序数组中找中位数 - 图12 ),因此[NC]36. 在两长度相等的有序数组中找中位数 - 图13[NC]36. 在两长度相等的有序数组中找中位数 - 图14中有一个指针只需要走 **1**就可以到达上中位数的位置。

    那么当其中一个指针失效时可以直接计算答案,因为还剩下[NC]36. 在两长度相等的有序数组中找中位数 - 图15 步没走不妨设为[NC]36. 在两长度相等的有序数组中找中位数 - 图16越界,那么[NC]36. 在两长度相等的有序数组中找中位数 - 图17直接走完剩余路程就可以到达上中位数


复杂度分析

时间复杂度:[NC]36. 在两长度相等的有序数组中找中位数 - 图18,其中 [NC]36. 在两长度相等的有序数组中找中位数 - 图19 为合并后数组的长度。

空间复杂度:[NC]36. 在两长度相等的有序数组中找中位数 - 图20,使用常数的空间

我的代码

  1. public class Solution {
  2. public int findMedianinTwoSortedAray (int[] arr1, int[] arr2) {
  3. //0. 获取数组长度
  4. int a1len = arr1.length;
  5. int a2len = arr2.length;
  6. //1. 计算合并后数组中的上中位数位置(或者说i,j需要移动的次数)
  7. int mid = a1len + (a2len - a1len + 1) / 2-1;
  8. int j = 0, i = 0;
  9. //2. 假装二路归并
  10. while (i < a1len && j < a2len) {
  11. if (mid-- == 0)
  12. return Math.min(arr1[i], arr2[j]);
  13. if (arr1[i] < arr2[j])
  14. i++;
  15. else
  16. j++;
  17. }
  18. // 当arr2走完的时候,arr1还没走完,此时上中位数则在arr1中
  19. if (i < a1len)
  20. return arr1[i + mid];// i 将剩余的 mid 步走完
  21. else
  22. return arr2[j + mid];// j 将剩余的 mid 步走完
  23. }
  24. }

解题思路:二分查找

时间复杂度度要求为[NC]36. 在两长度相等的有序数组中找中位数 - 图21,很容易就想到了二分查找。

算法是思路为:

先定位到两个数组的中位数,比较此时两个中位数对应的数的大小,再根据结果去进行调整,以数组1不超出范围为循环条件,每次比较区间范围的中位数的大小,将left1left2这两个指针始终指向可能的中位数的位置,因为数组是从小到大进行排序的。

复杂度分析

时间复杂度:[NC]36. 在两长度相等的有序数组中找中位数 - 图22,其中 [NC]36. 在两长度相等的有序数组中找中位数 - 图23 为合并后数组的长度。

空间复杂度:[NC]36. 在两长度相等的有序数组中找中位数 - 图24,使用常数的空间

我的代码

  1. import java.util.*;
  2. public class Solution {
  3. public int findMedianinTwoSortedAray (int[] arr1, int[] arr2) {
  4. // write code here
  5. if(arr1 == null || arr2 == null || arr1.length!=arr2.length){
  6. return 0;
  7. }
  8. // 数组1的左边界
  9. int left1 = 0;
  10. // 数组1的右边界
  11. int right1 = arr1.length - 1;
  12. // 数组2的左边界
  13. int left2 = 0;
  14. // 数组2的右边界
  15. int right2 = arr2.length - 1;
  16. // 数组1的中点
  17. int mid1 = 0;
  18. // 数组2的中点
  19. int mid2 = 0;
  20. // 偏移量
  21. int offset = 0;
  22. while(left1 < right1){
  23. // 找到两个数组的中点
  24. mid1 = left1+(right1 - left1) / 2;
  25. mid2 = left2+(right2 - left2) / 2;
  26. offset = ((right1 - left1 + 1)&1)^1; //位运算比对2取余要快
  27. // 当此时arr1中点位置大于arr2中点位置时
  28. if(arr1[mid1] > arr2[mid2]){
  29. // 调整arr1的右边界为mid1
  30. right1 = mid1;
  31. // 数组2的左边界调整为当前位置+偏移量
  32. left2 = mid2 + offset;
  33. }else if(arr1[mid1] < arr2[mid2]){
  34. right2 = mid2;
  35. left1 = mid1 + offset;
  36. }else {
  37. // 当相等的时候,则中位数即为此时
  38. return arr1[mid1];
  39. }
  40. }
  41. // 中位数为数组1的左指针的位置,或者数组2的左指针的位置
  42. return Math.min(arr1[left1],arr2[left2]);
  43. }
  44. }