LeetCode算法练习top100:(8)二分法

package top100.二分法;

public class TOP {
    //35. 搜索插入位置
    public int searchInsert(int[] nums, int target) {
        int n = nums.length;
        int left = 0, right = n - 1;
        while (left <= right) { //当left==mid,搜索到最后一个数字
            int mid = left + (right - left) / 2;
            if (target > nums[mid]) {
                left = mid + 1;
            } else if (target < nums[mid]) {
                right = mid - 1;
            } else {
                return mid;
            }
        }
        return left;
    }

    //74. 搜索二维矩阵
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length;
        int n = matrix[0].length;
        int i = m - 1, j = 0;
        while (i >= 0 && j <= n - 1) {
            if (matrix[i][j] == target) {
                return true;
            } else if (matrix[i][j] > target) {
                i--;
            } else {
                j++;
            }
        }
        return false;
    }

    //34. 在排序数组中查找元素的第一个和最后一个位置
    public int[] searchRange(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        int[] res = new int[2];
        res[0] = -1;
        res[1] = -1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (target == nums[mid]) {
                left = mid - 1;
                //向左搜索第一个
                while (left >= 0 && nums[left] == nums[mid]) {
                    left--;
                }
                res[0] = left + 1;
                right = mid + 1;
                //向右搜索最后一个
                while (right <= nums.length - 1 && nums[right] == nums[mid]) {
                    right++;
                }
                res[1] = right - 1;
                break;
            } else if (target > nums[mid]) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return res;
    }

    //33. 搜索旋转排序数组
    //方法1:将数组分为两段升序数组,用二分法搜索
    //方法2:先判断是在左段还是在右端,在判断target在mid的左边还是右边
    public int search(int[] nums, int target) {
        if (nums.length == 0) return -1;
        int left  = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (target == nums[mid]) return mid;
            //mid在左段:left到mid肯定是升序
            if (nums[left] <= nums[mid]) {
                //target在left和mid之间
                if (target >= nums[left] && target < nums[mid]) {
                    right = mid - 1;
                } else {
                    left = mid + 1;
                }
            } else { //mid在右段:mid到right肯定是升序
                if (target > nums[mid] && target <= nums[right] ) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                }
            }
        }
        return -1;
    }

    //153. 寻找旋转排序数组中的最小值
    public int findMin(int[] nums) {
        int left = 0, right = nums.length - 1;
        while (left < right) { //目标在left和right之间
            int mid = left + (right - left) / 2;
            //只能比较mid和right的值才能确定min的位置
            if (nums[mid] > nums[right]) { //最小值肯定在右边
                left = mid + 1;
            } else if (nums[mid] < nums[right]) { //最小值可能是mid
                right = mid;
            }
        }
        return nums[left];
    }

    //4. 寻找两个正序数组的中位数
    //这题可以转化为,如何找到第k小的元素
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length, n = nums2.length;
        int total = m + n;
        if (total % 2 == 1) { //奇数,寻找第k小
            int k = total / 2 + 1;
            return findKth(nums1, nums2, k);
        } else { //寻找第k小和第k+1小
            int k = total / 2;
            int a = findKth(nums1, nums2, k);
            int b = findKth(nums1, nums2, k + 1);
            return (a + b) * 1.0 / 2;
        }
    }
    private int findKth(int[] nums1, int[] nums2, int k) {
        int m = nums1.length, n = nums2.length;
        int start1 = 0, start2 = 0;  //数组有效不能的起点索引
        while (true) {
            //处理特殊情况
            if (start1 == m) { //数组1越界,直接返回数组2的第k小数字
                return nums2[start2 + k - 1];
            }
            if (start2 == n) {
                return nums1[start1 + k - 1];
            }
            //寻找第1小
            if (k == 1) {
                return Math.min(nums1[start1], nums2[start2]);
            }
            //开始排除第k小前面的数据
            int half = k / 2;
            int index1 = Math.min(start1 + half, m) - 1;//如果half超出数组,用最后一位数字
            int index2 = Math.min(start2 + half, n) - 1;
            //比较nums1[k/2-1]和nums2[k/2-1]
            if (nums1[index1] > nums2[index2]) {
                k -= (index2 - start2 + 1); //先更新k
                start2 = index2 + 1; //忽略掉num2的half个元素
            } else {
                k -= (index1 - start1 + 1);
                start1 = index1 + 1;
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值