乘风破浪:LeetCode真题_004_Median of Two Sorted Arrays

一、前言

说到算法,最难的就是一些需要通过分析得到一些递推公式或者有用的结论,进而用来解决问题的方法了。这些东西一方面比较难以理解,另一方面都是有着严密的数学逻辑在里面的,并且需要通过程序来实现,无疑增加了求解的困难。就比如说这次的问题,在两个已经排好序的数组之中找到中间值。这里就涉及到两个数组总长度是奇数还是偶数,如何查找的问题了。

二、Median of Two Sorted Arrays 

2.1 问题理解

2.2 分析解决

通过对题目的研究我们能够理解如果是奇数,则不用经过运算即可,如果是偶数,则需要将中间的两个数取平均值。最简单的想法就是将两个数组合并成一个数组,然后求中位数即可。但是这样的方式对于两个已经排好序的数组,需要遍历O(m+n)次,然后才能确定,其中m,n分别为两个已经排好序数组的长度。而题目要求算法时间复杂度为O(log2(m+n)),因此不能使用,那么我们要怎么做呢??

我们先来看看官方的算法:

首先进行分析,假设m<=n,两个数组A,B从小到大排列,那么如果我们分别对两个数组进行某种分割,分割的指针分别为i,j,并且分割之后要达到的结果是分成了四份,左边的两份A1,B1和在一起的长度等于右边A2,B2合在一起的长度,或者(+1),这样我们就找到了中间的几个数,但是我们还需要保证左边的所有元素的最大值要小于或者等于右边所有元素的最小值,如果能保证这两个条件,最终的结果就是左边所有的最大值与右边所有的最小值的平均值,或者左边/右边的最大值/最小值,具体看左边还是右边需要根据算法来考虑。这样就得到了解决问题的思路,可以使用二分查找算法来折半查找,同时也要注意一些边界的条件。

 class Solution {
public double findMedianSortedArrays(int[] A, int[] B) {
int m = A.length;
int n = B.length;
if (m > n) { // to ensure m<=n
int[] temp = A; A = B; B = temp;
int tmp = m; m = n; n = tmp;
}
int iMin = 0, iMax = m, halfLen = (m + n + 1) / 2;
while (iMin <= iMax) {
int i = (iMin + iMax) / 2;
int j = halfLen - i;
if (i < iMax && B[j-1] > A[i]){
iMin = i + 1; // i is too small
}
else if (i > iMin && A[i-1] > B[j]) {
iMax = i - 1; // i is too big
}
else { // i is perfect
int maxLeft = 0;
if (i == 0) { maxLeft = B[j-1]; }
else if (j == 0) { maxLeft = A[i-1]; }
else { maxLeft = Math.max(A[i-1], B[j-1]); }
if ( (m + n) % 2 == 1 ) { return maxLeft; } int minRight = 0;
if (i == m) { minRight = B[j]; }
else if (j == n) { minRight = A[i]; }
else { minRight = Math.min(B[j], A[i]); } return (maxLeft + minRight) / 2.0;
}
}
return 0.0;
}
}

  下面来看看我们的思路:

public class Solution {
/**
* <pre>
* There are two sorted arrays nums1 and nums2 of size m and n respectively.
* Find the median of the two sorted arrays. The overall run time complexity
* should be O(log (m+n)).
*
* 题目大意:
* 两个排序数组,找这两个排序数组的中位数,时间复杂度为O(log(m+n))
*
* 题解思路:
* 递归分治求解
* </pre>
*
* @param nums1
* @param nums2
* @return
*/
public double findMedianSortedArrays(int[] nums1, int[] nums2) { if (nums1 == null) {
nums1 = new int[0];
} if (nums2 == null) {
nums2 = new int[0];
} int len1 = nums1.length;
int len2 = nums2.length; if (len1 < len2) {
// 确保第一个数组比第二个数组长度大
return findMedianSortedArrays(nums2, nums1);
} // 如果长度小的数组长度为0,就返回前一个数组的中位数
if (len2 == 0) {
return (nums1[(len1 - 1) / 2] + nums1[len1 / 2]) / 2.0;
} int lo = 0;
int hi = len2 * 2;
int mid1;
int mid2;
double l1;
double l2;
double r1;
double r2; while (lo <= hi) {
mid2 = (lo + hi) / 2;
mid1 = len1 + len2 - mid2; l1 = (mid1 == 0) ? Integer.MIN_VALUE : nums1[(mid1 - 1) / 2];
l2 = (mid2 == 0) ? Integer.MIN_VALUE : nums2[(mid2 - 1) / 2]; r1 = (mid1 == len1 * 2) ? Integer.MAX_VALUE : nums1[mid1 / 2];
r2 = (mid2 == len2 * 2) ? Integer.MAX_VALUE : nums2[mid2 / 2]; if (l1 > r2) {
lo = mid2 + 1;
} else if (l2 > r1) {
hi = mid2 - 1;
} else {
return (Math.max(l1, l2) + Math.min(r1, r2)) / 2;
}
} return -1;
}
}

   注意我们这里的算法和官方的原理一样,只不过是将分割的坐标都扩大了两倍,这样更加能优化算法的性能,并且因为扩大了2倍之后,其他地方也做了相应的改变而已。

三、总结

