算法:二分查找题目练习

news2025/3/18 12:24:16

目录

题目一:二分查找

朴素的二分模版

题目二:在排序数组中查找元素的第⼀个和最后⼀个位置

查找区间左端点

查找区间右端点

查找区间左端点二分模版

查找区间右端点二分模版

题目三:搜索插⼊位置

题目四:x的平方根

题目五:山峰数组的峰顶

题目六:寻找峰值

题目七:搜索旋转排序数组中的最小值

题目八:0〜n-1中缺失的数字


二分查找算法原理

二分查找算法适用于数组有序的情况,当然数组如果无序但是能够找到一个规律,也是可以使用二分查找算法的

二分查找算法模版

这里的模块需要理解之后再记忆

有三个模版,分别是:

①朴素的二分模版
②查找左边界的二分模版
③查找右边界的二分模版


题目一:二分查找

给定一个 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

解法一:暴力解法

初看这个题,可以很容易想到暴力解法,也就是遍历一遍这个数组,直到找到这个目标值target,返回该目标值的下标即可,若没有找到该目标值,就返回-1即可

暴力解法时间复杂度是O(N)


解法二:二分查找算法

二分查找算法是当数组有二段性的时候,就能够使用二分查找算法了,因为在暴力解法中,依次遍历一次只能排除一个数,而如果数组有二段性,二分查找算法就可以依次排除一块区域的数,因此效率比较高

二段性就是我们所发现一个规律,根据这个规律选取一个点之后(一般选取中间的点),能够将数字分成两部分,根据规律能舍去其中一部分,进而在另一个部分里面继续查找的时候,此时就可以使用二分查找算法了

下面具体讲解二分查找算法:

有一个数组,左端点下标为left,右端点下标为right,中间位置的下标为mid,此时要查找的目标值是t,数组的中间值为x

此时选取中间的点x,与目标值t比较会有三种情况:

①x < t :left = mid +1,接着在 [ left, right ]的区间查找
②x > t :right = mid - 1,接着在 [ left, right ]的区间查找
③x == t:返回结果mid

循环的条件:left > right时就停止,因为每次判断完,如果没有找到结果,要不就是right左移或left右移,直到移动结束后left > right,就说明遍历结束了

二分查找算法的时间复杂度是O(logN)

代码如下:

class Solution {
public:
    int search(vector<int>& nums, int target) 
    {
        int left = 0, right = nums.size() - 1;
        while(left <= right)
        {
            int mid = left + (right - left) / 2; //防止溢出的风险
            if(nums[mid] < target) left = mid + 1;
            else if(nums[mid] > target) right = mid - 1;
            else return mid;
        }
        return -1;
    }
};

有个细节,在算中间值的下标mid时,没有采用(left + right) / 2来计算,因为这种计算方式有可能会导致溢出的风险,因为如果left和right都是极大的数,这两个数相加就可能会导致溢出

因此在这里采用(right - left) / 2,计算出left和right之间的距离的一半,再与left相加,就不会有上述风险了


朴素的二分模版

        while(left <= right)
        {
            int mid = left + (right - left) / 2;
            if(......) 
                left = mid + 1;
            else if(......) 
                right = mid - 1;
            else 
                return ......;
        }


题目二:在排序数组中查找元素的第⼀个和最后⼀个位置

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

解法一:暴力解法

同样在遇到这个题时,最容易想到的就是暴力解法了,依旧是遍历数组,在找到的第一个位置处做标记,在找到的最后一个位置处做标记,最后返回,如果没有找到要求的数,就返回[-1, -1]

暴力查找的时间复杂度依旧是O(N)


解法二:朴素二分

这个朴素二分的方法,在这道题中,就明显不太适用了,因为如果一个数组全部是同一个数,那么我使用朴素二分,从中间去一个点,并不能确定剩下符合条件的数是在左边还是右边,所以还是需要向左和右继续找,这样的时间复杂度和暴力解法并没有区别


所以下面详细说明一下查找区间的左端点和右端点的情况:

查找区间左端点

有一个数组如下所示,目标值t等于3,此时需要查找区间的左端点,也就是第一个3出现的位置

所以需要利用二段性, 将数组划分为上图所示的两部分,小于t和大于等于t这两部分

