LeetCode刷题实战4:寻找两个正序数组的中位数

server/2024/9/23 9:25:25/

题目内容

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2

示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5

提示:

  • nums1.length == m
  • nums2.length == n
  • 0 <= m <= 1000
  • 0 <= n <= 1000
  • 1 <= m + n <= 2000
  • -106 <= nums1[i], nums2[i] <= 106

解题方法

解题思路一

暴力求解:

b比较直接的想法是直接把两个数组合并成一个数组,但是时间复杂度肯定不满足要求。

解题思路二

二分查找:

因为题目要求算法的时间复杂度应该为 O(log (m+n)) ,顺序遍历肯定是不行的,只能用类似二分查找的思路来解这个题目。

根据中位数的定义:

当 m+n是奇数时,中位数是两个有序数组中的第 (m+n)/2个元素;

当 m+n是偶数时,中位数是两个有序数组中的第 (m+n)/2个元素和第 (m+n)/2+1个元素的平均值。

因此,这道题可以转化成寻找两个有序数组中的第 k小的数,其中 k 为 (m+n)/2或 (m+n)/2+1

所以面试题 也可以转换成 寻找两个有序数组中的第 k小的数 。

有以下三种情况需要特殊处理:

如果 A[k/2−1]\text{A}[k/2-1]A[k/2−1] 或者 B[k/2−1]\text{B}[k/2-1]B[k/2−1] 越界,那么我们可以选取对应数组中的最后一个元素。在这种情况下,我们必须根据排除数的个数减少 kkk 的值,而不能直接将 kkk 减去 k/2k/2k/2。

如果一个数组为空,说明该数组中的所有元素都被排除,我们可以直接返回另一个数组中第 kkk 小的元素。

如果 k=1k=1k=1,我们只要返回两个数组首元素的最小值即可。