遇到这样的问题,最重要的是要学会如何去建模,然后进行解决,涉及到了一定的算法和逻辑思维能力,对分析和理解都有很大的考察价值。

乘风破浪:LeetCode真题_004_Median of Two Sorted Arrays的更多相关文章

  1. 乘风破浪:LeetCode真题_033_Search in Rotated Sorted Array

    乘风破浪:LeetCode真题_033_Search in Rotated Sorted Array 一.前言     将传统的问题进行一些稍微的变形,这个时候我们可能无所适从了,因此还是实践出真知, ...

  2. 乘风破浪:LeetCode真题_026_Remove Duplicates from Sorted Array

    乘风破浪:LeetCode真题_026_Remove Duplicates from Sorted Array 一.前言     我们这次的实验是去除重复的有序数组元素,有大体两种算法. 二.Remo ...

  3. leetcode第二题--Median of Two Sorted Arrays

    Problem:There are two sorted arrays A and B of size m and n respectively. Find the median of the two ...

  4. 乘风破浪:LeetCode真题_034_Find First and Last Position of Element in Sorted Array

    乘风破浪:LeetCode真题_034_Find First and Last Position of Element in Sorted Array 一.前言 这次我们还是要改造二分搜索,但是想法却 ...

  5. 乘风破浪:LeetCode真题_023_Merge k Sorted Lists

    乘风破浪:LeetCode真题_023_Merge k Sorted Lists 一.前言 上次我们学过了合并两个链表,这次我们要合并N个链表要怎么做呢,最先想到的就是转换成2个链表合并的问题,然后解 ...

  6. 乘风破浪:LeetCode真题_021_Merge Two Sorted Lists

    乘风破浪:LeetCode真题_021_Merge Two Sorted Lists 一.前言 关于链表的合并操作我们是非常熟悉的了,下面我们再温故一下将两个有序链表合并成一个的过程,这是基本功. 二 ...

  7. 乘风破浪:LeetCode真题_041_First Missing Positive

    乘风破浪:LeetCode真题_041_First Missing Positive 一.前言 这次的题目之所以说是难,其实还是在于对于某些空间和时间的限制. 二.First Missing Posi ...

  8. 乘风破浪:LeetCode真题_040_Combination Sum II

    乘风破浪:LeetCode真题_040_Combination Sum II 一.前言 这次和上次的区别是元素不能重复使用了,这也简单,每一次去掉使用过的元素即可. 二.Combination Sum ...

  9. 乘风破浪:LeetCode真题_039_Combination Sum

    乘风破浪:LeetCode真题_039_Combination Sum 一.前言     这一道题又是集合上面的问题,可以重复使用数字,来求得几个数之和等于目标. 二.Combination Sum ...

随机推荐

  1. Linux 设置代理时, 密码出现特殊字符怎么办?

    配置代理的格式一般是这样的: $ export https_proxy=https://用户名:密码@代理地址:代理端口 比如需要配置这些: $ export http_proxy=http://Co ...

  2. iOS 性能优化套路

    ***  一级套路 ***  使用ARC管理内存- 防止内存泄露- 保证释放掉不再需要的内存,提高性能 在正确的地方使用 reuseIdentifier平时接触的需要考虑重用的视图有UICollect ...

  3. [Mysql 查询语句]——对查询结果进一步的操作

    distinct 不显示重复的查询结果 (1) 对于表中一些没有唯一性约束的字段,可能存在重复的值,这时可以使用distinct来消除那些查询结果中的重复值 select cust_id  from ...

  4. Android6.0内核移植(1):分析编译日志

    在下面命令之后产生的编译日志进行分析 source build/envsetup.sh lunch sabresd_6dq-user make -j20 ======================= ...

  5. SQL空和NULL的区别

    1.NULL意思为缺失的值(missing value). 2.三值逻辑(three-valued-logic: TRUE,FALSE,UNKNOWN). 在SQL中有三个逻辑谓词:TURE,FALS ...

  6. SQLServer 触发器入门

    阅读目录 一:触发器的优点 二:触发器的作用 三:触发器的分类 四:触发器的工作原理 五:创建触发器 六:管理触发器 概念:   触发器(trigger)是SQL server 提供给程序员和数据分析 ...

  7. 三:SpringCloud-Ribbon

    六:Ribbon负载均衡 1. 概述 1.1 是什么 Spring Cloud Ribbon是基于Netflix Ribbon实现的一套==客户端 负载均衡==的工具. 简单的说,Ribbon是Net ...

  8. 分布式微服务技术之 Spring Cloud Netflix

    1 背景 Netflix 是全球十大视频网站中唯一收费站点,是美国互联网流媒体播放商,由于访问量巨大,转型为云计算公司. 由Netflix公司主持开发了一套代码框架和库Netflix OSS即open ...

  9. MySQL常见常用的SQL优化

    应尽量避免在where中使用!=或<>操作符.否则会进行全表查询 对于查询,避免全盘扫描,考虑在where或order by涉及到的列上建立索引 避免在where中进行null值判断,否则 ...

  10. Spring FactoryBean用法

    最近在看spring ioc源码,看到FactoryBean这个内容.这个和BeanFactory的区别 1. BeanFactory: 生成bean的工厂,是一个接口,定义了很多方法 2. Fact ...