leetcode刷题(六)

二分搜索
  1. 找到某个值
  2. 确定左右边界
  3. 快速收缩搜索区间

爱吃香蕉的珂珂
在这里插入图片描述

思路
  • 吃香蕉的速度和时间存在函数关系
  • 寻找吃香蕉的最小速度
  • 寻找速度的左侧边界
 public long getHours(int[]piles,int x){
        long hours=0;
        for (int pile : piles) {
            hours += pile / x;
            if (pile % x > 0)
                hours++;
        }
        return hours;
    }
    /**
     * 爱吃香蕉的珂珂
     * @param piles
     * @param h
     * @return
     */
    public int minEatingSpeed(int[] piles, int h) {
        int left=1,right=1;
        for(int pile:piles){
            right=Math.max(right,pile);
        }
        while (left<=right){
            int mid=left+(right-left)/2;
            long hours=getHours(piles,mid);
            if(hours==h){
                right=mid-1;
            } else if (hours<h) {
                right=mid-1;
            } else if (hours>h) {
                left=mid+1;
            }
        }
        return left;
    }

在D天内送达包裹的能力
在这里插入图片描述

思路
  • 运输能力和运输时间存在函数关系
  • 根据函数关系由运输能力确定运输时间
  • 寻找最小运输能力,寻找最左侧边界
public int getDays(int[]weights,int x){
        int days=0;
        for(int i=0;i<weights.length;){
            int cap=x;
            while (i<weights.length){
                if(cap<weights[i]) break;
                else cap-=weights[i];
                i++;
            }
            days++;
        }
        return days;
    }
    public int shipWithinDays(int[] weights, int days) {
        int left=0,right=0;
        for(int weight:weights){
            left=Math.max(left,weight);
            right+=weight;
        }
        while (left<=right){
            int mid=left+(right-left)/2;
            int conveyDays=getDays(weights,mid);
            if(conveyDays==days){
                right=mid-1;
            } else if (conveyDays<days) {
                right=mid-1;
            } else if (conveyDays>days) {
                left=mid+1;
            }
        }
        return left;
    }

分割数组的最大值
在这里插入图片描述

思路
  • 转化问题:求在D天内运送包裹的能力
public int splitArray(int[] nums, int k) {
        return shipWithinDays(nums,k);
    }

搜索二维矩阵 I
在这里插入图片描述

思路
  • 将矩阵转化成数组a[k](0<=k<=m*n-1),
  • 矩阵元素matrix[i]lj]对应数组k=i*n+j(n是矩阵的列数)
  • 根据矩阵元素特点,转化成数组后,按照二分法搜索target
public int getMatrixValue(int[][]matrix,int index){
        int m=matrix.length,n=matrix[0].length;
        int i=index/n,j=index%n;
        return matrix[i][j];
    }

    /**
     * 搜索二维矩阵
     * @param matrix
     * @param target
     * @return
     */
public boolean searchMatrix(int[][] matrix, int target) {
    int m=matrix.length,n=matrix[0].length;
    int left=0,right=m*n-1;
    while (left<=right){
        int mid=left+(right-left)/2;
        int matrixValue=getMatrixValue(matrix,mid);
        if(matrixValue==target){
            return true;
        } else if (matrixValue<target) {
            left=mid+1;
        } else if (matrixValue>target) {
            right=mid-1;
        }
    }
    return false;
}

搜索二维矩阵 II
在这里插入图片描述

思路
  • 从矩阵右上角开始搜索数组元素
  • 如果矩阵元素比target大,则向左搜索;矩阵元素比target小,则向下搜索
public boolean searchMatrix2(int[][] matrix, int target) {
        int m=matrix.length,n=matrix[0].length;
        int i=0,j=n-1;
        while (i<m && j>=0){
            if(matrix[i][j]==target){
                return true;
            } else if (matrix[i][j]<target) {
                i++;
            } else if (matrix[i][j]>target) {
                j--;
            }
        }
        return false;
    }

找到k个最接近的元素
在这里插入图片描述

思路
  • 寻找最接近x的左侧边界p
  • 从p-1和p分别向数组两头寻找
