67、二分-寻找两个正序数组的中位数

思路: 

第一种方式双指针,只要排序一半数组的就行,那么就找到中位数。两个指针谁小移动谁。

1、两个都是有序数组,那么中位数就是合并成一个新的有序数组的中位数
2、只要排序到新数组长度的一半就可以得到中位数。因为我们不需要有序的数组,所以新建一个数组来记录。

代码如下:

class Solution {
    // 定义一个函数,接收两个整数数组作为参数
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
       // 初始化两个指针,分别指向两个数组的开始
       int aIndex = 0; 
       int bIndex = 0;
       // value 用于记录当前访问的元素,before 用于记录上一个访问的元素
       int value = 0; 
       int before = 0;
       
       // 循环至两数组长度之和的一半,因为中位数就在这个位置
       for (int i = 0; i <= (nums1.length + nums2.length) / 2; i++) {
           before = value; // 更新前一个元素
           // 比较两个数组当前元素的大小,以决定从哪个数组取元素
           if (aIndex < nums1.length && bIndex < nums2.length && nums1[aIndex] <= nums2[bIndex]) {
               value = nums1[aIndex++]; // 取 nums1 的元素,并将 aIndex 加 1
           } else {
               // 如果 nums1 已全部访问完,只能从 nums2 取元素
               if (aIndex >= nums1.length) {
                   value = nums2[bIndex++]; // 取 nums2 的元素,并将 bIndex 加 1
               } else if (bIndex >= nums2.length) { // 如果 nums2 已全部访问完,只能从 nums1 取元素
                   value = nums1[aIndex++];
               } else { // 否则从 nums2 取元素
                   value = nums2[bIndex++];
               }
           }
       }
       // 根据两数组长度之和判断是奇数还是偶数
       if ((nums1.length + nums2.length) % 2 == 0) {
           // 如果是偶数,中位数是中间两个数的平均值
           return (value + before) / 2.0;
       } else {
           // 如果是奇数,中位数是中间的那个数
           return value * 1.0;
       }
    }
}

第二种方式:改成求第k小的数。那么中位数就是第mid小的数。这个求第K小的数据就可以使用二分的方式。

public class Solution {
    
    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
		int size = nums1.length + nums2.length;
        int mid = findKthNum(nums1, nums2, size / 2+1);
        if (size%2==0){
            int upMid = findKthNum(nums1, nums2, size / 2);
            return (upMid+mid)/2.0;
        }else {
            return mid*1.0;
        }
	}
    public static int findKthNum(int[] arr1, int[] arr2, int kth) {
        int len1 = arr1.length, len2 = arr2.length;
        // 检查k是否为有效值
        if (kth > len1 + len2 || kth < 1) {
            return Integer.MAX_VALUE; // 返回一个错误码,比如-1,表示输入不合法
        }

        int index1 = 0, index2 = 0;  // 初始化两个数组的指针

        while (true) {
            // 边界情况
            if (index1 == len1) {
                return arr2[index2 + kth - 1];  // arr1已经全部考虑过,直接从arr2中取值
            }
            if (index2 == len2) {
                return arr1[index1 + kth - 1];  // arr2已经全部考虑过,直接从arr1中取值
            }
            if (kth == 1) {
                return Math.min(arr1[index1], arr2[index2]);  // 如果kth为1,最小的数即为两数组当前指针的最小值
            }

            // 正常情况,通过二分的方式减少搜索范围
            int halfK = kth / 2;
            int newIndex1 = Math.min(index1 + halfK, len1) - 1;  // 计算新的指针位置,不越界
            int newIndex2 = Math.min(index2 + halfK, len2) - 1;
            int pivot1 = arr1[newIndex1], pivot2 = arr2[newIndex2];
            if (pivot1 <= pivot2) {
                // pivot1较小或相等,舍弃arr1中index1到newIndex1的部分 就是说这部分不可能成为第k小数,但是肯定比第k小还要小,
                //那么这部分有多少个数呢?newIndex1-index+1   那么就是求 k减去这部分的 小值
                kth = kth - (newIndex1 - index1 + 1);
                //重新设置index1
                index1 = newIndex1 + 1;
            } else {
                // pivot2较小,舍弃arr2中index2到newIndex2的部分 同上
                kth -= (newIndex2 - index2 + 1);
                //重新设置index2
                index2 = newIndex2 + 1;
            }
        }
        // 由于逻辑保证了函数能够在循环中返回有效值,因此这里不需要额外的return语句
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值