查找算法

二分查找

1. 递归实现

    int binarySearch(std::vector &num, int start, int end, int target)
    {
        if (start > end) {
            return -1;
        }
        int mid = start + (end - start) / 2;
        if (target == num[mid]) {
            return 1;
        }
        else if (target < num[mid]) {
            return binarySearch(num, start, mid - 1, target);
        }
        else if (target > num[mid]) {
            return binarySearch(num, mid + 1, mid, target);
        }
    }

2. 迭代实现

    int binarySearch(std::vector &num, int target)
    {
        int begin = 0;
        int end = num.size() - 1;

        while (begin <= end) {
            int mid = (begin + end) / 2;
            if (num[mid] == target) {
                return 1;
            }
            if (num[mid] > target) {
                end = mid - 1;
            }
            if (num[mid] < target) {
                begin = mid + 1;
            }
        }
        return -1;
    }

题目

1. 插入位置

题目

给定一个排序数组与目标值,该数组中没有重复元素,如果目标值在数组中出现,就返回目标在数组中的下标,如果目标在数组中没有出现,则返回目标应该插入的数组下标,使得目标插入之后,数组仍然有序。

思路

使用二分查找,如果存在就可以直接返回下标,如果不存在那么判断目标值与此时mid值的大小,确定位置。

代码

    int searchInsertPosition(std::vector &num, int target)
    {
        int index = -1;  // 要返回的数组下标
        int begin = 0;
        int end = num.size() - 1;
        int mid = 0;

        while (index == -1) {
            mid = (begin + end) / 2;
            if (target == num[mid]) {
                index = mid;
            }
            else if (target < num[mid]) {
                if (mid == 0 || target > num[mid-1]) {
                    index = mid;
                }
                end = mid - 1;
            }
            else if (target > num[mid]) {
                if (mid == num.size() - 1 || target < num[mid + 1]) {
                    index = mid + 1;
                }
                begin = mid + 1;
            }
        }
        return index;
    }

2. 区间查找

题目

图1. 题目

思路

  • 先确定左边的端点,再确定右边的端点
  • 怎么确定左右两边的端点?使用二分查找

代码实现

    // 查找左端点
    int leftBoundry(std::vector &num, int target)
    {
        int begin = 0;
        int end = num.size();

        while (begin <= end) {
            int mid = (begin + end) / 2;
            if (target == num[mid]) {
                if (mid == 0 || num[mid - 1] < target) {
                    return mid;
                }
                end = mid - 1;
            }
            else if (target < num[mid]) {
                end = mid - 1;
            }
            else if (target > num[mid]) {
                begin = mid + 1;
            }
        }
        return -1;
    }
    // 查找右端点
    int rightBoundry(std::vector &num, int target)
    {
        int begin = 0;
        int end = num.size();

        while (begin <= end) {
            int mid = (begin + end) / 2;
            if (target == num[mid]) {
                if (mid == num.size() - 1 || num[mid + 1] > target) {
                    return mid;
                }
                begin = mid + 1;
            }
            else if (target < num[mid]) {
                end = mid - 1;
            }
            else if (target > num[mid]) {
                begin = mid + 1;
            }
        }
        return -1;
    }
    // 确定端点
    void findBoundry(std::vector &num, int target)
    {
        int left = leftBoundry(num, target);
        int right = rightBoundry(num, target);
        std:: cout << "left :   " << left << std::endl;
        std:: cout << "right:   " << right << std::endl;
    }

3. 旋转数组查找

题目

给定一个排序数组,数组中没有重复元素,且该数组可以在某个位置条件下旋转。给定目标target,求target是否在数组中出现,若出现返回元素所在数组下标,否则返回-1。

思路

  • 考虑用二分查找,如果能够正确的找到说明没有问题,如果没有找到,是不能说明在数组中没有改数字的,因为数组进行了旋转之后,小的数可能在后面,这时候我们应该确定旋转区间,然后在旋转区间中继续查找,这时如果找不到,说明没有该数;
  • 那么问题变成了怎么确定旋转区间的问题,充分利用旋转之后数组的性质来进行判断旋转区间

代码

class Solution {
public:
    int search(std::vector &num, int target)
    {
        int begin = 0;
        int end = num.size();
        int mid = 0;

        while (begin <= end) {
            mid = (begin + end) / 2;
            if (num[mid] == target) {  // 正常的二分查找,找到元素
                return mid;
            }
            if (num[mid] > target) {
                if (num[mid] > num[begin]) {
                    if (target >= num[begin]) {
                        end = mid - 1;
                    }
                    else {
                        begin = mid + 1;
                    }
                }
                else if (num[begin] > num[mid]) {
                    end = mid - 1;
                }
            }
            if (num[mid] < target) {
                if (num[begin] < num[mid]) {
                    begin = mid + 1;
                }
                else if (num[begin] > num[mid]) {
                    if (target >= num[begin]) {
                        end = mid - 1;
                    }
                    else {
                        begin = mid + 1;
                    }
                }
                else if (num[begin] == num[mid]) {
                    begin = mid + 1;
                }
            }
        }
        return -1;
    }
};

你可能感兴趣的:(查找算法)