算法笔记(分治)

关于一些分治问题的算法题目笔记

1.两个有序数组求合并数组的中位数要求复杂度在O(log (m+n))

示例1:

输入:
[100, 300],[200]
返回值:
200.00000
说明:
合并体重 = [100,200,300] ,中位数 200

描述:典型的分治问题,求中位数可以视为求第(n+m)/2个数,每次对比k/2的大小,每次可以直接排除k/2个数。

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param weightsA int整型一维数组 
     * @param weightsB int整型一维数组 
     * @return double浮点型
     */
    public double findMedianSortedArrays (int[] weightsA, int[] weightsB) {
        // write code here
        int n=weightsA.length;
        int m=weightsB.length;
        return (getKth(weightsA,0,n-1,weightsB,0,m-1,(m+n+1)/2)+getKth(weightsA,0,n-1,weightsB,0,m-1,(m+n)/2+1))*0.5;
        
    }
    public int getKth(int[] nums1,int l1,int r1,int[] nums2,int l2,int r2,int k){
        //得到两个数组的剩余长度
        int len1=r1-l1+1;
        int len2=r2-l2+1;
        //让第一个数组为长度较小的数组
        if(len1>len2){
            getKth(nums2,l2,r2,nums1,l1,l2,k);
        }
        //当一个数组的值已经完全排除了
        //则要找的数就是剩余另一个数组的k+1
        if(len1==0){
            return nums2[l2+k-1];
        }
        if(k==1){
            return Math.min(nums1[l1],nums2[l2]);
        }
        //防止k/2的值大于剩余长度
        int i=l1+Math.min(k/2,len1)-1;
        int j=l2+k/2-1;
        //此时舍弃第一个数组的左半边,k此时也要减去舍弃的数量
        if(nums1[i]<=nums2[j]){
            return getKth(nums1,i+1,r1,nums2,l2,r2,k-(i-l1+1));
        }else{
            //否则舍弃第二个数组的左半边
            return getKth(nums1,l1,r1,nums2,j+1,r2,k-(j-l2+1));
        }
    }
}

2.三个有序数组求合并数组的中位数要求复杂度在O(log (m+n+p))

示例1:

输入:
[1,3],[2],[4,5]
返回值:
3.00000
说明:
合并数组 = [1,2,3,4,5] ,中位数 3

描述:上一题的升级版,可以以同样的思路,每次排除最小值中数组的数。

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param herd1 int整型一维数组 
     * @param herd2 int整型一维数组 
     * @param herd3 int整型一维数组 
     * @return double浮点型
     */
    public double findMedianSortedArray (int[] herd1, int[] herd2, int[] herd3) {
        // write code here
        int n1=herd1.length,n2=herd2.length,n3=herd3.length;
        int length=n1+n2+n3;
        int left = (length + 1) / 2;
        int right = (length + 2) / 2;
        return (getKth_3(herd1, 0, n1 - 1, herd2, 0, n2 - 1, herd3, 0, n3 - 1, left) + getKth_3(herd1, 0, n1 - 1, herd2, 0, n2 - 1, herd3, 0, n3 - 1, right)) * 0.5;
    }
    public int getKth_3(int[]herd1,int l1,int r1,int[]herd2,int l2,int r2,int[]herd3,int l3,int r3,int k){
        int len1=r1-l1+1;
        int len2=r2-l2+1;
        int len3=r3-l3+1;
        //让数组的长度从小到大排序
        if(len2<len1&&len2<=len3){
            return getKth_3(herd2,l2,r2,herd1,l1,r1,herd3,l3,r3,k);
        }
        if(len3<len1){
            return getKth_3(herd3,l3,r3,herd2,l2,r2,herd1,l1,r1,k);
        }
        //如果其中一个数组的值为0那么就是两个数组的分治问题了
        if(len1==0){
            return getKth(herd2, l2, r2, herd3, l3, r3, k);
        }
        //如果中位数为1就取其中最小的一个
        if (k == 1)
            return Math.min(herd1[l1], Math.min(herd2[l2], herd3[l3]));
        
        //和两个数组比较的思路一致,都是排除掉某个数组小的那部分每次排除k/2个
        int u = l1 + Math.min(len1, k / 2) - 1;
        int v = l2 + k / 2 - 1;
        int w = l3 + k / 2 - 1;
        int min_val = Math.min(herd1[u], Math.min(herd2[v], herd3[w]));
        if (min_val == herd1[u])
            return getKth_3(herd1, u + 1, r1, herd2, l2, r2, herd3, l3, r3, k - (u - l1 + 1));
        else if (min_val == herd2[v])
            return getKth_3(herd1, l1, r1, herd2, v + 1, r2, herd3, l3, r3, k - (v - l2 + 1));
        else
            return getKth_3(herd1, l1, r1, herd2, l2, r2, herd3, w + 1, r3, k - (w - l3 + 1));
    }
    int getKth(int[]herd1, int l1, int r1, int[]herd2, int l2, int r2, int k) {
        int len1 = r1 - l1 + 1;
        int len2 = r2 - l2 + 1;
        if (len1 > len2)
            return getKth(herd2, l2, r2, herd1, l1, r1, k);
        if (len1 == 0)
            return herd2[l2 + k - 1];
        if (k == 1)
            return Math.min(herd1[l1], herd2[l2]);
         
        int i = l1 + Math.min(len1, k / 2) - 1;
        int j = l2 + k / 2 - 1;
        if (herd1[i] <= herd2[j])
            return getKth(herd1, i + 1, r1, herd2, l2, r2, k - (i - l1 + 1));
        else
            return getKth(herd1, l1, r1, herd2, j + 1, r2, k - (j - l2 + 1));
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值