LeetCode - 二分查找

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int search(int[] nums, int target) {
        int n = nums.length;
        int left = 0;
        int right = n-1;
        while(left < right){
            int mid = left + (right - left) / 2;
            if(nums[mid] < target)
               left = mid + 1;
            else
              right = mid;
        }
        if(nums[left] == target)
           return left;
        else
           return -1;
    }
}

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int[] searchRange(int[] nums, int target) {
         int n = nums.length;
         if(n == 0)
           return new int[]{-1,-1};
         int[] ans = new int[2];
         int left = 0;
         int right = n-1;
         //查找第一个位置
         while(left < right){
             int mid = left + (right-left) / 2;
             if(nums[mid] < target)
                left = mid + 1;
             else
               right = mid;
         }
         if(nums[left] != target)
            return new int[]{-1,-1};
        ans[0] = left;
         right = n-1;
         //查找最后一个位置
         while(left < right){
             int mid = left + (right-left+1) / 2;
             if(nums[mid] >  target)
                right = mid - 1;
             else
               left = mid;
         }
         ans[1] = left;
         return ans;
    }
}

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int search(int[] nums, int target) {
       int n = nums.length;
        if(n == 0)
           return 0;
         int[] ans = new int[2];
         int left = 0;
         int right = n-1;
         //查找第一个位置
         while(left < right){
             int mid = left + (right-left) / 2;
             if(nums[mid] < target)
                left = mid + 1;
             else
               right = mid;
         }
         if(nums[left] != target)
            return 0;
        ans[0] = left;
         right = n-1;
         //查找最后一个位置
         while(left < right){
             int mid = left + (right-left+1) / 2;
             if(nums[mid] >  target)
                right = mid - 1;
             else
               left = mid;
         }
         ans[1] = left;
         return ans[1]-ans[0]+1;
    }
}

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int searchInsert(int[] nums, int target) {
         int n = nums.length;
         int left = 0;
         int right = n-1;
         while(left < right){
             int mid = left + (right-left+1) / 2;
             if(nums[mid] > target)
                right = mid -1;
             else
                left = mid;
         }
         if(nums[left] >= target)
           return left;
         else
          return left + 1;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解法一
O(m+n)

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length;
        int n = matrix[0].length;
        int i = 0;
        int j = n-1;
        while(j >=0 && i < m){
            if(matrix[i][j] > target)
              j -= 1;
            else if(matrix[i][j] < target)
              i += 1;
            else
              return true;
        }
        return false;
    }
}

解法二
o(mlogn)

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
         int m = matrix.length;
         int n = matrix[0].length;
         for(int i = 0; i < m;i++){
             int left = 0;
             int right = n-1;
             while(left < right){
                 int mid = left + (right-left) / 2;
                 if(matrix[i][mid] < target)
                     left = mid+1;
                  else
                    right = mid;
                 
             }
             if(matrix[i][left] == target)
                return true;
         }
         return false;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解法一
O(logm+logn)=O(logmn)

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length;
        int n = matrix[0].length;
        int left = 0;
        int right = m-1;
        while(left < right){
            int mid = left + (right-left+1) / 2;
            if(matrix[mid][0] > target)
                right = mid-1;
            else
              left = mid;
        }
        //System.out.println(matrix[left][0]);
        if(matrix[left][0] > target)
          return false;
        int index = left;
        System.out.println(index);
        left = 0;
        right = n-1;
        while(left < right){
            int mid = left + (right-left) / 2;
            if(matrix[index][mid] < target)
                left = mid + 1;
            else
               right = mid;
        }
        if(matrix[index][left] == target)
           return true;
        else
           return false;
    }
}

解法二

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
         int m = matrix.length;
        int n = matrix[0].length;
        int left = 0;
        int right = m*n-1;
        while(left < right){
            int mid = left + (right-left+1) / 2;
            if(matrix[mid/n][mid%n] > target)
              right = mid-1;
            else
               left = mid;
        }
        if(matrix[left/n][left%n] == target)
           return true;
        else
           return false;
    }
}

