二分查找

来源:互联网 发布:怎样看出淘宝是包邮的 编辑:程序博客网 时间:2024/06/03 17:28

二分查找问题,找到后返回所在索引,否则返回-1。有以下几种情况:

1. 有序、无重复数组的查找

int binSearch(int *arr, int n, int key) {    int low = 0,  high = n - 1;    while (low < high) {        int mid = low + (-low + high) / 2;        if (arr[mid] == key) {            return mid;        } else if(arr[mid] < key) {            low = mid + 1;        } else            high = mid - 1;    }        return -1;}

2. 有序、有重复数组的查找

可能需要返回首次、末次出现的位置。这时候循环条件要做一下改变。循环条件需要满足,查找范围在缩小(丢掉的数字至少为1个)

2.1 返回最后一次出现的位置

对于arr[mid]>key,array[mid...high]均小于key,x只可能存在于arr[low...mid-1]中。数组减少的长度为high-mid+1,至少为1。
对于arr[mid]==key, arr[mid]是array[left, ..., mid]中最后一个值为key的元素,那么只能在arr[mid, ... ,right]中找,数组减少长度为mid-left。想要保证查找范围在减少,需要保证mid-left>0 !又因为mid = low + (-low + high) / 2 得high - low > 1,即满足这个条件才可以循环!
对于arr[mid]<key, arr[low...mid]均小于key,x只可能在[mid+1...high]之中。数组减少的长度为(mid-low)+1,至少为1。
最后返回high的值
int binSearch_last(int *arr, int n, int key) {    int low = 0,  high = n - 1;    while (low + 1 < high) {        int mid = low + (-low + high) / 2;        if (arr[mid] > key) high = mid - 1;        else low = mid;    }    if (arr[high] == key) return high;        return -1;}

2.2 返回第一次出现的位置

对于arr[mid]<key,array[left, ..., mid]均小于key,x只可能存在于arr[mid+1, ..., high]中。数组减少的长度为mid-left+1,至少为1。
对于arr[mid]==key, arr[mid]是array[left, ..., mid]中最后一个值为key的元素,那么只能在arr[mid, ... ,high]中找,数组减少长度为mid-left。想要保证查找范围在减少,需要保证mid-left>0 !又因为mid = low + (-low + high) / 2 得high - low > 1,即满足这个条件才可以循环!
对于arr[mid]>key, arr[mid, ..., right]均大于key,x只可能在[left, ..., mid-1]之中。数组减少的长度为(right-mid)+1,至少为1。
最后返回low的值
int binSearch_first(int *arr, int n, int key) {    int low = 0,  high = n - 1;    while (low + 1 < high) {        int mid = low + (-low + high) / 2;        if (arr[mid] < key) low = mid + 1;        else high = mid;    }    if (arr[low] == key) return low;        return -1;}


3. 练习题

《剑指offer》 中的旋转数组的最小数字

class Solution {public:    int findLiner(int *arr, int left, int right) {        int min_val = arr[left];        for (int i = left + 1; i <= right; i++) {            if (min_val > arr[i])                min_val = arr[i];        }        return min_val;    }    int rotateNum(int *arr, int n) {        int left = 0, right = n - 1, mid = 0;                while (left + 1 < right) {            mid = left + ((right - left) >> 1);            if (arr[mid] > arr[left]) {                left = mid;            } else if (arr[mid] == arr[left] && arr[mid] == arr[right]){                return findLiner(arr, left, right);            } else                 right = mid;        }        return arr[mid];    }};

leetcode Split Array Largest Sum

class Solution {public:    int splitArray(vector<int>& nums, int m) {        long long left = 0, right = 0;        for (int i = 0; i < nums.size(); ++i) {            left = max((int)left, nums[i]);            right += nums[i];        }        while (left < right) {            long long mid = left + (right - left) / 2;            if (can_split(nums, m, mid)) right = mid;            else left = mid + 1;        }        return left;    }    bool can_split(vector<int>& nums, int m, int sum) {        int cnt = 1, curSum = 0;        for (int i = 0; i < nums.size(); ++i) {            curSum += nums[i];            if (curSum > sum) {                curSum = nums[i];                ++cnt;                if (cnt > m) return false;            }        }        return true;    }};




0 0
原创粉丝点击