// 找到K个最接近的元素
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
        int p= leftBound(arr,x);
        int left=p-1,right=p;
        LinkedList<Integer>res=new LinkedList<>();
        while (k>=0){
            if(left==-1){
                res.addLast(arr[right]);
                right++;
            } else if (right==arr.length) {
                res.addFirst(arr[left]);
                left--;
            } else if (arr[right]-x<x-arr[left]) {
                res.addLast(arr[right]);
                right++;
            } else {
                res.addFirst(arr[left]);
                left--;
            }
            k--;
        }
        return res;
    }

寻找峰值
在这里插入图片描述

思路
  • 采用二分搜索缩小区间,mid=left+(right-left)/2
  • 如果nums[mid]>nums[mid+1],则mid或者mid左侧存在峰值,如果nums[mid]<nums[mid+1],则mid右侧存在峰值
public int findPeakElement(int[] nums) {
        int left=0,right=nums.length-1;
        while (left<right){
            int mid=left+(right-left)/2;
            if(nums[mid]>nums[mid+1]){
                right=mid;
            }else if(nums[mid]<nums[mid+1]){
                left=mid+1;
            }
        }
        return left;
    }

山脉数组的峰顶索引
在这里插入图片描述

思路同上题
public int peakIndexInMountainArray(int[] arr) {
        int left=0,right=arr.length-1;
        while (left<right){
            int mid=left+(right-left)/2;
            if(arr[mid]>arr[mid+1]){
                right=mid;
            }else {
                left=mid+1;
            }
        }
        return left;
    }

统计目标成绩的出现次数
在这里插入图片描述

思路
  • 寻找目标成绩的左右边界索引left,right
  • 返回right-left+1
public int countTarget(int[] scores, int target) {
        int left = leftBound(scores,target),right = rightBound(scores,target);
        return right-left+1;
    }

点名
在这里插入图片描述

思路
  • 数组元素当前值等于索引值,则left=mid+1,如果数组元素当前值大于索引值,则right=mid-1
public int takeAttendance(int[] records) {
        int left=0,right=records.length-1;
        while (left<=right){
            int mid=left+(right-left)/2;
            if(records[mid]==mid){
                left=mid+1;
            }else if(records[mid]>mid){
                right=mid-1;
            }
        }
        return left;
    }

搜索旋转排序数组 I
在这里插入图片描述

思路
  • 如果nums[mid]>=nums[left],说明left…mid有序,此时进入这个有序区间搜索target,如果nums[left]<=target<nums[mid],则right=mid-1,否则left=mid+1
  • 如果nums[mid]<nums[left],说明mid…right有序,此时进入这个有序区间搜索target,如果nums[mid]<target<=nums[right],则left=mid+1,否则right=mid-1
public int search(int[] nums, int target) {
  int left=0,right=nums.length-1;
  while (left<=right){
      int mid=left+(right-left)/2;
      if(nums[mid]==target)
          return mid;
      if(nums[mid]>=nums[left]){
          if(target>=nums[left] && target<nums[mid]){
              right=mid-1;
          }else{
              left=mid+1;
          }
      }else {
          if(target>nums[mid] && target<=nums[right]){
              left=mid+1;
          }else {
              right=mid-1;
          }
      }
  }
  return -1;

搜索旋转排序数组 II
在这里插入图片描述

思路
  • 先跳过首尾相同的数组值
  • 按照上题思路解决
public boolean search(int[] nums, int target) {
        int left=0,right=nums.length-1;
        while (left<=right){
            while (left<right && nums[left]==nums[left+1]) left++;
            while (left<right && nums[right]==nums[right-1]) right--;
            int mid=left+(right-left)/2;
            if(nums[mid]==target){
                return true;
            }
            if(nums[mid]>=nums[left]){
                if(nums[mid]>target && target>=nums[left]){
                    right=mid-1;
                }else{
                    left=mid+1;
                }
            }else{
                if(nums[mid]<target && target<=nums[right]){
                    left=mid+1;
                }else{
                    right=mid-1;
                }
            }
        }
        return false;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值