有一个数组,左端点下标为left,右端点下标为right,中间位置的下标为mid,此时要查找的目标值是t,数组的中间值为x

与朴素的二分模版不同,此题的target可能不止一个数,所以中间值与目标值t的比较就有如下两种情况:

x < t:left = mid + 1接着在 [ left, right ]的区间查找
x >= t:right = mid接着在 [ left, right ]的区间查找

需要注意,当x < t时,因为此时mid所指向的x都是不满足题意的,所以left需要移动到mid的右边,所以是 left = mid + 1

而当 x >= t时,此时的x有可能是目标值,所以right不能像二分的朴素模版那样,移动到mid的左边,而是移动到mid的位置

下面详细说明二分的两个细节:循环条件和求中点的操作

循环条件的相关细节:

关于循环条件:这里选的是 left < right 就进入循环,而不是left <= right

分下面三种情况讨论,来说明为什么循环条件选择 left < right

①数组中有结果:
数组如下,最终结果在ret这个位置开始:

最开始的时候,left是处于不合法的区间,而right是处于合法的区间,left区间和right区间如下所示:

right一直在合法区间上移动的时候,是绝对不会超过ret这个点的,因为right永远执行的是right = mid这个操作
而left是永远想跳出这个不合法区域的,因为left永远执行的是 left = mid + 1这个操作

而当left跳出区域与right相遇后,所指的这个位置正好是最终结果

所以当left = right的时候,就是最终结果了,无需继续判断

②数组全大于t:

如果全是大于t的,那么right是只会向左移动,直到移动到left的位置为止,因为这种情况下,left永远都不会移动,只有right不停地执行right = mid这个操作

此时left和right相遇了,但是这种情况下是没有最终结果的,所以只需判断一下相遇位置的值是否等于t即可,如果相等就返回这个位置的值,如果不相等就返回[-1, -1]即可

所以当left = right的时候,只需再与t比较一次判断是否是左端点的值即可,无需继续进入循环判断

③数组全小于t:

如果全是小于t的,那么left是只会向右移动,直到移动到right的位置为止

当他们相遇时,同样只需判断一下相遇位置的值是否等于t即可

所以当left = right的时候,只需再与t比较一次判断是否是左端点的值即可,无需继续进入循环判断

通过上述的三种情况,证明了循环条件是 left < right,不需要=,因为相等的时候就已经得出最终结果了,没有必要再进入循环中判断了

如果我们的循环条件不是 left < right,而是写成了 left <= right,就会出现死循环的情况

因为如果是第一种情况,left和right都指向了ret的位置,此时继续判断,right依旧是指向该位置,并不发生改变,继续进入循环......从而导致死循环


求中点的操作的相关细节:

在第一题中使用的朴素的二分模版,求中点时,采用的公式是:mid = left + (right - left) / 2

其实还有一个公式也可以求中点:mid = left + (right - left + 1) / 2

区别就是在括号中 +1,那么这两个的区别是什么呢?

很简单,当数组个数是偶数时,例如共有6个数,第一种公式求出来是下图这个位置:
mid = 0 + (5 - 0) / 2 = 2

如果是第二种公式,求出来则是这个位置:
mid = 0 + (5 - 0 + 1) / 2 = 3

可以观察到,在数组个数是偶数时,中间位置是两块,第一个公式指向的是偏左的那一块位置,而第二个公式指向的则是偏右的那一块位置

这两种情况再朴素二分中都可以使用,而在这种情况下则会有问题

当最后一个left和right指向下图所示的情况时:

如果采用第二个公式,计算出来mid指向中间偏右的位置,即:

如果是x < t,那么left = mid + 1,此时再判断不满足循环条件left < right,循环就会终止
而如果是x >= t,那么right = mid,此时mid和right指向同一块位置,这时就会出现死循环的情况

因此得出结论,在求区间左端点时,使用第二个公式求中点,就会陷入死循环

而如果采用第一个公式计算中点,mid就会指向:

如果是x < t,那么left = mid + 1,此时left和right相遇,循环终止
而如果是x >= t,那么right = mid,此时left和right同样相遇,循环终止

不会出现上述死循环的情况


查找区间右端点

同样是该数组如下所示,目标值t等于3,此时需要查找区间的右端点,也就是最后一个3出现的位置:

所以需要利用二段性, 将数组划分为上图所示的两部分,小于等于t和大于t这两部分

有一个数组,左端点下标为left,右端点下标为right,中间位置的下标为mid,此时要查找的目标值是t,数组的中间值为x

x <= t:left = mid接着在 [ left, right ]的区间查找
x > t:right = mid - 1接着在 [ left, right ]的区间查找

当x <= t时,表示结果就在mid的左边这个区域,此时的x有可能是目标值,所以left不能像二分的朴素模版那样,移动到mid的右边,而是移动到mid的位置
当x > t时,因为此时mid所指向的x都是不满足题意的,所以right需要移动到mid的左边,所以是 right= mid + -1

下面详细说明二分的两个细节:循环条件和求中点的操作

循环条件的相关细节:

循环条件同样是left < right

具体证明和上面求左端点的步骤一样,以此类推

求中点的操作的相关细节

求中点的方式依旧是这两个公式

①mid = left + (right - left) / 2
②mid = left + (right - left + 1) / 2

第一个公式求的是靠左的,第二个公式求的是靠右的

当最后一个left和right指向下图所示的情况时:

如果采用第一个公式,计算出来mid指向中间偏左的位置,即:

如果是x <= t,那么left = mid,此时mid和right指向同一块位置,这时就会出现死循环的情况

因此得出结论,在求区间右端点时,使用第一个公式求中点,就会陷入死循环

而如果采用第二个公式计算中点,mid就会指向中间偏右的位置:

如果是x <= t,那么left = mid,此时left和right相遇,循环终止
而如果是x > t,那么right = mid - 1,此时left和right同样相遇,循环终止

不会出现上述死循环的情况


利用上述讲解的计算左端点和右端点的方法,解决此题:

代码如下:

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        if(nums.size() == 0) return {-1,-1}; //判断边界条件
        int left = 0, right = nums.size()-1,begin = 0;
        while(left < right) //计算左端点
        {
            int mid = left + (right -left) / 2;
            if(nums[mid] < target) left = mid + 1;
            else right = mid;
        }
        //判断是否有结果
        if(nums[left] != target) return {-1,-1}; 
        else begin = left; //begin存储左端点的下标

        left = 0, right = nums.size()-1;
        while(left < right) //计算右端点
        {
            int mid = left + (right -left + 1) / 2;
            if(nums[mid] <= target) left = mid;
            else right = mid - 1;
        }
        return {begin,right};        
    }
};

查找区间左端点二分模版

        while(left < right)
        {
            int mid = left + (right -left) / 2;
            if(......) left = mid + 1;
            else right = mid;
        }

查找区间右端点二分模版

        while(left < right)
        {
            int mid = left + (right -left + 1) / 2;
            if(......) left = mid;
            else right = mid - 1;
        }

题目三:搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

这道题也可以很容易的看出这个数组的二段性

也就是所插入的值要不和数组中的数相等, 要不就是第一次出现比它大的这个数的位置,所以可以得到结论:最终找到的位置应该是大于等于目标值target的

所以利用二段性分为小于target,和大于等于目标值target

代码如下:

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0, right = nums.size()-1;
        if(nums[right] < target) return nums.size(); // 判断边界条件
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] < target) left = mid + 1;
            else right = mid;
        }
        return left;
    }
};

题目四:x的平方根

给你一个非负整数 x ,计算并返回 x 的 算术平方根 。

由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。

注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。

示例 1:

输入:x = 4
输出:2

示例 2:

输入:x = 8
输出:2
解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。

解法一:暴力解法

依次列举1、2、3、4、5....的平方,与x做比较,如果比x小就继续往后试,直到找到这个数的平方要么是大于这个数,要么是等于这个数位置,就说明找到了最终解

当等于时就返回这个数,当是大于时就返回它前一个数


解法二:二分查找

二分查找最重要的就是找到二段性

我们可以发现,整个数组可以分为小于等于x和大于x这两个区域

所以就有两种情况:

①mid * mid <= x:left = mid
②mid * mid > x:right = mid - 1

分情况讨论即可


代码如下:

class Solution {
public:
    int mySqrt(int x) {
        if(x < 1) return 0; // 处理边界条件
        long long left = 1, right = x;
        while(left < right)
        {
            long long mid = left + (right - left + 1) / 2;//防溢出
            if(mid * mid <= x) left = mid;
            else right = mid - 1;
        }
        return left;
    }
};

