【优选算法篇】寻找隐藏的宝藏:用二分查找打开算法世界的大门(上篇)
文章目录
须知
💬 欢迎讨论:如果你在学习过程中有任何问题或想法,欢迎在评论区留言,我们一起交流学习。你的支持是我继续创作的动力!
👍 点赞、收藏与分享:觉得这篇文章对你有帮助吗?别忘了点赞、收藏并分享给更多的小伙伴哦!你们的支持是我不断进步的动力!
🚀 分享给更多人:如果你觉得这篇文章对你有帮助,欢迎分享给更多对C++算法感兴趣的朋友,让我们一起进步!
1. C++ 二分查找算法 详解
1.1 二分查找算法的重要性
二分查找(Binary Search)是一种经典的算法,广泛应用于计算机科学中,尤其在处理有序数据时。其重要性体现在以下几个方面:
-
高效性:
- 时间复杂度为 O(logn),相比于线性搜索的 O(n),在大规模数据集上,性能提升显著。
- 特别适用于查找频繁的场景,如搜索引擎、数据库索引等。
-
普适性:
- 不仅可以应用于查找问题,还能扩展到解决复杂问题,如求解特定函数值、二分答案法、优化问题的解空间收缩等。
-
简洁性:
- 算法简单易实现,逻辑清晰,适合初学者掌握编程和算法的基本思想。
- 二分查找思想可以扩展到多种变体(如上下界查找、最优解逼近等)。
-
应用广泛:
- 排序数组中的查找问题。
- 数学问题求解(如平方根、最大值最小化等)。
- 各种问题优化(如动态规划中的状态转移点查找)。
1.2 什么是二分查找算法?
二分查找是一种在 有序数组 中查找目标值的算法。通过每次将查找范围缩小一半,逐步逼近目标值的位置。
定义核心:
- 二分查找的目标是利用有序性,将搜索范围逐步减少到最小。
- 通过比较中间值与目标值,决定在左右半区继续搜索。
1.3 核心思想
核心思想可以概括为“分而治之”:
-
缩小搜索范围:
- 每次比较目标值和中间值,根据有序性决定继续查找左半部分还是右半部分,排除另一半不可能的区域。
-
递归或迭代:
- 通过递归或迭代实现搜索范围不断缩小。
- 最终在可能的区间中找到目标值(或者确认目标值不存在)。
-
有序性约束:
- 二分查找仅适用于有序数组(或可以逻辑上排序的空间),是其适用性的前提。
二分查找的基本步骤
-
初始化范围:
- 定义左右边界
left
和right
,初始为数组的起点和终点。
- 定义左右边界
-
计算中点:
- 根据公式
mid = left + (right - left) / 2
计算中间索引,避免溢出。
- 根据公式
-
判断目标值:
- 如果目标值等于中点值,直接返回。
- 如果目标值小于中点值,缩小右边界
right = mid - 1
。 - 如果目标值大于中点值,缩小左边界
left = mid + 1
。
-
退出条件:
- 当
left > right
时,说明目标值不存在,结束搜索。
- 当
1.4 二分查找的典型应用
- 数组查找:
- 在排序数组中快速查找目标值。
- 上/下界查找:
- 查找目标值的第一个或最后一个出现位置。
- 函数值逼近:
- 在某范围内寻找特定条件满足的最优值。
- 复杂问题解空间缩减:
- 如动态规划中的优化问题(状态转移优化)。
2. 二分查找算法模版
2.1 标准二分查找模板
用于在 有序数组 中查找某个目标值。
int binarySearch(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;while (left <= right) { // 搜索区间为 [left, right]int mid = left + (right - left) / 2; // 避免溢出if (nums[mid] == target) {return mid; // 找到目标值,返回索引} else if (nums[mid] < target) {left = mid + 1; // 缩小到右半部分} else {right = mid - 1; // 缩小到左半部分}}return -1; // 未找到目标值
}
特点:
- 适用场景:查找目标值,返回其索引。
- 退出条件:当
left > right
时,说明目标值不存在。 - 时间复杂度:O(logn)。
2.2 查找左侧边界的二分查找
查找目标值的 最左位置。
int lowerBound(vector<int>& nums, int target) {int left = 0, right = nums.size();while (left < right) { // 搜索区间为 [left, right)int mid = left + (right - left) / 2;if (nums[mid] < target) {left = mid + 1; // 缩小到右半部分} else {right = mid; // 缩小到左半部分}}return left; // 返回左边界
}
- 如果目标值存在,返回其左边界索引。
- 如果目标值不存在,返回插入位置。
- 适用场景:查找目标值的第一个出现位置,或者获取目标值插入有序数组的位置。
2.3 查找右侧边界的二分查找
查找目标值的 最右位置。
int upperBound(vector<int>& nums, int target) {int left = 0, right = nums.size();while (left < right) { // 搜索区间为 [left, right)int mid = left + (right - left) / 2;if (nums[mid] <= target) {left = mid + 1; // 缩小到右半部分} else {right = mid; // 缩小到左半部分}}return left - 1; // 返回右边界索引
}
特点:
- 如果目标值存在,返回其右边界索引。
- 如果目标值不存在,返回小于目标值的最大元素位置。
2.4 查找目标值范围(二分查找综合模板)
同时查找目标值的左、右边界(适用于数组中目标值重复出现)。
vector<int> searchRange(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;// 查找左边界int start = -1, end = -1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] >= target) {right = mid - 1;} else {left = mid + 1;}}if (left < nums.size() && nums[left] == target) {start = left;} else {return {-1, -1}; // 目标值不存在}// 查找右边界left = 0, right = nums.size() - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] <= target) {left = mid + 1;} else {right = mid - 1;}}end = right;return {start, end};
}
特点:
- 适用于查找区间
[start, end]
。 - 如果目标值不存在,返回
{-1, -1}
。
2.5 二分答案法模板
适用于需要在范围内找到满足某种条件的最优解。
int binaryAnswer(int low, int high, function<bool(int)> condition) {while (low < high) {int mid = low + (high - low) / 2;if (condition(mid)) {high = mid; // 满足条件,收缩右边界} else {low = mid + 1; // 不满足条件,收缩左边界}}return low; // 返回最小满足条件的值
}
特点:
- 通过逻辑条件函数
condition(mid)
判断是否满足目标。 - 常用于优化问题,如最大值最小化、最小值最大化等。
2.6 常见边界问题注意点
-
搜索区间是否包含
right
:[left, right]
区间通常用于包含上下界查找。[left, right)
区间通常用于统一逻辑,更适合下界查找。
-
mid
计算防止溢出:- 使用
mid = left + (right - left) / 2
。
- 使用
-
退出条件的灵活性:
- 对于不同区间范围和边界需求,
while (left <= right)
和while (left < right)
需区别对待。
- 对于不同区间范围和边界需求,
2.7 总结
- 标准模板:快速定位目标值。
- 变体模板:查找上下界或目标值范围。
- 扩展模板:适用于更复杂的优化问题。 掌握不同场景下的二分查找模板,能够快速高效解决查找与优化问题。
3. 题目1:二分查找
题目链接:704. 二分查找 - 力扣(LeetCode)
题目描述:
3.1 算法思路:
核心思想
利用 二分查找算法,在有序数组中查找目标值。每次通过比较中间值与目标值的大小,缩小搜索范围,直到找到目标值或搜索范围为空。
3.1.1 具体步骤
-
初始化搜索范围:
- 左边界
left
初始化为数组起点0
。 - 右边界
right
初始化为数组终点nums.size() - 1
。
- 左边界
-
二分循环查找:
- 当
left <= right
时:- 计算中间索引
mid = left + (right - left) / 2
(避免整数溢出)。 - 如果
nums[mid] == target
,直接返回索引mid
。 - 如果
nums[mid] < target
,目标值在右半部分,将left
更新为mid + 1
。 - 如果
nums[mid] > target
,目标值在左半部分,将right
更新为mid - 1
。
- 计算中间索引
- 当
-
返回结果:
- 如果退出循环仍未找到目标值,返回
-1
。
- 如果退出循环仍未找到目标值,返回
3.2 示例代码:
class Solution {
public:int search(vector<int>& nums, int target) {int left = 0, right = nums.size() - 1;while (left <= right) { // 搜索区间为 [left, right]int mid = left + (right - left) / 2; // 计算中点,防止溢出if (nums[mid] == target) {return mid; // 找到目标值,返回索引} else if (nums[mid] < target) {left = mid + 1; // 目标值在右半部分} else {right = mid - 1; // 目标值在左半部分}}return -1; // 未找到目标值}
};
3.2.1 示例解析
示例 1:
输入:nums = [-1, 0, 3, 5, 9, 12], target = 9 输出:4
执行过程:
- 初始化:
left = 0
,right = 5
。 - 第 1 步:
mid = (0 + 5) / 2 = 2
,nums[mid] = 3 < 9
,更新left = 3
。 - 第 2 步:
mid = (3 + 5) / 2 = 4
,nums[mid] = 9 == 9
,返回索引4
。
3.3 时间与空间复杂度
3.3.1 时间复杂度:
- O(log n):
- 每次迭代将搜索范围缩小一半,因此时间复杂度是对数级别。
3.3.2 空间复杂度:
- O(1):
- 只使用了常数空间,无额外数组或递归调用栈。
边界条件分析
- 空数组:
- 如果
nums
为空,right = nums.size() - 1 = -1
,循环直接跳过,返回-1
。
- 如果
- 目标值不在数组中:
- 如果目标值不在数组中,循环最终会将
left > right
,返回-1
。
- 如果目标值不在数组中,循环最终会将
- 目标值在边界:
- 如果目标值是数组中的最小值或最大值,算法可以正确返回索引。
3.4 补充(可看可不看)
暴力解法
3.4.1 暴力解法思路
暴力解法的核心是直接遍历数组 nums
中的每一个元素,逐一与目标值 target
进行比较,直到找到目标值或遍历结束。
3.4.2 具体步骤
- 遍历数组:
- 从左到右逐一访问数组中的每一个元素。
- 比较当前元素与目标值:
- 如果当前元素等于目标值,返回当前索引。
- 返回结果:
- 如果遍历结束仍未找到目标值,返回
-1
表示目标值不存在。
- 如果遍历结束仍未找到目标值,返回
3.4.3 示例代码:
class Solution {
public:int search(vector<int>& nums, int target) {for (int i = 0; i < nums.size(); i++) {if (nums[i] == target) {return i; // 找到目标值,返回索引}}return -1; // 未找到目标值}
};
3.4.4 时间与空间复杂度
时间复杂度:
- 最坏情况:
- 当目标值位于数组末尾或者不存在时,需要遍历整个数组,时间复杂度为 O(n),其中 n 是数组长度。
- 最佳情况:
- 当目标值是数组中的第一个元素时,时间复杂度为 O(1)。
- 平均情况:
- O(n),因为没有利用数组的有序性。
空间复杂度:
- O(1):
- 只使用了常量级别的额外空间,没有引入新的数据结构。
暴力解法的优缺点
优点:
- 简单直接:
- 实现简单,逻辑清晰。
- 对初学者友好,无需理解复杂算法。
- 通用性强:
- 无需假设数组是有序的,可直接用于任意数组。
缺点:
- 效率低下:
- 对于大规模数组,时间复杂度 O(n) 远高于二分查找的 O(logn)。
- 未利用数组的有序性,性能不佳。
- 不符合题目要求:
- 题目中数组是有序的,暴力解法没有利用这一特性。
3.4.5 与二分查找对比
3.4.6 总结:
- 暴力解法逻辑简单,适合入门或小规模数据场景。
- 二分查找则充分利用了有序数组的特性,更适合大规模查找,性能更优。
3.5 总结:
- 算法思路:利用有序数组的性质,每次缩小搜索范围,逐步找到目标值或确定其不存在。
- 时间复杂度:O(logn),适合大规模数据的查找。
- 边界处理:代码能够正确处理空数组、目标值不在数组中、目标值在边界等特殊情况。
4. 题目2:在排序数组中查找元素的第一个和最后一个位置
题目链接:34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
题目描述:
4.1 算法思路:
这道题的核心是利用 二分查找 在排序数组中分别找到目标值的左右边界。
1. 核心思想
-
找到左边界(第一个等于
target
的元素的索引)。 -
找到右边界(最后一个等于
target
的元素的索引)。 -
如果找不到目标值,直接返回
[-1, -1]
。
2. 使用两次二分查找
-
查找左边界:定位目标值在数组中的最左位置。
-
查找右边界:定位目标值在数组中的最右位置。
4.2 示例代码:
class Solution {
public:vector<int> searchRange(vector<int>& nums, int target) {// 查找左边界int left = 0, right = nums.size() - 1;int leftIndex = -1, rightIndex = -1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] >= target) {right = mid - 1;} else {left = mid + 1;}}if (left < nums.size() && nums[left] == target) {leftIndex = left;} else {return {-1, -1}; // 如果左边界不存在,直接返回}// 查找右边界left = 0, right = nums.size() - 1;while (left <= right) {int mid = left + (right - left) / 2;if (nums[mid] <= target) {left = mid + 1;} else {right = mid - 1;}}if (right >= 0 && nums[right] == target) {rightIndex = right;}return {leftIndex, rightIndex};}
};
详细步骤
4.2.1 查找左边界
- 初始化
left = 0
,right = nums.size() - 1
。 - 在循环中,通过二分查找找到第一个大于或等于
target
的位置:- 如果
nums[mid] < target
,则目标值在右侧,调整left = mid + 1
。 - 如果
nums[mid] >= target
,则调整right = mid - 1
。
- 如果
- 最后检查
nums[left]
是否等于target
,如果相等,返回left
,否则返回-1
。
4.2.2 查找右边界
- 初始化
left = 0
,right = nums.size() - 1
。 - 在循环中,通过二分查找找到最后一个小于或等于
target
的位置:- 如果
nums[mid] > target
,则目标值在左侧,调整right = mid - 1
。 - 如果
nums[mid] <= target
,则调整left = mid + 1
。
- 如果
- 最后检查
nums[right]
是否等于target
,如果相等,返回right
,否则返回-1
。
示例解析
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
执行过程:
- 查找左边界:
- 初始范围:
left = 0, right = 5
。 - 第一次:
mid = 2
,nums[2] = 7 < 8
,更新left = 3
。 - 第二次:
mid = 4
,nums[4] = 8
,更新right = 3
。 - 第三次:
mid = 3
,nums[3] = 8
,更新right = 2
。 - 左边界为
3
。
- 初始范围:
- 查找右边界:
- 初始范围:
left = 0, right = 5
。 - 第一次:
mid = 2
,nums[2] = 7 < 8
,更新left = 3
。 - 第二次:
mid = 4
,nums[4] = 8
,更新left = 5
。 - 第三次:
mid = 5
,nums[5] = 10 > 8
,更新right = 4
。 - 右边界为
4
。
- 初始范围:
输出:
[3,4]
4.3 时间与空间复杂度
4.3.1 时间复杂度
- 每次二分查找的时间复杂度为 O(logn)。
- 两次二分查找,总时间复杂度为 O(2⋅logn)=O(logn)。
4.3.2 空间复杂度
- 只使用常量级额外空间,空间复杂度为 O(1)。
4.4 总结:
-
算法特点:
- 使用二分查找分别找到左边界和右边界。
- 时间复杂度 O(logn),适合大规模数据。
- 空间复杂度 O(1),仅使用常量级变量。
-
代码结构清晰:
- 两次独立的二分查找,易于理解和调试。
-
特殊情况处理:
- 数组为空或目标值不存在时,返回
[-1, -1]
。
- 数组为空或目标值不存在时,返回
5. 题目3:搜索插入位置
题目链接:35. 搜索插入位置 - 力扣(LeetCode)
题目描述:
5.1 算法思路:
核心思想:二分查找
由于数组是升序排序的,因此可以使用二分查找在 O(logn) 时间复杂度内找到目标值的插入位置。
5.2 示例代码:
class Solution
{
public:int searchInsert(vector<int>& nums, int target) {// 定义左右边界int left = 0, right = nums.size() - 1;// 特殊情况:如果目标值大于数组中所有元素,则插入到数组末尾if (nums[right] < target) return right + 1;// 二分查找while (left < right) {// 计算中间位置,避免溢出int mid = left + (right - left) / 2;// 如果中间值小于目标值,目标值在右半部分if (nums[mid] < target) left = mid + 1; // 调整左边界else // 如果中间值大于等于目标值,目标值可能在左半部分right = mid; // 调整右边界}// 最终 left == right,返回插入位置return left;}
};
5.2.1 注释内容说明
-
特殊处理(
nums[right] < target
):- 如果目标值大于数组中的最大值,则目标值一定插入到数组末尾。
- 为了提高效率,先检查这一特殊情况。
-
二分查找核心:
- 使用
while (left < right)
循环,通过不断缩小区间找到目标值或插入位置。 - 使用
mid = left + (right - left) / 2
计算中点,避免left + right
的溢出问题。
- 使用
-
区间调整逻辑:
- 当
nums[mid] < target
时,说明目标值在右半部分,更新左边界left = mid + 1
。 - 否则,目标值在左半部分或
nums[mid] == target
,更新右边界right = mid
。
- 当
-
最终返回:
- 循环退出时,
left == right
,此时left
即为目标值所在位置或插入位置。
- 循环退出时,
5.3 时间与空间复杂度
- 时间复杂度:O(logn)
- 二分查找每次将搜索范围缩小一半,复杂度是对数级。
- 空间复杂度:O(1)
- 无额外空间开销。
5.4 补充(可看可不看)
5.4.1 暴力解法
暴力解法的核心是 直接遍历数组:
- 遍历数组中的每个元素,与目标值
target
进行比较。 - 如果找到一个元素大于或等于目标值,返回该元素的索引。
- 如果遍历结束仍未找到,说明目标值比数组中所有元素都大,返回数组的长度。
这种方法时间复杂度是 O(n),适合小规模数组。
5.4.2 示例代码:
class Solution
{
public:int searchInsert(vector<int>& nums, int target) {for (int i = 0; i < nums.size(); i++) {// 如果找到第一个大于或等于目标值的位置,返回索引if (nums[i] >= target) return i;}// 如果目标值比所有元素都大,返回数组长度return nums.size();}
};
5.4.3 示例解析
示例 1:
输入:nums = [1, 3, 5, 6], target = 5 输出:2
执行过程:
- 遍历到
nums[0] = 1
,1 < 5
,继续。 - 遍历到
nums[1] = 3
,3 < 5
,继续。 - 遍历到
nums[2] = 5
,5 >= 5
,返回索引2
。
5.4.4 时间与空间复杂度
时间复杂度:
- 最坏情况:目标值比数组所有元素都大,需要遍历整个数组,时间复杂度为 O(n)。
- 最佳情况:目标值小于数组第一个元素,直接返回索引
0
,时间复杂度为 O(1)。
空间复杂度:
- O(1):不需要额外的存储空间。
优缺点分析
优点:
-
简单直接,易于实现。
-
适合小规模数组的情况。
缺点:
- 时间复杂度较高,不适合大规模数组。
- 没有利用数组的有序性,效率较低。
5.5 总结:
-
关键点:
- 明确目标值可能是数组中的一个元素,也可能是插入的位置。
- 使用二分查找,高效缩小范围。
- 返回
left
即为插入位置。
-
扩展场景:
- 如果需要返回目标值的插入位置,同时要求区分左、右边界,可以进一步扩展这段代码逻辑。
6. 题目4:x的平方根
题目链接:69. x 的平方根 - 力扣(LeetCode)
题目描述:
6.1 算法思路:
6.1.1 问题本质
我们要找到满足以下条件的最大整数 y
:
- y2≤x
- (y+1)2>x
6.1.2 核心思想
利用 二分查找 来寻找平方根:
-
二分查找的搜索区间是
[1, x]
(因为 x\sqrt{x}x 最大不会超过x
本身)。 -
每次取中点
mid
,计算 mid2 与x
比较:- 如果 mid2 ≤ x,说明平方根在右侧,更新
left = mid
。 - 如果 mid2 > x,说明平方根在左侧,更新
right = mid - 1
。
- 如果 mid2 ≤ x,说明平方根在右侧,更新
-
循环退出时,
left
指向平方根的整数部分。
6.2 示例代码:
class Solution
{
public:int mySqrt(int x) {if (x < 1) return 0; // 特殊情况处理int left = 1, right = x; // 定义二分查找的边界while (left < right) {long long mid = left + (right - left + 1) / 2; // 向上取整计算中点if (mid * mid > x) right = mid - 1; // 排除右半部分else left = mid; // 更新左边界,保留 mid}return left; // 最终返回平方根的整数部分}
};
版本2:
class Solution
{
public:int mySqrt(int x) {if (x == 0) return 0; // 直接处理特殊情况int left = 1, right = x;while (left <= right) // 使用闭区间 [left, right]{int mid = left + (right - left) / 2;if (mid <= x / mid) // 避免溢出left = mid + 1; // 更新左边界elseright = mid - 1; // 更新右边界}return right; // 返回右边界,即平方根整数部分}
};
6.2.1 关键点解析
-
初始化区间:
- 区间为
[1, x]
,因为平方根不会小于 1 且不会大于x
(对于 x≥1)。
- 区间为
-
中点计算:
- 使用
mid = left + (right - left + 1) / 2
来计算中点,避免直接加法可能导致的溢出。 - 向上取整 的目的是保证当区间只有两个元素时,选择靠右的中点,从而能够正确排除区间。
- 使用
-
更新区间:
- 如果 mid2>x:
right = mid - 1
,排除当前的mid
和右侧部分。 - 如果 mid2<=x:
left = mid
,保留当前的mid
。
- 如果 mid2>x:
-
返回值:
- 循环退出条件是
left == right
,此时left
即为平方根的整数部分。
- 循环退出条件是
6.3 补充(可看可不看)
暴力解法
6.3.1 示例代码:
class Solution
{
public:int mySqrt(int x) {if (x == 0) return 0; // 特殊情况处理int y = 0;while ((long long)y * y <= x) // 防止溢出{y++;}return y - 1; // 返回满足条件的最大整数}
};
6.3.2 时间与空间复杂度
时间复杂度
-
最坏情况:如果 x 很大(如 x = 10^9),暴力解法需要从
0
遍历到 x\sqrt{x},因此时间复杂度为 O(x\sqrt{x})。 -
最佳情况:如果 x=0 或 x=1,复杂度为 O(1)。
空间复杂度
- O(1):仅使用了常量级别的变量
y
和计算,不需要额外空间。
优缺点分析
优点
-
简单直观:
-
不依赖复杂的算法逻辑,直接枚举。
-
易于理解和实现。
-
-
无特殊处理:
-
不需要处理二分查找的边界条件,也无需考虑浮点数计算误差。
-
缺点
-
效率低下:
- 时间复杂度为 O(\sqrt{x}),对于较大的 x(如 10^9),效率明显低于二分查找法的 O(logx)。
-
对大数的适用性差:
- 如果没有使用
long long
类型,会因为 y2 的溢出问题导致错误结果。
- 如果没有使用
6.4 时间与空间复杂度
6.4.1 时间复杂度
- 二分查找的时间复杂度是 O(logx),因为每次迭代将搜索区间缩小一半。
6.4.2 空间复杂度
- 只使用了常量额外空间,空间复杂度是 O(1)。
6.5 对比
6.6 总结
-
算法思想:
- 二分查找用于在区间
[1, x]
中寻找满足 y2≤x 的最大整数y
。
- 二分查找用于在区间
-
复杂度:
- 时间复杂度 O(logx),空间复杂度 O(1)。
-
注意事项:
- 需要特别处理
x = 0
和x = 1
等特殊情况。 - 通过
mid <= x / mid
避免溢出问题。
- 需要特别处理
6.7 最后
通过上述例题分析可以看出,二分查找的核心用途是 快速缩小搜索范围,解决有序数据、边界条件和单调问题等场景。在实际问题中,熟练掌握二分查找模板和变体是解决高效算法问题的关键。
路虽远,行则将至;事虽难,做则必成
亲爱的读者们,下一篇文章再会!!!
相关文章:

【优选算法篇】寻找隐藏的宝藏:用二分查找打开算法世界的大门(上篇)
文章目录 须知 💬 欢迎讨论:如果你在学习过程中有任何问题或想法,欢迎在评论区留言,我们一起交流学习。你的支持是我继续创作的动力! 👍 点赞、收藏与分享:觉得这篇文章对你有帮助吗࿱…...

基于Vue实现的移动端手机商城项目 电商购物网站 成品源码
📂文章目录 一、📔网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站演示 📸部分截图 🎬视频演示 五、⚙️网站代码 🧱项目结构 💒vue代码预览 六、🔧完整…...

C语言:数组
数组 数组的概念 引例 如果我们要在程序中表示一个学生的成绩,我们会使用一个int来表示,如:int score。假如我们要在程序中表示一组成绩,此时我们所学的常规的数据类型就无法再表示,这个时候我们就需要使用一种新的…...

时间序列预测之FiLM
没错,就是看电影 文章目录 前言1. 问题描述2. 创新之处3. 贡献 一、时间序列在legende - fourier域的表示1. 勒让德投影2. 傅里叶变换 二、 模型结构1. LPU: Legendre Projection Unit2. FEL: Frequency Enhanced Layer3. 多尺度专家机制的混合 二、实验结果长时预测…...

【机器学习】窥数据之序,悟算法之道:机器学习的初心与远方
文章目录 机器学习入门:从零开始学习基础与应用前言第一部分:什么是机器学习?1.1 机器学习的定义1.1.1 举个例子:垃圾邮件分类器 1.2 机器学习的核心思想1.2.1 数据驱动的模式提取1.2.2 为什么机器学习比传统方法更灵活࿱…...

OpenCL介绍
OpenCL(Open Computing Language)详解 OpenCL 是一个开源的框架,用于编写在异构平台(包括中央处理单元(CPU)、图形处理单元(GPU)、数字信号处理器(DSP)和其他…...

「Mac畅玩鸿蒙与硬件42」UI互动应用篇19 - 数字键盘应用
本篇将带你实现一个数字键盘应用,支持用户通过点击数字键输入数字并实时更新显示内容。我们将展示如何使用按钮组件和状态管理来实现一个简洁且实用的数字键盘。 关键词 UI互动应用数字键盘按钮组件状态管理用户交互 一、功能说明 数字键盘应用将实现以下功能&…...

【前端知识】npm命令行详细说明
npm命令行详细说明 概述一、定义与功能二、基本命令三、配置文件与注册表四、应用场景五、高级特性 环境设置1. 设置镜像源2. 配置全局依赖存储路径3. 配置缓存路径4. 查看所有配置5. 清除缓存6. 升级npm版本 npm组件打包1. 初始化项目2. 安装依赖3. 构建脚本4. 打包项目5. 发布…...

Python网络爬虫技术详解与实践案例
Python网络爬虫技术详解与实践案例 在大数据和人工智能盛行的今天,数据的获取与分析成为许多项目和业务的关键。网络爬虫作为一种自动化的数据采集工具,广泛应用于数据挖掘、市场分析、情报收集等领域。本文将详细介绍Python网络爬虫的基本概念、工作流程、进阶技巧,并附上…...

【遥感目标检测综述】【GRSS】遥感目标检测与深度学习的相遇:挑战与进展的元综述
Remote Sensing Object Detection Meets Deep Learning: A Meta-review of Challenges and Advances 遥感目标检测与深度学习的相遇:挑战与进展的元综述 论文链接 0.论文摘要和作者信息 摘要 遥感目标检测(RSOD)是遥感领域最基…...

【大数据技术基础】 课程 第3章 Hadoop的安装和使用 大数据基础编程、实验和案例教程(第2版)
第3章 Hadoop的安装和使用 3.1 Hadoop简介 Hadoop是Apache软件基金会旗下的一个开源分布式计算平台,为用户提供了系统底层细节透明的分布式基础架构。Hadoop是基于Java语言开发的,具有很好的跨平台特性,并且可以部署在廉价的计算机集群中。H…...
【机器学习】机器学习的基本分类-监督学习-决策树-C4.5 算法
C4.5 是由 Ross Quinlan 提出的决策树算法,是对 ID3 算法的改进版本。它在 ID3 的基础上,解决了以下问题: 处理连续型数据:支持连续型特征,能够通过划分点将连续特征离散化。处理缺失值:能够在特征值缺失的…...

云计算vsphere 服务器上添加主机配置
这里是esxi 主机 先把主机打开 然后 先开启dns 再开启 vcenter 把每台设备桌面再vmware workstation 上显示 同上也是一样 ,因为在esxi 主机的界面可能有些东西不好操作 我们选择主机和集群 左边显示172.16.100.200...

Linux笔记---进程:进程替换
1. 进程替换的概念 进程替换是指在一个正在运行的进程中,用一个新的程序替换当前进程的代码和数据,使得进程开始执行新的程序,而不是原来的程序。 这种技术通常用于在不创建新进程的情况下,改变进程的行为。 我们之前谈到过for…...

量化交易backtrader实践(五)_策略综合篇(1)_股票软件指标回测
在第三章6到9节,我们学习和实践了大部分股票软件指标,且这些指标是backtrader内置指标实践中没有讲到过的。然后,在进行策略综合之前,我们先热个身,把一些可能比较有参考意义的股票软件内置指标在backtrader里给实现了…...

4.STM32通信接口之SPI通信(含源码)---软件SPI与W25Q64存储模块通信实战《精讲》
经过研究SPI协议和W25Q64,逐步了解了SPI的通信过程,接下来,就要进行战场实战了!跟进Whappy步伐! 目标:主要实现基于软件的SPI的STM32对W25Q64存储写入和读取操作! 开胃介绍(代码基本…...

MINDAGENT:游戏交互中的新兴性设计
一、摘要 1.问题/研究背景 LLM具有在多智能体系统中执行复杂调度的能力,并可以协调这些代理以完成需要广泛合作的复杂任务。 但是,目前还没有一个标准的游戏场景和相关的测试指标来评估 LLM 在游戏中的表现以及与人类玩家的合作能力。 2.研究目标/动…...

【工具变量】上市公司企业所在地城市等级直辖市、副省级城市、省会城市 计划单列市(2005-2022年)
一、包含指标: 股票代码 股票代码 股票简称 年份 所属城市 直辖市:企业所在地是否属于直辖市。1是,0否。 副省级城市:企业所在地是否属于副省级城市。1是,0否。 省会城市&a…...

C# 动态类型 Dynamic
文章目录 前言1. 什么是 Dynamic?2. 声明 Dynamic 变量3. Dynamic 的运行时类型检查4. 动态类型与反射的对比5. 使用 Dynamic 进行动态方法调用6. Dynamic 与 原生类型的兼容性7. 动态与 LINQ 的结合8. 结合 DLR 特性9. 动态类型的性能考虑10. 何时使用 Dynamic&…...

Css动画:旋转相册动画效果实现
🌈个人主页:前端青山 🔥系列专栏:Css篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Css篇专栏内容:Css动画:旋转相册动画效果实现 前言 随着Web技术的发展,网页不再局限于静态展示&#…...

Unity 基于Collider 组件在3D 物体表面放置3D 物体
实现 从鼠标点击的屏幕位置发送射线,以射线监测点击到的物体,根据点击物体的法线向量调整放置物体的位置及朝向。 Ray ray Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out RaycastHit hit, 100)) {obj.transform.…...

Hbase整合Mapreduce案例1 hdfs数据上传至hbase中——wordcount
目录 整合结构准备java API 编写pom.xmlMain.javaMap.javaReduce 运行 整合结构 准备 上传hdfs data.txt数据 data.txt I am wunaiieq QAQ 123456 Who I am In todays interconnected world the role of technology cannot be overstated It has revolutionized the way we …...

PyQt 中的无限循环后台任务
在 PyQt 中实现一个后台无限循环任务,需要确保不会阻塞主线程,否则会导致 GUI 无响应。常用的方法是利用 线程(QThread) 或 任务(QRunnable 和 QThreadPool) 来运行后台任务。以下是一些实现方式和关键点&a…...

5G CPE核心器件-基带处理器(三)
5G CPE 核心器件 -5G基带芯片 基带芯片简介基带芯片组成与结构技术特点与发展趋势5G基带芯片是5G CPE中最核心的组件,负责接入5G网络,并进行上下行数据业务传输。移动通信从1G发展到5G,终端形态产生了极大的变化,在集成度、功耗、性能等方面都取得巨大的提升。 基带芯片简…...

鸿蒙next版开发:拍照实现方案(ArkTS)
文章目录 拍照功能开发步骤1. 导入相关接口2. 创建会话3. 配置会话4. 触发拍照5. 监听拍照输出流状态 结语 在HarmonyOS 5.0中,ArkTS提供了一套完整的API来管理相机功能,特别是拍照功能。本文将详细介绍如何在ArkTS中实现拍照功能,并提供代码…...

C++面试突破---C/C++基础
1.C特点 1. C在C语言基础上引入了面对对象的机制,同时也兼容C语言。 2. C有三大特性(1)封装。(2)继承。(3)多态; 3. C语言编写出的程序结构清晰、易于扩充,程序可读性好。…...

项目搭建+修改
一 : 在列表成功回调函数,追加数据中,添加修改的按钮 for (let x of res) {//追加数据$("#table").append(<tr><td><input type"checkbox" class"ck" value"\${x.uid}"></td><td>\${x.uid}</td>…...

每日算法一练:剑指offer——树篇(4)
1.计算二叉树的深度 某公司架构以二叉树形式记录,请返回该公司的层级数。 示例 1: 输入:root [1, 2, 2, 3, null, null, 5, 4, null, null, 4] 输出: 4 解释: 上面示例中的二叉树的最大深度是 4,沿着路径 1 -> 2 -> 3 -&…...

Nginx静态资源配置
基本配置原则 明确资源目录:为不同类型的静态资源指定不同的路径,这样可以避免路径冲突,并且便于管理。正确设置文件权限:确保 Nginx 具有读取静态资源的权限。缓存优化:为静态资源设置缓存头(如 expires&…...

困扰解决:mfc140u.dll丢失的解决方法,多种有效解决方法全解析
当电脑提示“mfc140u.dll丢失”时,这可能会导致某些程序无法正常运行,给用户带来不便。不过,有多种方法可以尝试解决这个问题。这篇文章将以“mfc140u.dll丢失的解决方法”为主题,教大家有效解决mfc140u.dll丢失。 判断是否是“mf…...