算法题(二分查找)

一、题目

1、寻找旋转排序数组中的最小值(LC 153)

2、寻找两个正序数字的中位数(LC 4)

二、题解

1、寻找旋转排序数组中的最小值(LC 153)

(1)分析

这道题的数组是经过旋转的有序数组,整体不再完全有序,但仍然保持了两段各自有序的特性,所以不能直接遍历,可以使用二分查找。利用二分不断缩小范围,最终定位到最小值的位置。

采用闭区间二分写法,先定义好左右两个指针,然后在循环中不断计算中间位置,核心判断逻辑是把中间元素和数组最后一个元素做比较。如果中间元素小于或等于末尾元素,就说明最小值一定出现在左半区间,这时候我就把右指针移到中间位置左边,继续向左寻找。如果中间元素大于末尾元素,就说明最小值在右半区间,于是把左指针移到中间位置右边,向右缩小范围。

只依靠中间元素和末尾元素的大小关系,就能一步步缩小搜索范围。当循环结束时,左指针指向的位置就是整个数组的最小值所在下标,直接返回对应元素即可。

(2)解答
java 复制代码
class Solution {
    public int findMin(int[] nums) {
        int n = nums.length;
        int left = 0;
        int right = n - 1;

        //二分查找 , 闭区间
        while(left <= right){
            int mid = (left + right)/2;
    
            if(nums[n - 1] >= nums[mid]){     //中间元素与末尾元素比较
                right = mid - 1;             //末尾元素大或者相等,去左边找
            }else{
                left = mid + 1;              //末尾元素小,去右边找
            }
        }
        return nums[left];
    }
}

2、寻找两个正序数字的中位数(LC 4)

(1)分析

这道题是二分查找里难度较高的一道题,题目最关键的要求就是时间复杂度必须控制在 O (log (m+n)) 以内,所以不能把两个数组合并后再查找,只能使用二分分割的思想来解决。需要抓住中位数的本质,就是把两个有序数组分成左右两部分,让左边的所有元素都小于右边的所有元素,再根据总长度的奇偶性计算结果。

可以先保证 nums1 是长度更短的那个数组,这样可以减少二分的次数。新建了两个数组,在原数组的最前面和最后面分别加上最小值和最大值,这样就不用在分割时特意判断数组越界的问题,写起来轻松很多。

接下来就是核心的分割,用两个变量分别表示两个数组的分割位置,保证左边所有元素的总个数接近总长度的一半。当满足左边最大元素小于右边最小元素时,就说明找到了正确的分割方式。如果两个数组总长度是奇数,中位数就是左边部分的最大值;如果是偶数,就取左边最大值和右边最小值的平均值。通过不断调整分割位置来满足条件,最终直接算出中位数。

(2)解答
java 复制代码
class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {

        //保证nums1是长度较短的数组
        if(nums1.length > nums2.length){
            int[] temp = nums1;
            nums1 = nums2;
            nums2 = temp;
        }

        int m = nums1.length;
        int n = nums2.length;
        int[] a = new int[m+2];
        int[] b = new int[n+2];
        a[0] = Integer.MIN_VALUE;
        b[0] = Integer.MIN_VALUE;
        a[m+1] = Integer.MAX_VALUE;
        b[n+1] = Integer.MAX_VALUE;

        //复制数组,避免繁琐的边界条件判断
        //nums1拷贝到a,nums2拷贝到b,同时在首尾分别加两个元素
        System.arraycopy(nums1, 0, a, 1, m);
        System.arraycopy(nums2, 0, b, 1, n);

        int i = 0;           //a[i] 分割后数组a左边最大的元素
        int j = (m+n+1)/2;   //b[j] 分割后数组b左边最大的元素
                             //i+j=(m+1+1)/2
        while(true){
            if(a[i] <= b[j + 1] && b[j] <= a[i+1]){  //符合条件的分割
            int max1 = Math.max(a[i], b[j]);     //左侧的最大值
            int min2 = Math.min(a[i+1], b[j+1]);  //右侧的最小值
            return (m+n)%2 > 0 ? max1 : (max1 + min2)/2.0;
            }
            i++;
            j--;
        }
    }
}
相关推荐
明志数科28 分钟前
4D时序标注技术详解:让机器人理解连续动作的数据基础
java·算法·机器人
KaMeidebaby1 小时前
卡梅德生物技术快报|原核表达系统工艺优化:包涵体重折叠 + 分子筛纯化实现功能 RBD 高效制备,附全参数配置
前端·人工智能·算法·数据挖掘·数据分析
无限码力1 小时前
携程0510笔试真题【单数组交换】
算法·携程笔试·携程笔试真题·携程0510笔试真题
BlockWay2 小时前
WEEX Labs 周度观察:微软-OpenAI 合作调整与AI 多云趋势
大数据·人工智能·算法·安全·microsoft
风筝在晴天搁浅2 小时前
快手 CodeTop LeetCode 224.基本计算器
数据结构·算法·leetcode
Smoothcloud润云2 小时前
5大功能精修,重构AI算力使用体验!
java·人工智能·windows·算法·重构·编辑器·sublime text
计算机安禾2 小时前
【算法分析与设计】第41篇:确定性与非确定性多项式时间:P与NP的形式化
算法
leo__5203 小时前
随机接入退避算法过程模拟实现
网络·算法
-To be number.wan3 小时前
算法日记 | STL- sort排序
c++·算法
玖釉-3 小时前
Vulkan 中 Shader 的 vert、frag、mesh、comp 全面解析:作用、关系、特点与工程实践
开发语言·c++·windows·算法·图形渲染