算法--------------------寻找两个有序数组的中位数

本文主要是介绍算法--------------------寻找两个有序数组的中位数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。你可以假设 nums1 和 nums2 不会同时为空。示例 1:nums1 = [1, 3]
nums2 = [2]则中位数是 2.0
示例 2:nums1 = [1, 2]
nums2 = [3, 4]则中位数是 (2 + 3)/2 = 2.5来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

我的解决方法:

package com.xinyu.test;/*** Created by zy on 2019/4/16.*/
public class TestArray13 {public static void main(String[] args) {System.out.println(findMedianSortedArrays(new int[]{1,2},new int[]{-1,3}));}/***** 寻找两个有序数组的中位数给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。你可以假设 nums1 和 nums2 不会同时为空。示例 1:nums1 = [1, 3]nums2 = [2]则中位数是 2.0示例 2:nums1 = [1, 2]nums2 = [3, 4]则中位数是 (2 + 3)/2 = 2.5*/public static double findMedianSortedArrays(int[] nums1, int[] nums2) {int length1 = 0,length2 = 0;if (nums1 != null) {length1 = nums1.length;}if (nums2 != null) {length2 = nums2.length;}if (length1 == 0 ) {if (length2 % 2 == 0) {return (double) (nums2[length2/2] + nums2[length2/2 -1]) / 2;}else {return (double)nums2[length2/2];}}if (length2 == 0){if (length1 % 2 == 0) {return (double)(nums1[length1/2] + nums1[length1/2 -1]) / 2;}else {return (double)nums1[length1/2];}}
//        if (nums1[0] > nums2[0]) {
//            return findMedianSortedArrays(nums2,nums1);
//        }
//        int all = length1 + length2;
//        if (all %2 ==0) {
//            return  (double)(nums1[length1 -1] + nums2[0]) / 2;
//        }else {
//            return (double)nums1[length1 -1] < (double)nums2[0] ? (double)nums1[length1 -1] : (double)nums2[0] ;
//        }int arr[] = new int[length1 + length2];for (int i = 0, j = 0 , q = 0;i < length1 || (j < length2);){if (i < length1 && j < length2){if (nums1[i] < nums2[j]) {arr[q++] = nums1[i++];}else {arr[q++] = nums2[j++];}}else if (i < length1){arr[q++] = nums1[i++];}else if (j < length2){arr[q++] = nums2[j++];}}int all = length1 + length2;if (all % 2 == 0) {return (double)(arr[all/2] + arr[all/2 -1]) / 2;}else {return (double)arr[all/2];}}}

网上的解决方法:

package com.xinyu.test;/*** Created by zy on 2019/4/16.*/
public class TestArray13 {public static void main(String[] args) {System.out.println(findMedianSortedArrays(new int[]{1,2},new int[]{-1,3}));}/***** 寻找两个有序数组的中位数给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。你可以假设 nums1 和 nums2 不会同时为空。示例 1:nums1 = [1, 3]nums2 = [2]则中位数是 2.0示例 2:nums1 = [1, 2]nums2 = [3, 4]则中位数是 (2 + 3)/2 = 2.5*/public static double findMedianSortedArrays(int[] nums1, int[] nums2) {int length = nums1.length + nums2.length;if (length % 2 == 1) {return findKth(nums1, 0, nums2, 0, length / 2 + 1);}int small = findKth(nums1, 0, nums2, 0, length / 2);int big = findKth(nums1, 0, nums2, 0, length / 2 + 1);return (small + big) / 2.0;}/**** @param nums1 数组1* @param index1 表示数组1从第几位开始找* @param nums2 数组2* @param index2  表示数组2 从第几位开始找* @param k  k表示要找第几位,注意k 代表的不是索引,是索引加1* @return*/private static int findKth(int[] nums1, int index1, int[] nums2, int index2, int k) {// 如果第一个数组查找的位置是末尾,那么说明要找的数据不再数组1里面,那么直接从数组2里面找就可以。if (index1 == nums1.length) {return nums2[index2 + k - 1];}// 如果第二个数组查找的位置是末尾,那么说明要找的数据不再数组1里面,那么直接从数组1里面找就可以。if (index2 == nums2.length) {return nums1[index1 + k - 1];}//如果要找当前第一位,那么直接返回当前两个数组的最小值if (k == 1) {return Math.min(nums1[index1], nums2[index2]);}// 找到第k  位对应的,两个数组的数值  每次排除掉k/2 个数int num1 = index1 + k / 2 - 1 < nums1.length ? nums1[index1 + k / 2 - 1] : Integer.MAX_VALUE;int num2 = index2 + k / 2 - 1 < nums2.length ? nums2[index2 + k / 2 - 1] : Integer.MAX_VALUE;// 如果数组1 的比较小,那么数组1的查找开始位置要往前挪动k/2 个位置(即一下子排除了k/2 个元素),同时要找的位置减去k/2//注意 数学里面的k - k / 2  和java 里面的k - k / 2 不是等值的if (num1 < num2) {return findKth(nums1, index1 + k / 2, nums2, index2, k - k / 2);}// 如果数组2 的比较小,那么数组2的查找开始位置要往前挪动k/2 个位置(即一下子排除了k/2 个元素),同时要找的位置减去k/2return findKth(nums1, index1, nums2, index2 + k / 2, k - k / 2);}}

个人看了大概二个小时,终于看懂了。

大概逻辑是这样:

首先确定是需要寻找一个数,还是寻找两个数,如果是一个数,那么寻找第K 位数返回就可以了,如果是找两个数,那么就调用两次方法找到,求平均值就可以了。

关键在于寻找第k 个数。两个数组,我要找第k 个数,那么我可以 直接排除k/2 个数。怎么排除呢?
因为是两个有序数组,那么我找两个数组的第k/2 位,谁的值小,那么谁所在的数组开始查找的索引位置,直接往前挪k/2个位置。因为要找的数,肯定不在这里面。
然后依次再找第k -k/2 个数,因为前面已经挪了k/2 个数,那么要找的第k 个数,其实是在k - k/2 个位置。继续递归往后找。
直到k == 1 ,那么取最小的一个值。因为要找的是比较小的一个。或者有一个数组已经没有元素可以找了,那么返回另外一个数组的index + k-1 的数就可以了。

二分法查找,确实快。不需要一个一个遍历!学到了。

这篇关于算法--------------------寻找两个有序数组的中位数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131029

相关文章

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

C语言实现两个变量值交换的三种方式

《C语言实现两个变量值交换的三种方式》两个变量值的交换是编程中最常见的问题之一,以下将介绍三种变量的交换方式,其中第一种方式是最常用也是最实用的,后两种方式一般只在特殊限制下使用,需要的朋友可以参考下... 目录1.使用临时变量(推荐)2.相加和相减的方式(值较大时可能丢失数据)3.按位异或运算1.使用临时

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

java两个List的交集,并集方式

《java两个List的交集,并集方式》文章主要介绍了Java中两个List的交集和并集的处理方法,推荐使用Apache的CollectionUtils工具类,因为它简单且不会改变原有集合,同时,文章... 目录Java两个List的交集,并集方法一方法二方法三总结java两个List的交集,并集方法一

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

C++一个数组赋值给另一个数组方式

《C++一个数组赋值给另一个数组方式》文章介绍了三种在C++中将一个数组赋值给另一个数组的方法:使用循环逐个元素赋值、使用标准库函数std::copy或std::memcpy以及使用标准库容器,每种方... 目录C++一个数组赋值给另一个数组循环遍历赋值使用标准库中的函数 std::copy 或 std::

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::