减治法实现求两个序列的中位数

本文讲解如何使用递归方法解决两个已排序数组的中位数查找问题。作者首先介绍了问题背景,然后详细剖析了错误代码,通过调试发现并修复了问题,最后分析了时间复杂度。关键在于理解如何缩小查找范围,直至只剩一个数作为中位数。
摘要由CSDN通过智能技术生成

问题描述

设X[ 0 : n - 1]和Y[ 0 : n – 1 ]为两个数组,每个数组中含有n个已排好序的数。找出X和Y的2n个数的中位数。

数据输入

由文件input.txt提供输入数据。文件的第1行中有1个正整数nn<=200),表示每个数组有n个数。接下来的两行分别是X,Y数组的元素。

结果输出

          程序运行结束时,将计算出的中位数输出到文件output.txt中。

输入文件示例

输出文件示例

input.txt

output.txt

3

5 15 18

3 14 21

14

实现提示

   比较两个序列的中位数大小,如果两个数相等,则该数为整个2n个数据的中位数,否则通过比较,分别减少两个序列的查找范围,确定查找的起止位置,继续查找。

思路

   比较这两个序列的中位数大小,假定第一列的中位数为a,第二列的中位数为b。比较a和b:

(1)a<b:说明第一序列a前面的数太小了,第二序列b后的数太大了;

(2)a==b:两序列的中位数相等,不管其他数怎么排列,中位数一定是该数;

(3)a>b:说明第一序列a后面的数太大了,第二数列b前面的数太小了。

不断缩减两个序列的长度,直到两个序列都只剩下一个数时,由题意,选择的不是两数的平均值,而是较小的数。

代码实现

第一次的错误代码:

public class 寻找中位数 {
    public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.print("请输入各数组包含的元素个数:");
		int n = sc.nextInt();
		int[] nums1 = new int[n];
		int[] nums2 = new int[n];
		System.out.println("请输入第一组元素:");
		for(int i=0;i<n;i++) {
			nums1[i]=sc.nextInt();
		}
		System.out.println("请输入第二组元素:");
		for(int i=0;i<n;i++) {
			nums2[i]=sc.nextInt();
		}
		sc.close();
		System.out.println("这两组元素的中位数为:"+getNum(nums1,0,n-1,nums2,0,n-1));
	}
    private static int getNum(int[] nums1,int left1,int right1,int[] nums2,int left2,int right2) {
    	int mid1=(left1+right1)/2;
    	int mid2=(left2+right2)/2;
    	if(left1==right1&&left2==right2) {
    		return Math.min(nums1[mid1], nums2[mid2]);
    	}
    	if(nums1[mid1]==nums2[mid2]) {
    		return nums1[mid1];
    	}else {
    		if(nums1[mid1]>nums2[mid2]) {
    			return getNum(nums1,left1,mid1,nums2,mid2,right2);
    		}else {
    			return getNum(nums1,mid1,right1,nums2,left2,mid2);
    		}
    	}
    	
    }
}

 调试:输入示例的数据后,初始情况如下:

不断调试,发现程序停留在:

找到原因: nums1数组经过一次比较后,left=0,right=1,mid=0,在经历第二次比较时,nums1[mid1](5)<nums2[mid2](14),但是由于nums1的mid前面并无数字了,而我又没有对此做处理,导致nums1一直停留在那里。

 修改:

import java.util.Scanner;

public class 寻找中位数 {
    public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.print("请输入各数组包含的元素个数:");
		int n = sc.nextInt();
		int[] nums1 = new int[n];
		int[] nums2 = new int[n];
		System.out.println("请输入第一组元素:");
		for(int i=0;i<n;i++) {
			nums1[i]=sc.nextInt();
		}
		System.out.println("请输入第二组元素:");
		for(int i=0;i<n;i++) {
			nums2[i]=sc.nextInt();
		}
		sc.close();
		System.out.println("这两组元素的中位数为:"+getNum(nums1,0,n-1,nums2,0,n-1));
	}
    private static int getNum(int[] nums1,int left1,int right1,int[] nums2,int left2,int right2) {
    	int mid1=(left1+right1)/2;
    	int mid2=(left2+right2)/2;
    	if(left1==right1&&left2==right2) {
    		return Math.min(nums1[mid1], nums2[mid2]);
    	}
    	if(nums1[mid1]==nums2[mid2]) {
    		return nums1[mid1];
    	}else {
    		if(nums1[mid1]>nums2[mid2]) {
    			return getNum(nums1,left1,mid1==right1?mid1-1:mid1,nums2,mid2==left2?mid2+1:mid2,right2);
    		}else {
    			return getNum(nums1,mid1==left1?mid1+1:mid1,right1,nums2,left2,mid2==right2?right2-1:mid2);
    		}
    	}
    	
    }
}

代码试验成功。

分析

每个序列的比较数都减半,且该分治没有组合子问题的解的过程,可知递归方程:

T(n)=T(n/2)

时间复杂度为O(logn)

新手写文章,如有误,敬请斧正。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值