• 【手撕数据结构】二分查找(好多细节)


    🌈键盘敲烂,年薪30万🌈

    目录

    普通版本的二分查找:

    right只负责控制边界(少了两次比较):

    时间复杂度更稳定的版本:

    BSLeftmost:

    BSRightmost:


     

    普通版本的二分查找:

    • 🏸细节1:循环判定条件是left <= right
    • ⭐细节2:mid = (left + right ) >>> 1 原因见代码注释
    1. /***
    2. * 二分查找的实现 3个版本
    3. * 时间复杂度:O(longn)
    4. * 空间复杂度:O(1)
    5. *
    6. * 细节1:循环判定条件是left <= right
    7. * 细节2:mid计算要用 >>> 因为left + right 可能越界
    8. * 例如:right = Integer.MAX_INT-1 left = 0;
    9. * 第一轮计算没问题 假设mid < target
    10. * left = mid + 1; 这是后left+ right 就超出int的最大范围,变成负数
    11. * 原因很简单:java没有无符号数,最高位表示符号位,/ 运算是先将补码转原码 >>>位运算是直接再二进制上运算
    12. */
    13. public class Demo1 {
    14. public static void main(String[] args) {
    15. int[] nums = {1,4,6,8,15,76,145};
    16. int target = 145;
    17. int index1 = method1(nums, target);
    18. System.out.println(target + "索引为" + index1);
    19. System.out.println(target + "索引为" + index2);
    20. }
    21. private static int method1(int[] nums, int target) {
    22. int left = 0, right = nums.length-1;
    23. while(left <= right){
    24. //细节 用无符号右移运算符
    25. int mid = (left + right) >>> 1;
    26. if(nums[mid] > target){
    27. right = mid - 1;
    28. }else if (nums[mid] < target){
    29. left = mid + 1;
    30. }else{
    31. return mid;
    32. }
    33. }
    34. return -1;
    35. }
    36. }

    right只负责控制边界(少了两次比较):

    • 改动1:while条件是left < right
    • 改动2:right = nums.length
    1. public class Demo1 {
    2. public static void main(String[] args) {
    3. int[] nums = {1,4,6,8,15,76,145};
    4. int target = 145;
    5. int index2 = method2(nums, target);
    6. System.out.println(target + "索引为" + index2);
    7. }
    8. }
    9. private static int method2(int[] nums, int target) {
    10. int left = 0, right = nums.length; //right 只代表有边界,不参与比较
    11. while(left < right){
    12. int mid = (left + right) >>> 1;
    13. if(nums[mid] < target){
    14. left = mid + 1;
    15. }else if(nums[mid] > target){
    16. right = mid;
    17. }else {
    18. return mid;
    19. }
    20. }
    21. return -1;
    22. }

    时间复杂度更稳定的版本:

    • 细节:减少了if比较次数
    1. public class Demo1 {
    2. public static void main(String[] args) {
    3. int[] nums = {1,4,6,8,15,76,145};
    4. int target = 145;
    5. int index3 = method3(nums, target);
    6. System.out.println(target + "索引为" + index3);
    7. }
    8. }
    9. private static int method3(int[] nums, int target) {
    10. //这个最牛逼
    11. //减少循环内的比较次数
    12. int left = 0, right = nums.length;
    13. while(1 < right - left){
    14. int mid = (left + right) >>> 1;
    15. if(nums[mid] > target){
    16. right = mid;
    17. }else{
    18. left = mid;
    19. }
    20. }
    21. if(nums[left] == target){
    22. return left;
    23. }
    24. return -1;
    25. }

    BSLeftmost:

    1. /**
    2. *
    3. * 应用:求成绩排名 求前任
    4. */
    5. public class Leftmost {
    6. public static void main(String[] args) {
    7. int[] nums = {1,2,4,4,4,6,7};
    8. int target = 3;
    9. /***
    10. * params
    11. * return 找到了 - 返回靠左的下标
    12. * 没找到 - 返回>target的最靠左下标
    13. */
    14. int ans = BSLeftmost(nums, target);
    15. System.out.println(ans);
    16. }
    17. private static int BSLeftmost(int[] nums, int target) {
    18. int left = 0, right = nums.length -1;
    19. while(left <= right){
    20. int mid = (left+right) >>> 1;
    21. if(target > nums[mid]){
    22. left = mid + 1;
    23. } else{
    24. right = mid - 1;
    25. }
    26. }
    27. return left;
    28. }
    29. }

    BSRightmost:

    1. /**
    2. *
    3. * 求后任
    4. */
    5. public class Rightmost {
    6. public static void main(String[] args) {
    7. int[] nums = {1,2,4,4,4,6,7};
    8. int target = 3;
    9. /**
    10. * return 找到了返回下标
    11. * 没找到返回 <= targer的最靠右索引
    12. *
    13. */
    14. int ans = BSRightmost(nums, target);
    15. System.out.println(ans);
    16. }
    17. private static int BSRightmost(int[] nums, int target) {
    18. int left = 0, right = nums.length-1;
    19. while(left <= right){
    20. int mid = (left + right) >>> 1;
    21. if(target >= nums[mid]){
    22. left = mid + 1;
    23. }else {
    24. right = mid - 1;
    25. }
    26. }
    27. return left - 1;
    28. }
    29. }
  • 相关阅读:
    sparksql broadcast join opt
    React Native Webview 中input type=file accept=“image/*“ 无法调起相机问题排查及解决
    mysql(1)
    【计算机网络】数据链路层:使用广播信道的数据链路层(1)
    Spring Session 的原理
    立体车库管理系统
    tp5分页携带搜索参数
    Docker技术入门|L1简介及安装
    [spark]排序
    Java语言级别8不支持本地枚举和语言级别 ‘8‘ 不支持 内部类中的 static 声明
  • 原文地址:https://blog.csdn.net/Panci_/article/details/134452770