解法三
O(m+n)

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
         int m = matrix.length;
        int n = matrix[0].length;
        int i = 0;
        int j = n-1;
        while(j >=0 && i < m){
            if(matrix[i][j] > target)
              j -= 1;
            else if(matrix[i][j] < target)
              i += 1;
            else
              return true;
        }
        return false;
    }
}

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int maxEnvelopes(int[][] envelopes) {
       int n = envelopes.length;
       //nlogn
       Arrays.sort(envelopes,new Comparator<int[]>(){
           // 按第一维升序排序 如果第一维相同 按第二维降序排序
           public int compare(int[] e1,int[] e2){
               if(e1[0] != e2[0])
                  return e1[0] - e2[0];
                else
                return e2[1] - e1[1];
           }
       });
       int[] dp = new int[n];
       dp[0] = envelopes[0][1];
       int len = 1;
       for(int i = 1; i < n;i++){
           int left = 0;
           int right = len-1;
           while(left < right){
               int mid = left + (right-left) / 2;
               if(dp[mid] < envelopes[i][1])
                  left = mid+1;
               else
                 right = mid;
           }
           if(dp[left] >= envelopes[i][1])
             dp[left] = envelopes[i][1];
           else{
             dp[len] = envelopes[i][1];
             len += 1;
           }
       }
       return len;
    }
}

在这里插入图片描述
在这里插入图片描述

二分查找

在这里插入图片描述

class Solution {
    public int numMatchingSubseq(String s, String[] words) {
       int n = words.length;
       int m = s.length();
       //用map记录s中每个字符出现的位置 
       //'c':list list记录了字符'c'出现的位置 list递增排序
       ArrayList<Integer>[] count = new ArrayList[26];
       for(int i = 0; i < m;i++){
           char ch = s.charAt(i);
           int idx = ch-'a';
           if(count[idx] == null){
               count[idx] = new ArrayList<>();
           }
           count[idx].add(i);
       }
       int ans = 0;
       //遍历words 判断每个word 是否是s的子序列
       for(int i = 0; i < n; i++){
           String word = words[i];
           char ch = word.charAt(0);
           //第一个字符就不存在
           int idx = ch-'a';
           if(count[idx] == null)
              continue;
           int index = count[idx].get(0)+1;
           boolean flag = true;
           for(int j = 1;j < word.length() && flag;j++){
              char chj = word.charAt(j);
              idx = chj - 'a';
              ArrayList<Integer> al = count[idx];
              //有字符不存在
              if(al == null){
                 flag = false;
                 break;
              }
              //找出al中>= index 的最小值
              int left = 0;
              int right = al.size()-1;
              while(left < right){
                  int mid = left + (right-left) / 2;
                  if(al.get(mid) < index)
                     left = mid+1;
                  else
                     right = mid;
              }
              if(al.get(left)< index)
                flag = false;
              else{
                  index = al.get(left) + 1;
              }
           }
           if(flag == true)
              ans += 1;
       }
       return ans;
    }
}

哈希map略慢 但耗内存小
在这里插入图片描述

class Solution {
    public int numMatchingSubseq(String s, String[] words) {
       int n = words.length;
       int m = s.length();
       //用map记录s中每个字符出现的位置 
       //'c':list list记录了字符'c'出现的位置 list递增排序
       Map<Character,ArrayList<Integer>> count = new HashMap<>();
       for(int i = 0; i < m;i++){
           char ch = s.charAt(i);
        if(count.get(ch) == null)
          count.put(ch,new ArrayList<>());
        count.get(ch).add(i);
       }
       int ans = 0;
       //遍历words 判断每个word 是否是s的子序列
       for(int i = 0; i < n; i++){
           String word = words[i];
           char ch = word.charAt(0);
           //第一个字符就不存在
           if(count.get(ch) == null)
              continue;
           int index = count.get(ch).get(0)+1;
           boolean flag = true;
           for(int j = 1;j < word.length() && flag;j++){
              char chj = word.charAt(j);
              ArrayList<Integer> al = count.get(chj);
              //有字符不存在
              if(al == null){
                 flag = false;
                 break;
              }
              //找出al中>= index 的最小值
              int left = 0;
              int right = al.size()-1;
              while(left < right){
                  int mid = left + (right-left) / 2;
                  if(al.get(mid) < index)
                     left = mid+1;
                  else
                     right = mid;
              }
              if(al.get(left)< index)
                flag = false;
              else{
                  index = al.get(left) + 1;
              }
           }
           if(flag == true)
              ans += 1;
       }
       return ans;
    }
}

指向下一个字母的指针

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int numMatchingSubseq(String s, String[] words) {
        int m = s.length();
        int n = words.length;
        Map<Character,ArrayList<String>> count = new HashMap<>();
        for(int i = 0; i < n;i++){
            char ch = words[i].charAt(0);
            if(count.get(ch) == null)
               count.put(ch,new ArrayList<>());
            count.get(ch).add(words[i]);
        }
        int ans = 0;
        for(int i = 0; i < m;i++){
            char ch = s.charAt(i);
            ArrayList<String> list = count.get(ch);
            if(list == null)
               continue;
            count.remove(ch);
            for(int j = 0; j < list.size();j++){
                String word = list.get(j);
                if(word.length() == 1){
                    ans += 1;
                    continue;
                }
                word = word.substring(1,word.length());
                char chj = word.charAt(0);
                if(count.get(chj) == null)
                   count.put(chj,new ArrayList<>());
                count.get(chj).add(word);  
            }
        }
        return ans;
    }
}