题目五:山峰数组的峰顶

符合下列属性的数组 arr 称为 山脉数组 :

  • arr.length >= 3
  • 存在 i0 < i < arr.length - 1)使得:
    • arr[0] < arr[1] < ... arr[i-1] < arr[i]
    • arr[i] > arr[i+1] > ... > arr[arr.length - 1]

给你由整数组成的山脉数组 arr ,返回满足 arr[0] < arr[1] < ... arr[i - 1] < arr[i] > arr[i + 1] > ... > arr[arr.length - 1] 的下标 i 。

你必须设计并实现时间复杂度为 O(log(n)) 的解决方案。

示例 1:

输入:arr = [0,1,0]
输出:1

示例 2:

输入:arr = [0,2,1,0]
输出:1

示例 3:

输入:arr = [0,10,5,2]
输出:1

这个题目也是比较好理解的,所给的数组元素的大小,都是先上升再下降的,都存在一个最大值,求这个最大值的下标

解法一:暴力枚举

从前往后依次枚举,当枚举到一个数的值是大于前一个数的,这个数就是峰值,返回下标即可

暴力解法的时间复杂度是O(N)


解法二:二分查找算法

此时根据这个峰值数组的特性,可以找到这个数组的二段性, 如下图所示:

左边的区间包含峰值,每一个数都大于前一个数

右边区域不包含峰值,每一个数都小于小于前一个数

代码如下:

class Solution {
public:
    int peakIndexInMountainArray(vector<int>& arr) {
        int left = 0, right = arr.size()-1;
        while(left < right)
        {
            int mid = left + (right - left + 1) / 2;
            if(arr[mid] > arr[mid-1]) left = mid;
            else right = mid - 1;
        }
        return left;
    }
};

题目六:寻找峰值

峰值元素是指其值严格大于左右相邻值的元素。

给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。

你可以假设 nums[-1] = nums[n] = -∞ 。

你必须实现时间复杂度为 O(log n) 的算法来解决此问题。

示例 1:

输入:nums = [1,2,3,1]
输出:2
解释:3 是峰值元素,你的函数应该返回其索引 2。

示例 2:

输入:nums = [1,2,1,3,5,6,4]
输出:1 或 5 
解释:你的函数可以返回索引 1,其峰值元素为 2;
     或者返回索引 5, 其峰值元素为 6。

这道题需要注意的是:nums[-1] = nums[n] = -∞ 这个条件

表示默认第一个元素前和最后一个元素之后都是最小的,所以如果是如下这种情况,最后一个位置也是峰值,如下:

或是这种情况,第一个也是峰值:

这就是刚买这个条件所表达的意思


解法一:暴力枚举

从第一个位置开始暴力枚举,分下面的情况讨论即可:

①第二个数比第一个小,此时第一个数就是峰值
②在走的过程中一直上升,直到遇到一个比该值小的,此时该值就是峰值
③从第一个数开始一直上升,直到最后一个数为止,此时最后一个数是峰值

暴力枚举的时间复杂度是O(N)


解法二:二分查找算法

在arr数组中,有两种情况,一个坐标是i另一个坐标是i+1

如果arr[i] > arr[i+1],说明此时是下降趋势,也就是说答案就在 <= i的区域,此时需要改变right的值

如果arr[i] <  arr[i+1],说明此时是上升趋势,也就是说答案就在 > i的区域,此时需要改变left的值

将上述所说的i替换为mid,就可以使用二分查找算法进行计算了

代码如下:

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int left = 0, right = nums.size()-1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] > nums[mid + 1]) right = mid;
            else left = mid + 1;
        }
        return left;
    }
};

题目七:搜索旋转排序数组中的最小值

已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:

  • 若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
  • 若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]

注意,数组 [a[0], a[1], a[2], ..., a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], ..., a[n-2]] 。

给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。

你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

输入:nums = [3,4,5,1,2]
输出:1
解释:原数组为 [1,2,3,4,5] ,旋转 3 次得到输入数组。

示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0
解释:原数组为 [0,1,2,4,5,6,7] ,旋转 3 次得到输入数组。

示例 3:

输入:nums = [11,13,15,17]
输出:11
解释:原数组为 [11,13,15,17] ,旋转 4 次得到输入数组。

需要注意数组中的数是互不相同的,需要找出最小元素

解法一:暴力枚举

暴力枚举,遍历一遍数组,找出最小的元素

时间复杂度O(N)


解法二:二分查找算法

此题也可以找到数组的二段性,每一个数组都大致可以分为下面这种情况,即原本的递增数字旋转后,会出现先递增,再递增的趋势:

AB这一段都大于D点,CD这一段都小于等于D点,就有了二分查找算法所需的二段性

设D点为x,分为下面两种情况:

①arr[mid] > x,表示在AB线段上,此时改变需要改变左区间
②arr[mid] <= x,表示在CD线段上,此时改变需要改变右区间

代码如下:

class Solution {
public:
    int findMin(vector<int>& nums) {
        int left = 0, right = nums.size()-1;
        int x = nums[right];
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(nums[mid] > x) left = mid + 1; 
            else right = mid;
        }
        return nums[left];
    }
};

题目八:0〜n-1中缺失的数字

某班级 n 位同学的学号为 0 ~ n-1。点名结果记录于升序数组 records。假定仅有一位同学缺席,请返回他的学号。

示例 1:

输入: records = [0,1,2,3,5]
输出: 4

示例 2:

输入: records = [0, 1, 2, 3, 4, 5, 6, 8]
输出: 7

这里的最后一道题,其实是很简单的,其中是有非常多的解法的,具体如下:

前四种的时间复杂度都是O(N),因为都需要遍历一遍数组

解法一:遍历数组

因为是学号从0开始递增的,所以直接遍历数组,看哪个数断开了

代码如下:

class Solution {
public:
    int takeAttendance(vector<int>& records) {
        int i = 0;
        for (i = 0; i < records.size(); i++) 
        {
            if (records[i] != i)
                break;
        }
        return i;
    }
};

解法二:哈希表

建立大小为n的哈希表,遍历原始数组,填进哈希表中,接着遍历哈希表,发现哪个数字没有填,答案就是那个数字

class Solution {
public:
    int takeAttendance(vector<int>& records) {
        int i = 0;
        unordered_map<int, int> ump; 
        for (auto& it : records) ump[it]++;
        for (i = 0; i < records.size(); i++) 
        {
            if(!ump.count(i)) break;
        }
        return i;
    }
};

用数组替代哈希表:

class Solution {
public:
    int takeAttendance(vector<int>& records) {
        int i = 0;
        int hash[10000] = {0};
        for (auto& it : records) hash[it]++;
        for (i = 0; i < records.size(); i++) 
        {
            if(hash[i] == 0)
                break;
        }
        return i;
    }
};

解法三:位运算(异或运算)

异或运算时有个特点:相同为0,相异为1,所以我们可以先把数组中的元素异或一遍,再异或n个递增的数组,异或完后剩下来的就是缺失的数

因为缺失了一个数,所以for循环中个数需要加1

代码如下:

class Solution {
public:
    int takeAttendance(vector<int>& records) {
        int i = 0, res = 0;
        for (auto& it : records) res ^= it;
        for (i = 0; i < records.size()+1; i++) res ^= i;
        return res;
    }
};

解法四:数学(高斯求和公式)

也就是将n个数加起来,依次减去原数组中的数,剩下的就是缺失的数

因为n个数从0开始递增,所以公差是1,可以使用(首项 + 末项) * 项数 / 2计算

因为从0开始,共有n个数,所以首项是0,末项是records.size()也就是n,因为假设有3个数,末项是2,而records中缺少了一个数,records.size()就为2,所以可以将records.size()当做末项

项数是n+1,因为n是records.size(),而records缺少了一个数,所以项数需要+1

代码如下:

class Solution {
public:
    int takeAttendance(vector<int>& records) {
        int i = 0, res = 0, n = records.size();
        res = (0 + n)*(n + 1)/2;
        for (i = 0; i < records.size(); i++) res -= records[i];
        return res;
    }
};

解法五:二分查找算法

这道题光看数字可能看不出来怎么使用二分,而如果将下标都标注出来, 此时就可以很清晰的看出二段性了,假设数组是0,1,2,3,5,如下所示,黑色的表示数字元素,红色的表示下标:

可以很清晰的看到,绿框中元素与所对应的下标是相等的,而紫框中的元素与下标是不同的,这里就体现了二段性,我们要找的就是下标为4的这个位置

①arr[mid] == mid,表示此时在绿框中,需要改变left,即left = mid + 1
②arr[mid] != mid,表示此时在紫框中,需要改变right,并且mid可能是答案,所以right = mid

需要注意边界情况,如果数组是0,1,2,3,4这样的类型,缺了一个5,此时我们按照上述的情况使用二分查找算法,会使得最终的left指向4这个值的下标,所以我们需要最后比较一下,left所对应的值和left是否相等, 如果相等就表示是这种特殊情况,需要进行特殊处理

代码如下:

class Solution {
public:
    int takeAttendance(vector<int>& records) {
        int left = 0,right = records.size()-1;
        while(left < right)
        {
            int mid = left + (right - left) / 2;
            if(records[mid] == mid) left = mid + 1;
            else right = mid;
        }
        //处理细节
        return records[left] == left ? left + 1 : left;
    }
};

二分查找题目到此结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1694513.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL select for update 加锁

背景 当多人操作同一个客户下账号的时候&#xff0c;希望顺序执行&#xff0c;某个时刻只有一个人在操作&#xff1b;当然可以通过引入redis这种中间件实现&#xff0c;但考虑到并发不会很多&#xff0c;所以不想再引入别的中间件。 表结构 create table jiankunking_accoun…

amis 联动效果触发的几种方式

联动效果实现主要俩种方式: 1.表达式实现联动,基于组件内或数据链的变量变化的联动 比如&#xff1a; "source": "/amis/api/mock2/options/level2?name${name} " (必须是这种字符串拼接形式,在data数据映射中表达式不会触发联动) 所有初始化接口链…

【FPGA】Verilog:解码器 | 编码器 | 多路复用器(Mux, Multiplexer)

0x00 什么是解码器 解码器是根据输入信号在多个输出位中选择一个输出位的装置。例如,当解码器接收2位二进制值作为输入时,它可以接收00、01、10、11四种输入值,并根据每个输入值在4个输出位中选择一个,输出为1000、0100、0010、0001中的一种。这样的解码器被称为高电平有效…

【数据挖掘】四分位数识别数据中的异常值(附代码)

写在前面&#xff1a; 首先感谢兄弟们的订阅&#xff0c;让我有创作的动力&#xff0c;在创作过程我会尽最大能力&#xff0c;保证作品的质量&#xff0c;如果有问题&#xff0c;可以私信我&#xff0c;让我们携手共进&#xff0c;共创辉煌。 路虽远&#xff0c;行则将至&#…

Android四大组件 Broadcast广播机制

一 概述 广播 (Broadcast) 机制用于进程或线程间通信&#xff0c;广播分为广播发送和广播接收两个过程&#xff0c;其中广播接收者 BroadcastReceiver 是 Android 四大组件之一。BroadcastReceiver 分为两类&#xff1a; 静态广播接收者&#xff1a;通过 AndroidManifest.xm…

开源模型应用落地-食用指南-以最小成本博最大收获

一、背景 时间飞逝&#xff0c;我首次撰写的“开源大语言模型-实际应用落地”专栏已经完成了一半以上的内容。由衷感谢各位朋友的支持,希望这些内容能给正在学习的朋友们带来一些帮助。 在这里&#xff0c;我想分享一下创作这个专栏的初心以及如何有效的&#xff0c;循序渐进的…

机器视觉-硬件

机器视觉-硬件 镜头焦距凸透镜焦点不止一个相机镜头由多个镜片组成对焦和变焦 镜头光圈光圈的位置光圈系数F 镜头的景深景深在光路中的几何意义 远心镜头远心镜头的种类远心镜头特性应用场景 镜头的分辨率镜头反差镜头的MTF曲线镜头的靶面尺寸镜头的几何相差相机镜头接口螺纹接…

私域流量的真谛:构建并运营属于你自己的私域生态

大家好&#xff0c;我是来自一家专注于私域电商行业的软件开发公司的产品经理&#xff0c;拥有超过七年的行业经验。今天&#xff0c;我想和大家聊聊私域流量的真正含义&#xff0c;以及为何我们应该关注并努力打造属于自己的私域生态。 什么是私域流量&#xff1f; 私域流量&…

