LeetCode 求中位数 最优解( 那不是坐标虽然很像但是不是)

  public double findMediandArrays(int[] A ,int[] B){
        int m = A.length;
        int n = B.length;
        // 长度无所谓 但是必须知道 谁长谁短 这里涉及取值范围的问题
        if(m>n){
            // 尾递归不会栈堆积
            findMediandArrays(B,A);
        }
        // I的取值范围 最小为 0 最大值为 m
        int maxI = m,minI = 0;

        while (maxI>=minI){
            // 这个i不是坐标 是数组A切割点的位置与实际坐标有差异  一定要明确这点这也是困扰我很久的问题
            // 这里是将 数组A 一分为二  取到了A的中位数
            // 如果A为奇数  中位数为i  为偶数  中位数为 2分之 A[i]+A[i-1]
            // [1,2,3]  [1,2,3,4] 有兴趣自己代入一下
            int i = (maxI+minI)/2;
            // 这里是 数组B的切割点  这个切割点和 i 相关也就是 通过i 求 j
            // 因为中位数的位置不变 永远是(m+n)/2  所以求出了一个得知一个数组的切割位置就知道另一个的切割点
            // 这也是之前为什么要区分长短的原因 如果不区分长短  j 有可能为负数
            // 为什么加一呢是 奇偶合并  这里的合并不是 偶数合并为奇数
            // 而是奇数合并为偶数  也就是说总长度为偶数
            // 中位数永远左节点为  (m+n)/2 -1 右节点分为  (m+n)/2
            // 如果为奇数返回 做节点  如果为偶数返回左右节点的均值
            int j = (m+n+1)/2-i;
            // 移动切割点 这里要先确认结果 再想条件
            // 结果是 i 增加还是减小
            if (i!=m&&j!=0 && A[i]<B[j-1]){
                // i增加 j就会减小  j的最小值为0 i的最大值为 m
                // 所以 i增加要满足 i!=m  j!=0
                // 然后理解什么是中位数
                // 因为数组有序 所以 A[i]> A[i-1]
                // 因为数组有序 所以 B[j]> B[j-1]
                // 如果 A[i]<B[j-1] 则需要增加i 减小 j 使其接近中位数条件
                // 左边最大值 小于右面最小值
                // 所以 i要增大
                minI = minI + 1;
            }
            //这里是结果是i减小同理
            else  if (i!=0&&j!=n&&A[i-1]>B[j] ){
                maxI = maxI - 1;

            }// 当切割点不再变更  则 找到中位数切割位置 开始求值
            else {
                // 左边最大值
                int leftMax = 0;
                if (i == 0 ){
                    // 左边最大值 i 和j 是切割点不是坐标
                    leftMax = B[j-1];
                }else  if(j==0){
                    leftMax = A[i-1];
                }else {
                    leftMax = Math.max( B[j-1], A[i-1]);
                }
                //这个地方 不要用一个数组代入  想想中位数  因为 这个题解一切以中位数为基础的理论
                // 代入时要用两个有序数组  一个数组 无法代入
                // 如果是奇数  直接返回左边最大值就可以
                if (((m+n)&1)==1){
                    return leftMax;
                }
                //右边最小值 求职同理
                int rightMin = 0;
                if (i == m ){
                    // 左边最大值 i 和j 是切割点不是坐标
                    rightMin = B[j];
                }else  if(j==n){
                    rightMin = A[i];
                }else {
                    rightMin = Math.min(B[j], A[i]);
                }
                return (leftMax+rightMin)/2.0;

            }



        }

        return 0.0;
    }

 

posted @ 2021-09-13 16:39  OTeam  阅读(111)  评论(0)    收藏  举报