算法小白力扣刷题记录【二分搜索】

算法小白算法刷题记录【一】


前言

第一次刷题,第一次发博,知识来源网络,但是用自己理解的话表达。跟着[代码随想录]内容开始 吧。记录自己刷题过程,如果同样有踩坑,提供一种思想吧。【算法小白开始,不高深】
环境:VScode:Leetcode插件。
记录一:二分搜索法


一、什么是二分搜索法?

问题:什么时候要用它?看到什么能想到用二分搜索法?
答:看到“有序数组”、“找特定元素”、“元素不重复”,把第一反应的线性搜索换成二分搜索。
解释:二分:折半的意思,每次划分一半去搜索(字面理解)。因为时间复杂度是O(logn),所以也叫对数搜索算法。
目的:在有序数组中,找一个特定元素A,返回这个元素的位置
过程:从中间位置开始,和要找的元素A比较。如果A大,去大的那一半找;如果A小,去小的那一半找。(有序作用的体现,不是有序不能用的,要么得先排序)确定好哪一半之后,再找这一半的中间,继续重复过程。最终返回位置。

二、解答过程

1.力扣[704]

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

		输入: nums = [-1,0,3,5,9,12], target = 9
		输出: 4
		解释: 9 出现在 nums 中并且下标为 4

示例 2:

		输入: nums = [-1,0,3,5,9,12], target = 2
		输出: -1
		解释: 2 不存在 nums 中因此返回 -1

2.第一动手尝试(不看讲解,没做优化)

全靠自己想,写出来的。没有做优化的代码。先贴算法代码:

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int size = nums.size();//获得当前元素个数
        int middle = floor(size/2);//确定中间索引,左半边的右界,右半边的左界。
        int left = 0;   //左半边的左界
        int right = size-1;//右半边的右界
        while((0 <= middle<size) && (right >= left) ){    //最后确定条件
            if(nums[middle] == target){   //如果刚好是正中间的元素,直接返回查找
                return middle;            
            }else if(nums[middle] < target){ //进入右半边查找,更新边界
                left = middle+1;
            }else if(nums[middle] > target){
                right = middle -1;
            }
            middle = left + floor((right-left)/2);
        }
        return -1;
    }
};

写的过程(包含删减的过程,主要体现为什么这样改?):

1.第一步确定左右两半的边界:

一开始:int middle = floor(size/2);
	   int left = middle;
	   int right = middle+1;

得到左半边:[0,left]。右半边:[right,size]。(先放着)写到更新边界的时候发现,左半边的0没有办法改,右半边的size没有办法动。所以改成了[left,middle]和[middle,right]。最后如图所示。

2.if条件判断:

else if(nums[middle] < target){ //进入右半边查找,更新边界
            left = middle+1;
            middle = left + floor((right-left)/2);	//注意先写了这行

写到if大于的条件发现middle更新语句一样,所以删去了这里,统一放到了最后。

3.left和right更新

我在这里没有出错。此时我还没有区间是闭区间还是左闭右开区间的概念,但是我认为nums[middle]已经比较过,下一轮不应该再有nums[middle]。
所以right = middle-1;left = middle+1.

4.while条件确定

在最后才确定了while条件,想middle界限应该在vector内;并且right>=left。
为什么有“=”?
答:画图发现当left=right,就剩nums[left]也就是nums[right]没有比较,不能漏掉它,所以得有“=”。

C++运行:

执行代码:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

int main(){
    vector<int> nums;
    int elem;
    int target;
    Solution search;
    cout<<"输入有序数字,空格为间:"<<endl;
    do{
        cin>>elem;
        nums.push_back(elem);
    }while(cin.get() != '\n');
    cout<<"要查找的目标值:"<<endl;
    cin>>target;
    int result = search.search(nums,target);
    if(result == -1){
        cout<<target<<"不存在nums中因此返回"<<result<<endl;
    }else{
        cout<<target<<"出现在nums中并且下标为"<<result<<endl;
    }
    return 0;
}

运行结果没有问题。

3.代码随想录学习(改进)

区别:

第一:while()。他没有判断middle,只判断left和right足够。
第二:middle,我先确定每一轮循环的middle,再去while。而他是先进入while,再去求middle。

想一想我要按照他这么改吗?

卡哥讲解记录:

循环不变量:每次while都是找一个区间,也就是说的在左半边还是右半边?
	表达:始终坚持区间包含left和right下标的元素(左闭右闭)或者始终坚持区间包含left下标元素但不包含right下标元素(左闭右开)
	总结:我在写的时候是左闭右闭,[left,right]。此时有了区间的概念。
第一种[left,right]:
	while(left<=right)				left=middle+1;right=middle-1;
第二种[left,right):
	while(left<right)				初始right=nums.size()。left = middle+1;right=middle;
讲解从区间合不合法确定,更直观可以画图指向元素尝试一下。

总结:不要漏掉元素和target比较,从这个角度看,边界的确定保证每个元素都能被比较到,同时不要重复比较

改进点:为语句更少,更简洁。

  1. middle不会越界,所以可以不用放在while中。
  2. middle只在while内放上面,初始时可以不用写了。

总结

二分搜索记录如上。边界确定好的关键是:不要漏掉元素和target比较,从这个角度看,边界的确定保证每个元素都能被比较到,同时不要重复比较

(欢迎指正)

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,关于力扣刷题C++常用操作,我可以给你一些常见的操作和技巧: 1. 使用 STL 容器和算法库:STL(Standard Template Library)是 C++ 标准库中的一个重要组成部分,包含了许多常用的容器和算法。在力扣刷题中,使用 STL 可以大大提高代码的效率和可读性。例如,vector 可以用来存储动态数组,sort 可以用来排序等等。 2. 使用 auto 关键字:auto 关键字可以自动推导变量类型,可以减少代码量和提高可读性。例如,auto x = 1; 可以自动推导出 x 的类型为 int。 3. 使用 lambda 表达式:lambda 表达式是 C++11 中引入的一种匿名函数,可以方便地定义一些简单的函数对象。在力扣刷题中,使用 lambda 表达式可以简化代码,例如在 sort 函数中自定义比较函数。 4. 使用位运算:位运算是一种高效的运算方式,在力扣刷题中经常会用到。例如,左移运算符 << 可以用来计算 2 的幂次方,右移运算符 >> 可以用来除以 2 等等。 5. 使用递归:递归是一种常见的算法思想,在力扣刷题中也经常会用到。例如,二叉树的遍历、链表的反转等等。 6. 使用 STL 中的 priority_queue:priority_queue 是 STL 中的一个容器,可以用来实现堆。在力扣刷题中,使用 priority_queue 可以方便地实现一些需要维护最大值或最小值的算法。 7. 使用 STL 中的 unordered_map:unordered_map 是 STL 中的一个容器,可以用来实现哈希表。在力扣刷题中,使用 unordered_map 可以方便地实现一些需要快速查找和插入的算法。 8. 使用 STL 中的 string:string 是 STL 中的一个容器,可以用来存储字符串。在力扣刷题中,使用 string 可以方便地处理字符串相关的问题。 9. 注意边界条件:在力扣刷题中,边界条件往往是解决问题的关键。需要仔细分析题目,考虑各种边界情况,避免出现错误。 10. 注意时间复杂度:在力扣刷题中,时间复杂度往往是评判代码优劣的重要指标。需要仔细分析算法的时间复杂度,并尽可能优化代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值