【重点!!!】【二分查找】4.寻找两个正序数组的中位数

题目

最佳解法:二分查找

在这里插入图片描述
在这里插入图片描述

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1
        m, n = len(nums1), len(nums2)
        imin, imax, half = 0, m, (m+n+1) // 2
        while imin <= imax:
            i = (imin + imax) // 2 # nums1分割线左侧元素数量
            j = half - i           # nums2分割线左侧元素数量
            if i < m and nums2[j-1] > nums1[i]: # i太小, 需要增大
                imin += 1
            elif i > 0 and nums1[i-1] > nums2[j]: # i太大,需要降低
                imax -= 1
            else:
                nums1_left_max = -inf if i == 0 else nums1[i-1]
                nums1_right_min = inf if i == m else nums1[i]
                nums2_left_max = -inf if j == 0 else nums2[j-1]
                nums2_right_min = inf if j == n else nums2[j]
                if (m + n) % 2 == 1:
                    return max(nums1_left_max, nums2_left_max)
                else:
                    return (max(nums1_left_max, nums2_left_max) + min(nums1_right_min, nums2_right_min)) / 2.0

法1:二分查找(最优解法)

时间复杂度:O(logMin(m, n)),空间复杂度:O(1)。
同时看这两种解法及其注释!!!
视频讲解:https://www.bilibili.com/video/BV1Xv411z76J/?spm_id_from=333.337.search-card.all.click&vd_source=af30aa36f473ad5a8ffdcc06e213d1f6
在这里插入图片描述

Python

class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        if len(nums1) > len(nums2):
            nums1, nums2 = nums2, nums1
        m, n = len(nums1), len(nums2)
        total = (m + n + 1) // 2
        # 在nums1的区间[0, m]里查找恰当的分割线
        # 使得nums1[i - 1] ≤ nums2[j] && nums2[j - 1] ≤ nums1[i]
        left, right = 0, m # [a, b)开闭区间
        while left < right:
            nums1_left = (left + right + 1) // 2        # nums1分割线左边元素数量
            nums2_left = total - nums1_left             # nums2分割线左边元素数量
            if nums1[nums1_left-1] > nums2[nums2_left]: # 分割线太靠右了,需要往左移动
                right = nums1_left-1
            else:
                left = nums1_left
        i, j = left, total - left
        nums1_left_max = -inf if i == 0 else nums1[i-1]
        nums1_right_min = inf if i == m else nums1[i]
        nums2_left_max = -inf if j == 0 else nums2[j-1]
        nums2_right_min = inf if j == n else nums2[j]
        if (m + n) % 2 == 1:
            return max(nums1_left_max, nums2_left_max)
        else:
            return (max(nums1_left_max, nums2_left_max) + min(nums1_right_min, nums2_right_min)) / 2.0

Java

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        if (nums1.length > nums2.length) {
            int[] tmp = nums1;
            nums1 = nums2;
            nums2 = tmp;
        }
        int m = nums1.length, n = nums2.length;
        // 在nums1的区间[0, m]里查找恰当的分割线
        // 使得nums1[i - 1] ≤ nums2[j] && nums2[j - 1] ≤ nums1[i]

        int totalLeft = (m + n + 1) / 2; // 左 ≥ 右
        int left = 0, right = m; // [left, right)是闭开区间
        while (left < right) {
            int nums1Left = (left + right + 1) / 2; // 是指的nums1分割线左侧元素个数(左 ≥ 右), 对应索引是nums1Left - 1
            int nums2Left = totalLeft - nums1Left;  // 是指的nums2分割线左侧元素个数(左 ≥ 右), 对应索引是nums2Left - 1
            if (nums1[nums1Left - 1] > nums2[nums2Left]) { // nums1的分割线太靠右,需要往左移
                right = nums1Left - 1; // right是取不到的边界, 下次迭代索引nums1Left - 1肯定取不到,故设置right = nums1Left - 1
            } else { // 这里并未直接判断nums2[nums2Left - 1]与nums1[nums1Left]的关系, 故使得nums1[nums1Left]尽量大
                left = nums1Left;      // left是可取到的边界,  下次迭代索引可能取到nums1Left,故设置left = nums1Left
            }
        }
        int i = left, j = totalLeft - left;
        int nums1LeftMax = i == 0 ? Integer.MIN_VALUE : nums1[i - 1];
        int nums1RightMin = i == m ? Integer.MAX_VALUE : nums1[i];
        int nums2LeftMax = j == 0 ? Integer.MIN_VALUE : nums2[j - 1];
        int nums2RightMin = j == n ? Integer.MAX_VALUE : nums2[j];
        int leftMax = Math.max(nums1LeftMax, nums2LeftMax);
        int rightMin = Math.min(nums1RightMin, nums2RightMin);
        if ((m + n) % 2 == 1) {
            return (double) leftMax;
        } else {
            return ((double) leftMax + (double) rightMin) / 2.0;
        }
    }
}
### 中位数算法实现 中位数是指一数据按大小顺序排列后处于中间位置的数值。如果数据数量为奇数,则中位数中间的那个值;如果是偶数,则中位数通常是中间两个数的平均值。 下面是一个基于快速选择(Quickselect)算法的 C 实现,用于找到数中的中位数[^1]: ```c #include <stdio.h> // 交换两个整数 void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } // 划分函数,类似于快速排序中的划分操作 int partition(int arr[], int low, int high) { int pivot = arr[high]; int i = low - 1; for (int j = low; j <= high - 1; j++) { if (arr[j] <= pivot) { i++; swap(&arr[i], &arr[j]); } } swap(&arr[i + 1], &arr[high]); return i + 1; } // 快速选择算法的核心部分 int kthSmallest(int arr[], int l, int r, int k) { if (k > 0 && k <= r - l + 1) { int pos = partition(arr, l, r); if (pos - l == k - 1) return arr[pos]; if (pos - l > k - 1) return kthSmallest(arr, l, pos - 1, k); else return kthSmallest(arr, pos + 1, r, k - pos + l - 1); } return INT_MAX; } double findMedian(int arr[], int n) { if (n % 2 == 1) { return kthSmallest(arr, 0, n - 1, n / 2 + 1); // 奇数情况返回第 (n/2)+1 小的元素 } else { int first = kthSmallest(arr, 0, n - 1, n / 2); // 找到第一个中间值 int second = kthSmallest(arr, 0, n - 1, n / 2 + 1); // 找到第二个中间值 return ((double)(first + second)) / 2.0; // 返回它们的平均值 } } int main() { int arr[] = {9, 5, 7, 1, 3}; int n = sizeof(arr) / sizeof(arr[0]); double median = findMedian(arr, n); printf("Median: %.2lf\n", median); return 0; } ``` 上述代码实现了快速选择算法来高效地求解中位数。对于更复杂的场景或者需要保证最坏情况下性能稳定的情况,可以考虑 BFPRT 算法(即“中位数中位数”算法),其时间复杂度为 \(O(n)\)[^3]。 #### 关于 y 轴上的最佳位置问题 在某些实际应用中,比如寻找最优加油站的位置等问题,通常可以通过计算给定点集中某维度(如 y 坐标)的中位数作为目标位置的选择依据[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值