文心大模型4.0创建智能体:资深研发专家一对一辅导

目录 前言 一、什么是文心智能体平台&#xff1f; 1、通过平台能做什么 2、平台的优势 3、智能体类型 二、如何访问和使用这个智能体&#xff1f; 1、零代码开发&#xff1a;一句话创建智能体 2、资深研发专家一对一辅导智能体介绍 总结 前言 在当今快节奏和高度竞争的…

【高时效通路】

一 高时效通路 1.1 pathchdumper 实时数据拉取、实时数据处理、5分钟微批dump来加速时效性&#xff0c;具体来说&#xff1a; 实时数据拉取&#xff08;Fetcher&#xff09;&#xff1a;基于Databus Fetcher基建&#xff0c;直接对接F0层实时拉取最新数据&#xff0c;保证该…

哥白尼哨兵系列卫星数据不能下载的解决方法

自2023年1月24日起&#xff0c;一个新的哥白尼数据空间生态系统已经启动&#xff0c;为所有哨兵数据&#xff08;Sentinel-1, Sentinel-2, Sentinel-3 and Sentinel-5P&#xff09;提供可视化和数据处理&#xff0c;地址为&#xff1a;https://dataspace.copernicus.eu/。详细介…

Linux驱动(2)---Linux内核的组成

1.Linux内核源码目录 arch包含和硬件体系相关结构相关源码&#xff0c;每个平台占用一个目录 block&#xff1a;块设备驱动程序I/O调度 crypto&#xff1a;常用加密和三列算法&#xff0c;还有一些压缩和CRC校验算法。 documentation:内核个部分的通用解释和注释.。 drive…

护眼小贴士:学生如何正确使用台灯?

随着电子设备的普及和长时间的用眼&#xff0c;长时间盯着屏幕或学习&#xff0c;眼睛需要不断调节焦距&#xff0c;导致眼睛肌肉疲劳&#xff0c;进而引发视力下降。这种现象在年轻一代甚至青少年中尤为普遍&#xff0c;这种疲劳状态不仅影响眼睛的舒适度&#xff0c;还会导致…

【Linux】网络层——IP协议

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;Linux 目录 &#x1f449;&#x1f3fb;IP协议基本概念&#x1f449;&#x1f3fb;IP的协议头格式&#x1f449;&#x1f3fb;IP协议的网段划分五类IP地址子…

fastapi中实现多个路由请求

大家伙&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 前言 最近在写机器人相关的接口&#xff0c;顺手学了学python&#xff0c;发现这是个好东西&#xff0c;写代码效率比java要高很多&#xff0c;比如写个词云呀&#xff0c;写个回调呀&am…

从参数变化解读 MySQL 8.2.0 发版说明

↑ 关注“少安事务所”公众号&#xff0c;欢迎⭐收藏&#xff0c;不错过精彩内容~ 日前&#xff0c;MySQL 8.2.0 创新版本已正式上线&#xff0c;并提供安装包下载&#xff0c;但 docker 镜像尚未更新。 在 MySQL 8.1.0 刚发版时也做过分析&#xff0c;欢迎阅读&#xff1a; 重…

云部署最简单python web

最近在玩云主机&#xff0c;考虑将简单的web应用装上去&#xff0c;通过广域网访问一下&#xff0c;代码很简单&#xff0c;所以新手几乎不会碰到什么问题。 from flask import Flaskapp Flask(__name__)app.route(/) def hello_world():return Hello, World!app.route(/gree…

html通过数据改变,图片跟着改变

改变前 改变后 通过数据来控制样式展示 <template><div>通过num控制图标是否更改{{num}}<div class"box"><!-- 如果num大于1则是另一种&#xff0c;样式&#xff0c;如果小时1&#xff0c;则是另一种样式 --><div class"item&qu…

字节面试:百亿级数据存储,怎么设计?只是分库分表吗?

尼恩&#xff1a;百亿级数据存储架构起源 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;经常性的指导小伙伴们改造简历。 经过尼恩的改造之后&#xff0c;很多小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试机会&#xff0c…

WGCLOUD可以使用短信告警通知吗

支持的 以下是官网的说明 告警报警配置说明 - WGCLOUD