算法题(二分查找)

一、题目

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--;
        }
    }
}
相关推荐
裕晟资质规划5 小时前
武器装备科研生产单位保密资质申请方法论:条件模型与流程拆解
人工智能·算法
en.en..7 小时前
C语言 标准输入 / 输出缓冲区
算法
吃好睡好便好8 小时前
查找函数的使用
学习·算法·matlab·生活·查找函数
学习星球8 小时前
单调栈——从“找下一个更大的“到柱状图中的最大矩形
数据库·c++·算法·leetcode·xcode
靠沿10 小时前
贪心算法专题(二)
算法·贪心算法
猎头南楼10 小时前
具身智能模型部署方向的能力要求与技术栈梳理
人工智能·深度学习·算法
啥都想学点的研究生11 小时前
一篇文章讲清楚:线性回归问题的求解——正规方程法
算法·机器学习·线性回归
青少儿编程课堂11 小时前
树状数组精讲:逆序对计数与离散化(附双语言解法)
算法·树状数组·离散化·信息学奥赛·逆序对
血小板要健康12 小时前
网格 dfs 与 FloodFill:从岛屿、区域到搜索路径
笔记·算法·leetcode·深度优先
VALENIAN瓦伦尼安教学设备12 小时前
设备状态检测振动分析实训台案例分析
大数据·数据库·人工智能·嵌入式硬件·算法