在这里插入图片描述
在这里插入图片描述

class Solution {
    public List<Integer> findClosestElements(int[] arr, int k, int x) {
          int n = arr.length;
          int left = 0;
          int right = n-1;
          int mid = 0;
          //寻找小于等于x的最大数
          while(left < right){
              mid = left +(right-left+1) / 2;
              if(arr[mid] > x)
                right = mid-1;
              else
                left = mid;
          }
          //如果arr[left] == x 那就以arr[left]为中点 否则以 arr[left] 和 arr[left+1]中与x较近的一个为中点
          if(left+1< n && Math.abs(arr[left+1]-x) < Math.abs(arr[left]-x))
             mid = left+1;
          else
             mid = left;
         //双指针寻找k个数
          if(mid == n-1){//中点在末尾
              right = n-1;
              left = n-1-k+1;
          }else if(mid == 0){//中点在头
              left = 0;
              right = k-1;
          }else{
              left = mid-1;
              right = mid + 1;
              while(left >= 0 && right < n && (right-left-1) < k){
                  if(Math.abs(arr[right] - x) < Math.abs(arr[left]-x))
                     right += 1;
                  else
                     left -= 1;
              }
              left = left+1;
              right = right-1;
              // 没有足够k个数 left >= 0 || right < n 跳出循环
              if(right-left+1 < k){
                  int dif =  k-(right-left+1);
                  if(left == 0){
                    right += dif;
                  }else{
                      left -= dif;
                  }
              }
          }
          List<Integer> ans = new ArrayList<>();
          for(int i = left; i <= right;i++){
              ans.add(arr[i]);
          }
          return ans;
           
    }
}

在这里插入图片描述
在这里插入图片描述

前置知识

在这里插入图片描述
在这里插入图片描述
讲的比较好的题解

class Solution {
    public int trailingZeroes(int n) {
       int ans = 0;
       while(n>0){
           ans += n/5;
           n = n/ 5;
       }
       return ans;
    }
}
class Solution {
    public int preimageSizeFZF(int k) {
         long left = 0L;
         long right = 5L * k;
         long mid = 0L;
         long sum = 0L;
         long n = 0L;
         while(left < right){
             mid = left + (right - left + 1) / 2;
             n = mid;
             sum = 0L;
             while(n > 0){
                 sum += n / 5;
                 n = n / 5;
             }
             if(sum > k)
                right = mid -1;
             else
               left = mid;
         }
         n = left;
         sum = 0L;
         while(n > 0){
            sum += n / 5;
            n = n / 5;
        }
        if(sum == k)
           return 5;
        else
           return 0;
    }
}

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        //数组长度
        int n = arr.length;
        int left = 1;
        int right = n-2;
        while(left < right){
            int mid = left + (right - left + 1) / 2;
            if(arr[mid] < arr[mid-1] && arr[mid] > arr[mid+1])
               right = mid-1;
            else
              left = mid;
        }
        return left;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
    public int shipWithinDays(int[] weights, int days) {
        //船的最小载重为单个包裹重量的最大值
        int left = 1;
         // 船的最大载重为所有包裹的总和
        int right = 0;
        for(int i = 0; i < weights.length;i++){
            right += weights[i];
            left = Math.max(weights[i],left);
        }
        while(left < right){
            int mid = left + (right - left) / 2;
            if(isOK(weights,days,mid))
               right = mid;
            else
              left = mid + 1;

        }
        return left;
    }
    public boolean isOK(int[] weights,int days,int capacity){
        int cur = 0;
        int d = 1;
        for(int i = 0; i < weights.length;i++){
            //判断能不能装上船呀
            //可以装上船
            if(cur + weights[i] <= capacity)
               cur += weights[i];
            //不能装上船
            else{
                cur = weights[i];
                d += 1;
            }
        }
        if(d <= days)
           return true;
        else
          return false;
    }
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

