跟着代码随想录的第一天——二分查找

1.二分查找

什么时候需要二分查找?

有序数列+不重复元素+只查找一个

这三个种情况一起才能去使用二分查找。

什么是二分查找?

不断去将一个数组分成两份,不断去比较这份数组的中位数和要查找数是否相同,直到相同为止就是二分查找。

举一个现实一点的例子,你借了一堆书,里面有一本书没登记上,你现在想把它找出来,你把书平均分成两份,你把其中一份拿去过安检,你发现报警器响了,那你就把这一份书拿出来再来分成两份,再拿一份去过安检,如果响了就去拆这一份不响就去拆另外一份,不断去重复这个操作,直到只剩一本,这一本就是我们需要的。

1.1二分查找的思路

那给你一串有序无重复数据,你要怎么去找这一串数据中你所需要的数呢?

这里有一串数组arr={1,2,3,4,5,6,7,8,...n}.在数组内部对应的下标为0-(n-1).你的目标为target.利用二分查找去找出这个数。

第一步,你需要知道这个数组的最大数,最小数和中位数。由于数组是有序的。所以最大的数为arr[n-1],最小的数为arr[0],所以初始的下标right=arr.size()-1,left=0

而这串数组的中位数下标为:middle=left+(right-lefte)/2,这个算法我也是参考了网上别人的想法,如果直接用middle=(right+lefte)/2会造成有符号数的溢出,但我个人人为如果将数据直接定义为unsigned格式不知道是不是就存在这个问题了。有的人在这里主要是会去纠结奇数和偶数中位数的区别,其实很简单:

比如数组有四个数,那其中位数的下标根据公式计算为2,对应的其实是数组的第三个数,如果第三个数不是目标,那你之后去对比的两堆数其实是第1,2个数一堆,然后第4个数一堆。

而如果数组有5个数,那中位数计算后的下标根据公式计算也为2,对应的也是数组的第三个数,如果第三个数不是目标,那你之后去对比的两堆数其实是第1,2个数一堆,然后第4,5个数一堆.

总数为奇和欧数只是会影响你对比的堆中个数,你不管怎么分堆,所需的数肯定不会被遗漏的,只是迭代次数不一样了。

接下来,你需要去对照找到中位数和target的大小关系,才知道这个target是属于哪一堆的。

初始的情况,我们需要去对比所有数据的中位数是否为目标target。如果不是就需要去判断中位数比target大还是小了。以1,2,3,4,5为例,查找2,下表为初始位置

12345
下标01234
左右位置leftmidright

由于mid指向的数大于target,所以第二次应该去查找mid左边的部分,如下图所示:

12
下标01
左右位置left/midright

而此时mid指向的数小于target,所以第三次应该去查找mid右边的数,如下图所示:

2
下标1
左右位置left/right/mid

此时mid指向的数等于target,所以应该返回此时的下标mid。

1.2 二分查找的代码

力扣练习:704. 二分查找 - 力扣(LeetCode)

明白了思路现在就可以开始编程了。以C++代码为例。力扣都是用的核心代码模式,但是实际不少大厂笔试的编程模式都是ACM模式,所以下面用两种模式来编写代码:

ACM模式:

#include<iostream>
#include<vector>
using namespace std;
int getarget(vector<int>& nums, int val)
{
    int left = 0;
    int right = nums.size()-1;//左右游标
    while (left <= right)//闭合数组的二分查找
    {
        int middle = left + (right - left) / 2;//替换中位数
        if (nums[middle] > val)
        {
            right = middle - 1;
        }
        else if (nums[middle] < val)
        {
            left = middle + 1;
        }
        else
        {
            return middle;
        }
    }
    return -1;
}
int main()
{
    int n;
    vector<int>arr;
    int temp ;
    cin >> temp;
    while (cin >> n)
    {
        arr.push_back(n);
        if (cin.get() == '\n') break;
    }//输入不知道个数的数组;
    cout<<getarget(arr, temp)<<endl;
    return 0;
   
}

输入格式为:第一行输入查找目标

第二行输入需要查找的数组用空格隔开

核心代码模式:

class Solution {
public:
    int search(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size()-1;//左右游标
    while (left <= right)//闭合数组的二分查找
    {
        int middle = left + (right - left) / 2;//替换中位数
        cout << middle << endl;
        if (nums[middle] > val)
        {
            right = middle - 1;
        }
        else if (nums[middle] < val)
        {
            left = middle + 1;
        }
        else
        {
            return middle;
        }
    }
        return -1;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值