zoukankan      html  css  js  c++  java
  • 算法:二分法


    二分法题型:

    (常规的三种主流写法:(<=)对应mid+1,mid-1;    (<)对应mid+1,mid;  (+1<)对应mid,mid;) 

    (无证明推测:一般找具体tar的在循环内部返回的才会用<=(指的是返回全部情况 而不是个别情况);因为用<=循环后lo!=hi了,而是lo=hi+1;

    所以不是内部返回的一般都用(lo<hi),对应的下面指针变化必须要有一个是+1/-1的,不能两个都是mid;

    mid偏左,则lo=mid+1;mid偏右,则hi=mid-1;) 

    1.Classical Binary Search:http://www.lintcode.com/en/problem/classical-binary-search/

    经典二分查找:

    解法:(循环条件<=; 指针变化lo=mid+1 /hi=mid-1;)(PS: mid=lo+((hi - lo)>>1 防止溢出+移位替代除法提升速度)

    public class Solution {
    
        public int findPosition(int[] nums, int target) {
    
            int lo = 0;
            int hi = nums.length - 1;
            while (lo <= hi) {
                int mid = lo + ((hi - lo) >> 1);
                if (nums[mid] == target) return mid;
                else if (nums[mid] < target) lo = mid + 1;
                else hi = mid - 1;
            }
            return -1;
    
        }
    
    }
    View Code
    public class Solution {
    
        public int findPosition(int[] nums, int target) {
    
            int lo = 0;
            int hi = nums.length - 1;
            while (lo < hi) {
                int mid = lo + ((hi - lo) >> 1);
                if (nums[mid] == target) return mid;
                else if (nums[mid] > target) hi = mid;
                else lo = mid + 1;
            }
            return -1;
        }
    }
    View Code

    2.First Position of Target:http://www.lintcode.com/en/problem/first-position-of-target/

    查找第一个目标数:

    解法1:(在while循环内,使用一个rst记录=tar的mid值;while(lo<=hi),如果>=tar,则hi=mid-1,否则lo=mid+1) 

    (具体过程分析:与常规的二分查找相同,不过是当=tar的时候,1.rst记录值,防止此时的mid已经是最左了;2.hi=mid-1继续查找左边的数;)

    class Solution {
    
        public int binarySearch(int[] nums, int target) {
            if (nums == null || nums.length == 0) {
                return -1;
            }
            
            int lo = 0, hi = nums.length - 1;
            int rst = -1;
            while (lo <= hi) {
                int mid = lo + ((hi - lo) >> 1);
                if (nums[mid] >= target) {
                    hi = mid - 1;
                } else {
                    lo = mid + 1;
                }
                if (nums[mid] == target) rst = mid;
            }
            return rst;
    
        }
    }
    View Code

    解法2:(while(lo<hi); 如果=tar,则hi=mid,大于则mid-1,小于则mid+1;最后循环外判断lo=tar?lo;)

    (注意:一定是lo<hi而不能是<=;不然错误!例如[1,4],1;  1-lo/mid, 4-hi; 1-lo/mid/hi;死循环!即)

    class Solution {
    
        public int binarySearch(int[] nums, int target) {
            if (nums == null || nums.length == 0) {
                return -1;
            }
            
            int lo = 0, hi = nums.length - 1;
            while (lo < hi) {
                int mid = lo + ((hi - lo) >> 1);
                if (nums[mid] == target) {
                    hi = mid;
                } else if (nums[mid] < target) {
                    lo = mid + 1;
                } else {
                    hi = mid - 1;
                }
            }
            if (nums[lo] == target) {
                return lo;
            }
            
            return -1;
        }
    }
    View Code

    (或者合并=和>) (使用这种解法

    循环条件(lo<hi); mid=lo+((hi-lo)>>1); 判断if(>=)hi=mid;  否则lo=mid+1; 循环外判断[lo]=tar;

    class Solution {
    
        public int binarySearch(int[] nums, int target) {
            if (nums == null || nums.length == 0) {
                return -1;
            }
            
            int lo = 0, hi = nums.length - 1;
            while (lo < hi) {
                int mid = lo + ((hi - lo) >> 1);
                if (nums[mid] < target) {
                    lo = mid + 1;
                } else {
                    hi = mid;
                }
            }
            if (nums[lo] == target) {
                return lo;
            }
            
            return -1;
        }
    }
    View Code

    解法3:(九章模板;(+1<) + mid + 分别判断lo和hi;)

    class Solution {
    
        public int binarySearch(int[] nums, int target) {
            if (nums == null || nums.length == 0) {
                return -1;
            }
            
            int start = 0, end = nums.length - 1;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (nums[mid] == target) {
                    end = mid;
                } else if (nums[mid] < target) {
                    start = mid;
                    // or start = mid + 1
                } else {
                    end = mid;
                    // or end = mid - 1
                }
            }
            
            if (nums[start] == target) {
                return start;
            }
            if (nums[end] == target) {
                return end;
            }
            return -1;
        }
    }
    View Code

    3.Find Last Position of Targethttp://www.lintcode.com/zh-cn/problem/last-position-of-target/

    查找最后一个目标数: 

    解法1:(与First解法1相同)

    class Solution {
    
        public int binarySearch(int[] nums, int target) {
            if (nums == null || nums.length == 0) {
                return -1;
            }
            
            int lo = 0, hi = nums.length - 1;
            int rst = -1;
            while (lo <= hi) {
                int mid = lo + ((hi - lo) >> 1);
                if (nums[mid] <= target) {
                    lo = mid + 1;
                } else {
                    hi = mid - 1;
                }
                if (nums[mid] == target) rst = mid;
            }
            return rst;
    
        }
    }
    View Code

    解法2:

    (循环条件(lo<hi); mid=lo+((hi-lo+1)>>1); 判断if(<=)lo=mid;  否则hi=mid-1; 循环外判断[hi]=tar;)

    class Solution {
    
        public int binarySearch(int[] nums, int target) {
            if (nums == null || nums.length == 0) {
                return -1;
            }
            
            int lo = 0, hi = nums.length - 1;
            while (lo < hi) {
                int mid = lo + ((hi - lo + 1) >> 1);
                if (nums[mid] <= target) {
                    lo = mid ;
                } else {
                    hi = mid - 1;
                }
            }
            if (nums[hi] == target) {
                return hi;
            }
            
            return -1;
        }
    }
    View Code

    4.Search for a Range:http://www.lintcode.com/en/problem/search-for-a-range/

    搜索区间(找出第一个和最后一个tar的位置):

    解法1:(即整合First和Last的解法即可;)

     1 public class Solution {
     2     public int[] searchRange(int[] A, int target) {
     3         int[] rst = new int[]{-1,-1};
     4         if (A.length == 0) {
     5             return rst;
     6         }
     7         int lo = 0, hi = A.length - 1;
     8         while (lo <= hi) {
     9             int mid = lo + (hi - lo) / 2;
    10             if (A[mid] >= target) {
    11                 hi = mid - 1;
    12             } else {
    13                 lo = mid + 1;
    14             }
    15             if (A[mid] == target) rst[0] = mid;
    16         }
    17         if (rst[0] == -1) {
    18             return rst;
    19         }
    20         lo = rst[0]; 
    21         hi = A.length - 1;
    22         while (lo <= hi) {
    23             int mid = lo + (hi - lo) / 2;
    24             if (A[mid] <= target) {
    25                 lo = mid + 1;
    26             } else {
    27                 hi = mid - 1;
    28             }
    29             if (A[mid] == target) rst[1] = mid;
    30         }
    31         return rst;
    32     }
    33 }
    View Code

    解法2:(//First: lo+(hi-lo)/2; while(<); (>=)mid; mid+1; if(lo) //Last : lo+(hi-lo+1)/2; while(<=); (<=)mid; mid-1; if(hi);)

    (注意:第二个一定要是lo+(hi-lo+1)/2;不然mid偏左则会死循环;例如[5,5],5;)

    public class Solution {
        public int[] searchRange(int[] A, int target) {
            int[] rst = new int[]{-1,-1};
            if (A.length == 0) {
                return rst;
            }
            int lo = 0, hi = A.length - 1;
            while (lo < hi) {
                int mid = lo + (hi - lo) / 2;
                if (A[mid] >= target) {
                    hi = mid;
                } else {
                    lo = mid + 1;
                }
            }
            if (A[lo] == target) rst[0] = lo;
            else return rst;
            
    
            hi = A.length - 1;
            while (lo < hi) {
                int mid = lo + (hi - lo + 1)/ 2;
                if (A[mid] <= target) {
                    lo = mid;
                } else {
                    hi = mid - 1;
                }
            }
            if (A[hi] == target) rst[1] = hi;
            return rst;
        }
    }
    View Code

    解法3:(九章模板)

    public class Solution {
        public int[] searchRange(int[] A, int target) {
            if (A.length == 0) {
                return new int[]{-1, -1};
            }
            
            int start, end, mid;
            int[] bound = new int[2]; 
            
            // search for left bound
            start = 0; 
            end = A.length - 1;
            while (start + 1 < end) {
                mid = start + (end - start) / 2;
                if (A[mid] == target) {
                    end = mid;
                } else if (A[mid] < target) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            if (A[start] == target) {
                bound[0] = start;
            } else if (A[end] == target) {
                bound[0] = end;
            } else {
                bound[0] = bound[1] = -1;
                return bound;
            }
            
            // search for right bound
            start = 0;
            end = A.length - 1;
            while (start + 1 < end) {
                mid = start + (end - start) / 2;
                if (A[mid] == target) {
                    start = mid;
                } else if (A[mid] < target) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            if (A[end] == target) {
                bound[1] = end;
            } else if (A[start] == target) {
                bound[1] = start;
            } else {
                bound[0] = bound[1] = -1;
                return bound;
            }
            
            return bound;
        }
    }
    View Code

    5.Find Minimum in Rotated Sorted Array:http://www.lintcode.com/en/problem/find-minimum-in-rotated-sorted-array/

    寻找旋转排序数组中的最小值:

    解法1:(while(lo<hi); 首先判断([lo]>[hi])return[lo]; 然后再判断[mid]和[start]; >=则lo=mid+1; 否则hi=mid; return[lo];)

    (其实思想是找出第一个小于[lo]的值;比较[mid]和[lo];)

    ([5,6,7,1,2,3,4] 如果[lo]<[hi] 那么说明没有旋转; 比较mid和start,如果>=,说明旋转的在后半部分(不含mid)例如[2,1]/[2,3,1],而[2,3,4]是已经判断过了的所以不会出现;如果<,说明在前半部分(包含mid),例如[3,1,2]包含mid)

    public class Solution {
    
        public int findMin(int[] nums) {
    
            int lo = 0, hi = nums.length - 1;
            while (lo < hi) {
                if (nums[lo] < nums[hi]) return nums[lo];
                int mid = lo + (hi - lo) / 2;
                if (nums[mid] >= nums[lo]) lo = mid + 1;
                else hi = mid;
            }
            return nums[lo];
    
        }
    }
    View Code

    解法2:(思想:找出第一个小于[hi]的值;如果mid<=hi, 那么hi=mid;mid>hi, 那么mid那么lo=mid; 与Find First的套路一致! 其实和解法1一样……解法1更优化.

    不过这里的[hi]是变化的,而九章的解法里是把hi固定为最后一位)

    public class Solution {
        public int findMin(int[] nums) {
            int lo = 0, hi = nums.length - 1;
            while (lo < hi) {
                int mid = lo + (hi - lo) / 2;
                if (nums[mid] > nums[hi]) lo = mid + 1;
                else hi = mid;
            }
            return nums[lo];
        }
    }
    View Code

    (注意:如果使用解法1,则必须判断[lo]<[hi]情况;而解法2则不需要;) 

    6.Search a 2D Matrix : http://www.lintcode.com/en/problem/search-a-2d-matrix/

    搜索二维矩阵:

    解法1:(两次二分搜索;第一次循环必须是while(+1<),对应循环内部是mid,mid;最后分别判断[end]和[start]与tar; 第二次循环,普通的二分法;)

    public class Solution {
        /**
         * @param matrix, a list of lists of integers
         * @param target, an integer
         * @return a boolean, indicate whether matrix contains target
         */
        public boolean searchMatrix(int[][] matrix, int target) {
            // write your code here
            if (matrix == null || matrix.length == 0){
                return false;
            }
            if (matrix[0] == null || matrix[0].length == 0){
                return false;
            }
            int start = 0;
            int end = matrix.length - 1;
            int row ;
            while (start + 1 < end) {
                int mid = start + (end - start)/2;
                if (matrix[mid][0] == target){
                    return true;
                } else if (matrix[mid][0] < target) {
                    start = mid ;
                } else {
                    end = mid ;
                }
            }
            if (matrix[end][0] <= target){
                row = end;
            } else if (matrix[start][0] <= target){
                row = start;
            } else {
                return false;
            }
         
            start = 0;
            end = matrix[0].length - 1;
            while (start <= end) {
                int mid = start + (end - start)/2;
                if (matrix[row][mid] == target){
                    return true;
                } else if (matrix[row][mid] < target) {
                    start = mid + 1;
                } else {
                    end = mid - 1;
                }
            }
            return false;
        }
    }
    View Code

    解法2:(一次二分搜索;看作是将Matrix看成m*n长的list,mid对应的number=Matrix[mid/col][mid%col])

    public class Solution {
        /**
         * @param matrix, a list of lists of integers
         * @param target, an integer
         * @return a boolean, indicate whether matrix contains target
         */
        public boolean searchMatrix(int[][] matrix, int target) {
            // write your code here
            if (matrix == null || matrix.length == 0){
                return false;
            }
            if (matrix[0] == null || matrix[0].length == 0){
                return false;
            }
            int start = 0;
            int row = matrix.length;
            int col = matrix[0].length;
            int end = row * col - 1;
            while (start <= end){
                int mid = start + (end - start) / 2;
                int num = matrix[mid / col][mid % col];
                if (num == target){
                    return true;
                } else if (num < target){
                    start = mid + 1;
                } else {
                    end = mid - 1;
                }
            }
            return false;
        }
    }
    View Code

    LeetCode:

    1.Search in Rotated Sorted Array:https://leetcode.com/problems/search-in-rotated-sorted-array/#/description

    找出旋转排序数组的tar值:

    (findMin+常规Binary Search)

    解法:(先找出最小值位置index:(lo<hi)三步-判断([lo]<[hi]),判断([lo]<=mid),else;index是最小值位置,也是数组旋转的位数; 再用常规二分搜索- realmid=(mid+index)%n;判断realMid和tar,指针移动为mid+1/mid-1;)

    public class Solution {
        public int search(int[] nums, int target) {
            int lo = 0,  n = nums.length;
            int hi = n - 1;
            int index = findMinIndex(nums);
            while (lo <= hi) {
                int mid = lo + (hi - lo) / 2;
                int realMid = (mid + index) % n;
                if (nums[realMid] == target) return realMid;
                else if (nums[realMid] < target) lo = mid + 1;
                else hi = mid - 1;
            }
            return -1;
        }
        public int findMinIndex(int[] nums) {
            int lo = 0, hi = nums.length - 1;
            while (lo < hi) {
                if (nums[lo] < nums[hi]) return lo;
                int mid = lo + (hi - lo) / 2;
                if (nums[lo] <= nums[mid]) lo = mid + 1;
                else hi = mid;
            }
            return lo;
        }
    }
    View Code

    2.Find Minimum in Rotated Sorted Array II:https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/#/description

    找出旋转排序数组最小值II(含重复):

    解法1:(基于Minimum的解法1;区别就是mid=lo的时候,lo++)

    public class Solution {
        public int findMin(int[] nums) {
            int lo = 0, hi = nums.length - 1;
            while (lo < hi) {
                if (nums[lo] < nums[hi]) return nums[lo];
                int mid = lo + (hi - lo) / 2;
                if (nums[mid] > nums[lo]) lo = mid + 1;
                else if (nums[mid] < nums[lo]) hi = mid;
                else lo++;
            }
            return nums[lo];
        }
    }
    View Code

    解法2:(与MinimumI解法2相同,区别就是mid=hi的时候,hi--,这样此时不会移除最小值;因为mid=hi有两种情况,一是mid-hi之间全部相等,二是mid前的所有数都等于hi;其实和解法1一样……)

     1 public class Solution {
     2     public int findMin(int[] nums) {
     3         int lo = 0, hi = nums.length - 1;
     4         while (lo < hi) {
     5             int mid = lo + (hi - lo) / 2;
     6             if (nums[mid] > nums[hi]) lo = mid + 1;
     7             else if (nums[mid] < nums[hi]) hi = mid;
     8             else hi--;
     9         }
    10         return nums[lo];
    11     }
    12 }
    View Code

    3.Search Insert Position:https://leetcode.com/problems/search-insert-position/#/description

    寻找插入位置(找到tar则返回改位置,否则返回插入位置):

    解法:(和常规Binary Search相同;唯一区别是BS找不到返回-1,该题找不到返回lo!  [2,4]示例,lo/mid-2,hi-4;若tar-3 则mid<tar, lo=mid+1; 此时lo刚好为目标位置;若tar-1 则mid>tar,hi=mid-1,为lo的前一个位置,但是插入的位置是要替换lo的位置的,所以目标位置仍然为lo; )

    public class Solution {
        public int searchInsert(int[] nums, int target) {
            int lo = 0, hi = nums.length - 1;
            while (lo <= hi) {
                int mid = lo + (hi - lo) / 2;
                if (nums[mid] == target) {
                    return mid;
                } else if (nums[mid] > target) {
                    hi = mid - 1;
                } else {
                    lo = mid + 1;
                }
            }
            return lo;
        }
    }
    View Code
  • 相关阅读:
    经典音乐插曲推荐![附地址]
    广播电台常用51首背景音乐——绝对经典
    酒吧..夜店常用歌曲~潮人必备音乐噢~【附下载地址】
    ASP与ASP.NET互通COOKIES的一点经验
    linux进程状态浅析
    常用的酒吧经典乐曲106首
    呼和浩特电视台媒资管理系统的设计与分析
    不再为DataGrid生成的表格的单无格中的内容过长、自动折行、表格撑开等问题而烦恼
    Linux shell脚本全面学习
    ASP.NET文件管理显示信息
  • 原文地址:https://www.cnblogs.com/buwenyuwu/p/6541214.html
Copyright © 2011-2022 走看看