class Solution {
    public int splitArray(int[] nums, int k) {
       //子数组之和的最大值 的 最小值是nums中元素的最大值
       int left = 0;
       //子数组的之和的最大值 的最大值是nums中所有元素相加
       int right = 0;
       for(int i = 0; i < nums.length;i++){
           right += nums[i];
           left = Math.max(nums[i],left);
       }      
       while(left < right){
           int mid = left + (right - left) / 2;
           int group = splitNum(nums,mid);
           //组太多了 说明max_value 设小了
           if(group > k)
              left = mid + 1;
           else
              right = mid;
       }
       return left;
    }
    public int splitNum(int[] nums,int max_value){
        int sum = 0;
        int group = 1;
        for(int i = 0; i < nums.length; i++){
              if(sum + nums[i] <= max_value)
                 sum += nums[i];
              else{
                  sum = nums[i];
                  group += 1;
              }
        }
        return group;
    }
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

class Solution {
    public int minEatingSpeed(int[] piles, int h) {
        //速度最小值是1
        int left = 1;
        //速度最大值是piles中元素最大值
        int right = 1;
        for(int i = 0; i < piles.length;i++){
            right = Math.max(right,piles[i]);
        }
        while(left < right){
            int mid = left + (right - left) / 2;
            int hour = getHour(piles,mid);
            //速度小了
            if(hour > h)
              left = mid + 1;
            else
              right = mid;
        }
        return left;

    }
    public int getHour(int[] piles,int speed){
        int hour = 0;
        for(int i =0 ; i < piles.length;i++){
            hour += piles[i] % speed == 0 ? piles[i] / speed : (piles[i] / speed) +1 ;
        }
        return hour;
    }
}

丑数系列
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
    public boolean isUgly(int n) {
        if (n <= 0) {
            return false;
        }
        int[] factors = {2, 3, 5};
        for (int factor : factors) {
            while (n % factor == 0) {
                n /= factor;
            }
        }
        return n == 1;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
优先队列 一个丑数 * 2 *3 * 5以后也是丑数

class Solution {
    public int nthUglyNumber(int n) {
       Set<Long> set = new HashSet<>();
       //默认是小顶堆
       PriorityQueue<Long> heap = new  PriorityQueue<Long>();
       long[] factors = {2L,3L,5L};
       set.add(1L);
       heap.offer(1L);
       int sum = 0;
       int ans = 0;
       while(sum < n){
           ans = (int)((long)heap.poll());
           sum += 1;
           for(int i = 0; i < factors.length;i++){
               if(!set.contains(ans * factors[i])){
                   set.add(ans * factors[i]);
                   heap.offer(ans * factors[i]);
               }
           }
       }
       return ans;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
二分查找 + 容斥定理 + 辗转相除法
在这里插入图片描述

class Solution {
    public int nthUglyNumber(int n, int a, int b, int c) {
       //[1-nums] 之间
       long left = 1;
       long right = 2000000000;
       while(left < right){
           long mid = left + (right - left) / 2;
           if(getUglyNum(mid,a,b,c) < n)
              left = mid + 1;
            else
              right = mid;
       }
       return (int)(left);
    }
    //最小公倍数
    private long lcm(long a,long b){
       return (a * b) / gcd(a,b);
    }
    //最大公约数
    //两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数
    public long gcd(long a,long b){
         if(a < b)
           return gcd(b,a);
         if(b == 0)
            return a;
         return gcd(b,a % b);
    }
    public long getUglyNum(long n,long a,long b,long c){
        long A = n / a;
        long B = n / b;
        long C = n / c;
        long AB = n / lcm(a,b);
        long BC = n / lcm(b,c);
        long AC = n / lcm(a,c);
        long ABC = n / lcm(lcm(a,b),c);
        return A + B + C -AB - BC - AC + ABC;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
    public int nthSuperUglyNumber(int n, int[] primes) {
        int plen = primes.length;
        //存放前n个丑数
        long[] dp = new long[n];
        dp[0] = 1;
        //当前最小丑数是dp[0]
        //pointers都指向下标0
        int[] pointers = new int[plen];
        for(int i = 1; i < n; i++){
            dp[i] = Long.MAX_VALUE;
            for(int j = 0; j < plen;j++){
                dp[i] = Math.min(dp[i],dp[pointers[j]]* (long)(primes[j]));
            }
            for(int j = 0; j < plen;j++){
                if(dp[i] == dp[pointers[j]]* (long)(primes[j]))
                    pointers[j] += 1;
            }
        }
        return (int)(dp[n-1]);
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
    public int missingNumber(int[] nums) {
      // 重点 找到第一个不满足nums[index] = index的情况 缺失值就是 nums[index] -1 
      int n = nums.length;
      int left = 0;
      int right = n-1;
      while(left < right){
          int mid = left + (right - left) / 2;
          if(nums[mid] == mid){
              left = mid + 1;
          }
          else{
              right = mid;
          }
      }
      //left 一直向右移发现一直满足 nums[left] = left 缺失值在最末尾 
      if(nums[left] == left)
        return left + 1;
      //第一个不满足nums[index] = index 的情况 缺失值就是 nums[index] -1 
      else
        return nums[left] - 1;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值