public double findMedianSortedArrays(int[] nums1, int[] nums2) {int length1 = nums1.length;int length2 = nums2.length;int totalLength = length1 + length2;if (totalLength % 2 == 1) {// 奇数int midIndex = totalLength / 2;double midValue = findKElement(nums1, nums2, midIndex + 1);return midValue;} else {// 偶数int midIndex1 = totalLength / 2 - 1;int midIndex2 = totalLength / 2;int midValue1 = findKElement(nums1, nums2, midIndex1 + 1);int midValue2 = findKElement(nums1, nums2, midIndex2 + 1);return (midValue1 + midValue2) / 2.0;}}/*** 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1]* 进行比较* 这里的 "/" 表示整除* nums1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个* nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个* 取 pivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <=* k-2 个* 这样 pivot 本身最大也只能是第 k-1 小的元素* 如果 pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的* nums1 数组* 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的* nums2 数组* 由于我们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数*/public int findKElement(int[] nums1, int[] nums2, int k) {int length1 = nums1.length;int length2 = nums2.length;int index1 = 0;int index2 = 0;while (true) {// 边界情况if (index1 == length1) {return nums2[index2 + k - 1];}if (index2 == length2) {return nums1[index1 + k - 1];}if (k == 1) {return Math.min(nums1[index1], nums2[index2]);}// 正常情况int half = k / 2;int newIndex1 = Math.min(index1 + half, length1) - 1;int newIndex2 = Math.min(index2 + half, length2) - 1;int v1 = nums1[newIndex1];int v2 = nums2[newIndex2];if (v1 <= v2) {k -= (newIndex1 - index1 + 1);index1 = newIndex1 + 1;} else {k -= (newIndex2 - index2 + 1);index2 = newIndex2 + 1;}}}

题解参考了官方的题解方法,链接:https://leetcode.cn/problems/median-of-two-sorted-arrays/solutions/258842/xun-zhao-liang-ge-you-xu-shu-zu-de-zhong-wei-s-114/
 

解题思路三

划线:

(上面图片来自网络)

思路是在两个数组上 画一条线,思路是比较简单,但是特殊情况的考虑和边界的考虑是比较困难的,非常容易出错。

class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {if (nums1.length > nums2.length) {return findMedianSortedArrays(nums2, nums1);}int m = nums1.length;int n = nums2.length;int left = 0, right = m;// median1:前一部分的最大值// median2:后一部分的最小值int median1 = 0, median2 = 0;while (left <= right) {// 前一部分包含 nums1[0 .. i-1] 和 nums2[0 .. j-1]// 后一部分包含 nums1[i .. m-1] 和 nums2[j .. n-1]int i = (left + right) / 2;int j = (m + n + 1) / 2 - i;// nums_im1, nums_i, nums_jm1, nums_j 分别表示 nums1[i-1], nums1[i], nums2[j-1], nums2[j]int nums_im1 = (i == 0 ? Integer.MIN_VALUE : nums1[i - 1]);int nums_i = (i == m ? Integer.MAX_VALUE : nums1[i]);int nums_jm1 = (j == 0 ? Integer.MIN_VALUE : nums2[j - 1]);int nums_j = (j == n ? Integer.MAX_VALUE : nums2[j]);if (nums_im1 <= nums_j) {median1 = Math.max(nums_im1, nums_jm1);median2 = Math.min(nums_i, nums_j);left = i + 1;} else {right = i - 1;}}return (m + n) % 2 == 0 ? (median1 + median2) / 2.0 : median1;}
}


http://www.ppmy.cn/server/11809.html

相关文章

Linux内核驱动开发-006内核定时器

1驱动程序 /*************************************************************************> File Name: timer.c> Author: yas> Mail: rage_yashotmail.com> Created Time: 2024年04月23日 星期二 19时20分42秒*************************************************…

[ LeetCode ] 题刷刷(Python)-第28题:找出字符串中第一个匹配项的下标

题目描述 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示例 示例 1&#xff1a; 输入&#xff1a;…

前端学习<四>JavaScript基础——44-键盘事件

鼠标的拖拽事件 拖拽的流程&#xff1a; &#xff08;1&#xff09;onmousedown&#xff1a;当鼠标在被拖拽元素上按下时&#xff0c;开始拖拽&#xff1b; &#xff08;2&#xff09;onmousemove&#xff1a;当鼠标移动时被拖拽元素跟随鼠标移动&#xff1b; &#xff08;…

路由引入,过滤实验

实验拓补图 实验目的&#xff1a; 1、按照图示配置 IP 地址&#xff0c;R1&#xff0c;R3&#xff0c;R4 loopback口模拟业务网段 2、R1 和 R2 运行 RIPv2,R2&#xff0c;R3和R4运行 OSPF&#xff0c;各自协议内部互通 3、在 RIP 和 oSPF 间配置双向路由引入,要求除 R4 上的…

FLAML框架学习干货整理

一、FLAML介绍 FLAML (Fast and Lightweight AutoML) 是一个用于自动机器学习&#xff08;AutoML&#xff09;的 Python 库&#xff0c;旨在快速且资源效率高地找到机器学习任务的最优模型和其超参数。它由微软研究院开发&#xff0c;适用于广泛的机器学习任务&#xff0c;如分…

VUE-列表

VUE-列表 列表功能 如下例子 列表展示 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><meta http-equiv&qu…

AUTOSAR-COMStack-003_SignalGroup如何发送接收

1. Ref Ref.1 AUTOSAR_RS_Main.pdf Ref.1 AUTOSAR_RS_Features.pdf Ref.2 AUTOSAR_SRS_COM.pdf Ref.3 AUTOSAR_SWS_COM.pdf 2. 为什么要使用Signal Group&#xff1f; 2.1 Traceabilty [RS_PO_00004] AUTOSAR shall define an open architecture for automotive software.…

python基本语法与使用

Python是一种高级编程语言&#xff0c;它被广泛应用于各种领域&#xff0c;包括Web开发、数据科学、人工智能等。以下是Python的基本语法和使用方法&#xff1a; 1.注释 使用#来添加单行注释&#xff0c;多行注释可以使用或"""来包围。 # 这是一个单行注释…