双指针算法思想——OJ例题扩展算法解析思路
大家好!上一期我发布了关于双指针的OJ平台上的典型例题思路解析,基于上一期的内容,我们这一期从其中内容扩展出来相似例题进行剖析和运用,一起来试一下吧!
目录
一、 基于移动零的举一反三
题一:27. 移除元素 - 力扣(LeetCode)
运行代码:
1. 双指针初始化
2. 遍历数组
3. 处理非 val 元素
4. 处理 val 元素
5. 返回结果
6. 时间复杂度
7. 空间复杂度
代码总结
示例
题二:2460. 对数组执行操作 - 力扣(LeetCode)
基本大体思路:
第一部分:应用特定规则修改数组元素
思路:
示例:
第二部分:将所有非零元素移动到数组的前部
思路:
示例:
第三部分:返回结果——返回修改后的数组 nums。
总结
示例运行
二、基于快乐数的举一反三
题一:2460. 对数组执行操作 - 力扣(LeetCode)
运行代码:
1. 初始化快慢指针
2. 处理特殊情况
3. 遍历链表
4. 遍历结束
5. 算法原理
6. 时间复杂度
7. 示例
8. 总结
题二:258. 各位相加 - 力扣(LeetCode)
运行代码:
2. 内层循环:计算数位和
3. 返回结果
4. 示例
5. 时间复杂度
题三: 263. 丑数 - 力扣(LeetCode)
运行代码:
1. 处理特殊情况
2. 定义质因数数组
3. 循环去除质因数
4. 判断最终结果
总结
题四:1945. 字符串转化后的各位数字之和 - 力扣(LeetCode)
运行代码:
问题分析
代码思路
第一步:字母转换为数字字符串
第二步:数字求和操作
第三步:返回结果
代码实现的关键点
步骤:
时间复杂度分析
题五:2457. 美丽整数的最小增量 - 力扣(LeetCode)
思路:
运行代码:
题六:2507. 使用质因数之和替换后可以取到的最小值 - 力扣(LeetCode)
运行代码:
问题分析
代码思路
第一步:质因数分解
第二步:替换为质因数之和
第三步:返回结果
代码实现的关键点
1. sumOfPrimeFactors 函数
2. smallestValue 函数
示例运行
步骤:
时间复杂度分析
题七:2520. 统计能整除数字的位数 - 力扣(LeetCode)
运行代码:
代码思路
第一步:初始化
第二步:逐位提取数字
第三步:返回结果
代码实现的关键点
1. 逐位提取数字
2. 判断是否能整除
3. 边界条件
示例运行
步骤:
时间复杂度分析
一、 基于移动零的举一反三
题一:27. 移除元素 - 力扣(LeetCode)
运行代码:
class Solution {
public:int removeElement(vector<int>& nums, int val) {int left=0;int right=0;while(right<nums.size()){if(nums[right]!=val){ swap(nums[left],nums[right]);left++;}right++;}return left;}
};
1. 双指针初始化
left
指针:用于指向当前可以放置非val
元素的位置。
right
指针:用于遍历数组,寻找非val
的元素。2. 遍历数组
使用
while
循环遍历数组,right
指针从数组的起始位置开始,逐步向右移动。在遍历过程中,
right
指针会检查当前元素是否等于val
。3. 处理非
val
元素
如果
nums[right]
不等于val
,说明这个元素应该保留在数组中。将这个元素与
nums[left]
交换,确保所有非val
的元素都集中在数组的左侧。交换后,
left
指针向右移动一位,指向下一个可以放置非val
元素的位置。4. 处理
val
元素
如果
nums[right]
等于val
,则不做任何操作,right
指针继续向右移动,跳过这个元素。5. 返回结果
当
right
指针遍历完整个数组后,left
指针的位置即为移除所有val
元素后数组的新长度。返回
left
的值。6. 时间复杂度
该算法的时间复杂度为 O(n),其中 n 是数组的长度。因为每个元素最多被访问一次。
7. 空间复杂度
该算法的空间复杂度为 O(1),因为它只使用了常数个额外的变量(
left
和right
指针)。代码总结
通过双指针技巧,代码高效地将所有非
val
元素移动到数组的前部,并返回新数组的长度。这种方法避免了使用额外的空间,直接在原数组上进行操作,是一种原地修改的算法。
示例
假设
nums = [3, 2, 2, 3]
,val = 3
,代码的执行过程如下:
left = 0
,right = 0
,nums[0] = 3
(等于val
),right++
。
left = 0
,right = 1
,nums[1] = 2
(不等于val
),交换nums[0]
和nums[1]
,数组变为[2, 3, 2, 3]
,left++
,right++
。
left = 1
,right = 2
,nums[2] = 2
(不等于val
),交换nums[1]
和nums[2]
,数组变为[2, 2, 3, 3]
,left++
,right++
。
left = 2
,right = 3
,nums[3] = 3
(等于val
),right++
。遍历结束,返回
left = 2
,表示新数组的长度为 2,且前两个元素[2, 2]
是移除val
后的结果。
题二:2460. 对数组执行操作 - 力扣(LeetCode)
基本大体思路:
-
应用特定规则修改数组元素:如果相邻的两个元素相等,则将左边的元素乘以 2,右边的元素置为 0。
-
将所有非零元素移动到数组的前部:保持非零元素的相对顺序,并将所有 0 移动到数组的末尾。
以下是代码的思路解析:
第一部分:应用特定规则修改数组元素
for (int i = 0; i < n - 1; i++) {int left = i, right = i + 1;if (nums[left] == nums[right]) {nums[left] *= 2;nums[right] = 0;} else {continue;} }
思路:
遍历数组:
使用一个
for
循环遍历数组,从索引0
到n-2
(因为需要比较当前元素和下一个元素)。定义两个指针
left
和right
,分别指向当前元素和下一个元素。检查相邻元素是否相等:
如果
nums[left] == nums[right]
,则将nums[left]
的值乘以 2,并将nums[right]
置为 0。如果相邻元素不相等,则跳过,继续遍历。
示例:
假设
nums = [1, 1, 2, 2]
:
遍历到
i = 0
时,nums[0] == nums[1]
,因此nums[0] *= 2
(变为 2),nums[1] = 0
,数组变为[2, 0, 2, 2]
。遍历到
i = 2
时,nums[2] == nums[3]
,因此nums[2] *= 2
(变为 4),nums[3] = 0
,数组变为[2, 0, 4, 0]
。第二部分:将所有非零元素移动到数组的前部
int dest = -1, cur = 0; while (cur < nums.size()) {if (nums[cur]) {dest++;swap(nums[dest], nums[cur]);cur++;} else {cur++;} }
思路:
双指针初始化:
dest
指针:用于指向当前可以放置非零元素的位置,初始值为-1
。
cur
指针:用于遍历数组,初始值为0
。遍历数组:
使用
while
循环遍历数组,cur
指针从0
开始,逐步向右移动。处理非零元素:
如果
nums[cur]
是非零元素,则将dest
指针向右移动一位,并交换nums[dest]
和nums[cur]
。这样可以将所有非零元素移动到数组的前部,同时保持它们的相对顺序。
处理零元素:
如果
nums[cur]
是零元素,则跳过,cur
指针继续向右移动。示例:
假设经过第一部分操作后,
nums = [2, 0, 4, 0]
:
dest = -1
,cur = 0
,nums[0] = 2
(非零),dest++
(变为 0),交换nums[0]
和nums[0]
(数组不变),cur++
。
dest = 0
,cur = 1
,nums[1] = 0
(零),跳过,cur++
。
dest = 0
,cur = 2
,nums[2] = 4
(非零),dest++
(变为 1),交换nums[1]
和nums[2]
,数组变为[2, 4, 0, 0]
,cur++
。
dest = 1
,cur = 3
,nums[3] = 0
(零),跳过,cur++
。遍历结束,数组变为
[2, 4, 0, 0]
。第三部分:返回结果——返回修改后的数组
nums
。总结
时间复杂度:
第一部分遍历数组一次,时间复杂度为 O(n)。
第二部分遍历数组一次,时间复杂度为 O(n)。
总时间复杂度为 O(n)。
空间复杂度:
只使用了常数个额外变量(
dest
和cur
),空间复杂度为 O(1)。功能:
代码实现了对数组的原地修改,满足题目要求。
示例运行
假设输入
nums = [1, 1, 2, 2]
:
第一部分操作后,数组变为
[2, 0, 4, 0]
。第二部分操作后,数组变为
[2, 4, 0, 0]
。返回
[2, 4, 0, 0]
。
二、基于快乐数的举一反三
题一:2460. 对数组执行操作 - 力扣(LeetCode)
运行代码:
class Solution {
public:bool hasCycle(ListNode *head) {ListNode* slow=head;ListNode* fast=head;if(head==nullptr||head->next==nullptr){return false;}while(fast!=nullptr&&fast->next!=nullptr){slow=slow->next;fast=fast->next->next;if(slow==fast){return true;}}return false;}
};
1. 初始化快慢指针
slow
是慢指针,每次移动一步。
fast
是快指针,每次移动两步。初始时,两个指针都指向链表的头节点
head
。2. 处理特殊情况
如果链表为空(
head == nullptr
)或只有一个节点(head->next == nullptr
),则链表不可能有环,直接返回false
。3. 遍历链表
使用
while
循环遍历链表,条件是fast != nullptr && fast->next != nullptr
。
这个条件确保快指针可以安全地移动两步(避免访问空指针)。
在每次循环中:
慢指针
slow
移动一步:slow = slow->next
。快指针
fast
移动两步:fast = fast->next->next
。如果快慢指针相遇(
slow == fast
),说明链表中有环,返回true
。4. 遍历结束
如果快指针到达链表末尾(
fast == nullptr
或fast->next == nullptr
),说明链表中没有环,返回false
。5. 算法原理
快慢指针的核心思想:
如果链表中有环,快指针最终会追上慢指针(因为快指针每次比慢指针多走一步)。
如果链表中没有环,快指针会先到达链表末尾。
6. 时间复杂度
时间复杂度:O(n),其中 n 是链表的节点数。
如果链表中无环,快指针会先到达链表末尾,遍历次数为 n/2。
如果链表中有环,快慢指针会在环内相遇,遍历次数小于 n。
空间复杂度:O(1),只使用了常数个额外空间(两个指针)。
7. 示例
假设链表如下:
初始时,
slow
和fast
都指向节点 3。移动过程:
slow
移动到 2,fast
移动到 0。
slow
移动到0,fast
移动到 2。
slow
移动到-4,fast
移动到 -4。
slow == fast
,说明链表有环,返回true
。8. 总结
这段代码通过快慢指针高效地判断链表中是否存在环。
快慢指针算法是解决链表环检测问题的经典方法,具有时间复杂度 O(n) 和空间复杂度 O(1) 的优势。
题二:258. 各位相加 - 力扣(LeetCode)
运行代码:
class Solution {
public:int addDigits(int num) {while(num>=10){int sum=0;while(num>0){sum+=num%10;num/=10;}num=sum;}return num;}
};
1. 外层循环:判断是否需要继续计算
如果
num
大于或等于 10,说明num
还不是个位数,需要继续计算数位和。如果
num
小于 10,说明已经得到结果,直接返回num
。2. 内层循环:计算数位和
sum
初始化:
每次外层循环开始时,
sum
初始化为 0,用于累加num
的各个数位。内层循环逻辑:
使用
while (num > 0)
循环,逐位取出num
的个位数,并累加到sum
中。每次取出个位数后,将
num
除以 10,去掉已经处理的个位数。更新
num
:
内层循环结束后,将
sum
赋值给num
,继续外层循环的判断。3. 返回结果
当
num
小于 10 时,跳出外层循环,返回num
,即为最终的结果。4. 示例
假设输入
num = 38
,代码的执行过程如下:
第一次外层循环:
num = 38
(大于等于 10),进入内层循环。内层循环:
sum += 8
(38 % 10
),sum = 8
,num = 3
(38 / 10
)。
sum += 3
(3 % 10
),sum = 11
,num = 0
(3 / 10
)。内层循环结束,
num = sum = 11
。第二次外层循环:
num = 11
(大于等于 10),进入内层循环。内层循环:
sum += 1
(11 % 10
),sum = 1
,num = 1
(11 / 10
)。
sum += 1
(1 % 10
),sum = 2
,num = 0
(1 / 10
)。内层循环结束,
num = sum = 2
。外层循环结束:
num = 2
(小于 10),跳出循环,返回2
。5. 时间复杂度
时间复杂度:O(log n),其中 n 是输入的数字。
每次外层循环会将
num
减少到其数位和,数位和的规模远小于num
。内层循环的次数取决于
num
的位数,每次内层循环的时间复杂度为 O(log n)。空间复杂度:O(1),只使用了常数个额外变量。
题三: 263. 丑数 - 力扣(LeetCode)
运行代码:
class Solution {
public:bool isUgly(int n) {int arr[]={2,3,5};if(n<=0){return false;}else{for(int i=0;i<3;i++){while(n%arr[i]==0){n/=arr[i];}}return n==1;}}
};
1. 处理特殊情况
如果
n
小于或等于 0,直接返回false
,因为丑数必须是正整数。2. 定义质因数数组
定义一个数组
arr
,包含 2、3、5 这三个质因数。3. 循环去除质因数
使用一个
for
循环遍历数组arr
中的每个质因数。对于每个质因数,使用
while
循环不断将n
除以该质因数,直到n
不再能被该质因数整除为止。这样做的目的是将
n
中的所有 2、3、5 的质因数全部去除。4. 判断最终结果
如果
n
最终变为 1,说明n
只包含 2、3、5 这些质因数,因此n
是丑数,返回true
。如果
n
最终不为 1,说明n
包含其他质因数,因此n
不是丑数,返回false
。总结
该算法通过不断去除
n
中的 2、3、5 质因数,最终判断n
是否变为 1 来判断n
是否为丑数。时间复杂度为 O(log n),因为每次除法操作都会减少
n
的大小。空间复杂度为 O(1),只使用了常数级别的额外空间。
题四:1945. 字符串转化后的各位数字之和 - 力扣(LeetCode)
运行代码:
class Solution {
public:int getLucky(string s, int k) {string digits;for(auto ch : s){// 将字符转换为对应的数字并追加到digits字符串中digits += to_string(ch - 'a' + 1);}for(int i = 1; i <= k && digits.size() > 1; ++i){int sum = 0;for(auto ch : digits){// 将字符转换为数字并累加sum += stoi(string(1, ch));}// 将累加结果转换为字符串digits = to_string(sum);}// 返回最终结果return stoi(digits);}
};
问题分析
输入:
一个字符串
s
,由小写字母组成。一个整数
k
,表示需要进行“数字求和”操作的次数。转换规则:
将字符串中的每个字母转换为其在字母表中的位置值(
a -> 1
,b -> 2
, ...,z -> 26
)。将这些位置值拼接成一个数字字符串。
操作规则:
对数字字符串中的每一位数字求和,得到一个新的数字。
重复上述操作
k
次,或者直到数字字符串的长度变为 1(即无法继续求和)。输出:
最终的数字结果。
代码思路
第一步:字母转换为数字字符串
遍历字符串
s
中的每个字符ch
。将字符
ch
转换为对应的数字:
公式:
ch - 'a' + 1
。
ch - 'a'
得到字符ch
在字母表中的偏移量(a -> 0
,b -> 1
, ...,z -> 25
)。
+ 1
将其转换为位置值(a -> 1
,b -> 2
, ...,z -> 26
)。将数字转换为字符串并追加到
digits
中。示例:
输入
s = "abc"
:
a -> 1
,b -> 2
,c -> 3
。
digits = "123"
。第二步:数字求和操作
进行
k
次求和操作:
每次操作中,遍历
digits
中的每个字符(即数字的每一位)。将字符转换为数字并累加到
sum
中。将
sum
转换为字符串,更新digits
。如果
digits
的长度变为 1,则提前结束循环(因为无法继续求和)。示例:
输入
digits = "123"
,k = 2
:
第一次操作:
sum = 1 + 2 + 3 = 6
。
digits = "6"
。第二次操作:
由于
digits
的长度已经是 1,循环结束。第三步:返回结果
将最终的
digits
转换为整数并返回。示例:
最终
digits = "6"
,返回6
。代码实现的关键点
字符到数字的转换:
使用
ch - 'a' + 1
将字母转换为对应的数字。使用
to_string
将数字转换为字符串。数字求和:
使用
stoi(string(1, ch))
将字符转换为数字。使用
to_string(sum)
将求和结果转换回字符串。循环控制:
最多进行
k
次操作。如果
digits
的长度变为 1,提前结束循环。步骤:
字母转换为数字字符串:
l -> 12
,e -> 5
,e -> 5
,t -> 20
,c -> 3
,o -> 15
,d -> 4
,e -> 5
。
digits = "12552031545"
。第一次求和操作:
sum = 1 + 2 + 5 + 5 + 2 + 0 + 3 + 1 + 5 + 4 + 5 = 33
。
digits = "33"
。第二次求和操作:
sum = 3 + 3 = 6
。
digits = "6"
。返回结果:
6
。时间复杂度分析
字母转换:
遍历字符串
s
,时间复杂度为O(n)
,其中n
是字符串的长度。数字求和操作:
每次求和操作需要遍历
digits
的所有字符。最多进行
k
次操作。最坏情况下,
digits
的长度可能很大,但每次求和操作会显著减少其长度。总体时间复杂度为
O(k * m)
,其中m
是digits
的最大长度。
题五:2457. 美丽整数的最小增量 - 力扣(LeetCode)
思路:
- 得到当前数字的各位数字之和,如果<=target就直接返回0
- 当前值各位数之和大于了target,那么考虑进行进位,当前数大于,那么个位的数字往上变大更不可能满足条件
- 寻找最小值,末尾为0则最小 所以我们令此时的个位为0,十位进1,同理,如果计算后仍旧大于target,我们将十位变为0,百位进1
- 举例子:123 3
- 123 和为6>3,那么124-129的各位数和不可能小于6,直到进位后130达到4才小于123的6
- 130 和为4>3 那么131-139也不可能小于4,也只有进位后200才小于130的4
- 200 和为2<3,所以200-123的差就是最小增量
运行代码:
class Solution {
public:int sub(long long n)//位数求和{int sum = 0;while (n > 0){sum += n % 10;n /= 10;}return sum;}long long makeIntegerBeautiful(long long n, int target){if (sub(n) <= target)return 0;long long i = 10;long long t=n;//保存原值while (sub(n) > target){n=n/i;//去掉当前末位(即末位变为0) 第一轮123-> 12 第二轮130->1n++;//进位 第一轮12+1->13 第二轮1+1->2n*=i;//末尾变为0 第一轮13*10->130 第二轮2*100->200i*=10;//每一次进位 }return n-t;}
};
题六:2507. 使用质因数之和替换后可以取到的最小值 - 力扣(LeetCode)
运行代码:
class Solution {
public:// 辅助函数:计算 n 的质因数之和int sumOfPrimeFactors(int n) {int sum = 0;// 从最小的质数 2 开始分解for (int i = 2; i * i <= n; i++) {while (n % i == 0) {sum += i; // 累加质因数n /= i;}}// 如果 n 仍然是大于 1 的质数if (n > 1) {sum += n;}return sum;}// 主函数:计算 n 的最小值int smallestValue(int n) {while (true) {int sum = sumOfPrimeFactors(n); // 计算质因数之和if (sum == n) { // 如果 n 已经是质数break;}n = sum; // 替换 n 为质因数之和}return n;}
};
问题分析
输入:
一个正整数
n
。操作规则:
将
n
替换为其质因数之和。重复上述操作,直到
n
无法再被分解(即n
是一个质数)。输出:
最终
n
的最小值(即一个质数)。代码思路
第一步:质因数分解
对于一个正整数
n
,找到其所有质因数。如果
n
能被某个质因数多次整除,则在求和时,该质因数需要被累加多次。第二步:替换为质因数之和
将
n
替换为其质因数之和。重复上述操作,直到
n
是一个质数。第三步:返回结果
最终
n
的值即为所求的最小值。代码实现的关键点
1.
sumOfPrimeFactors
函数
功能:计算整数
n
的所有质因数之和。实现:
从最小的质数
2
开始,逐个检查是否能整除n
。如果能整除,则将该质因数累加到
sum
中,并将n
除以该质因数。重复上述过程,直到
n
变为1
或无法再被分解。如果
n
仍然是大于1
的质数,则将其累加到sum
中。2.
smallestValue
函数
功能:将
n
替换为其质因数之和,直到n
变为质数。实现:
循环调用
sumOfPrimeFactors
,计算n
的质因数之和。如果
sum == n
,说明n
已经是质数,退出循环。否则,将
n
替换为sum
,继续循环。示例运行
步骤:
第一次分解:
质因数分解:
12 = 2 * 2 * 3
。质因数之和:
2 + 2 + 3 = 7
。替换
n
为7
。第二次分解:
7
是质数,无法再分解。返回
7
。时间复杂度分析
质因数分解:
每次分解的时间复杂度为
O(sqrt(n))
。循环次数:
每次替换
n
为质因数之和,n
的值会显著减小。最坏情况下,循环次数为
O(log n)
次。总体时间复杂度:
O(sqrt(n) * log n)
。
题七:2520. 统计能整除数字的位数 - 力扣(LeetCode)
运行代码:
class Solution {
public:int countDigits(int num) {int t = num, res = 0;while (t) {if (num % (t % 10) == 0) {res += 1;}t /= 10;}return res;}
};
问题分析
输入:
一个整数
num
。目标:
计算
num
中有多少位数字能够整除num
本身。关键点:
需要逐位提取
num
的数字。判断每一位数字是否能整除
num
。代码思路
第一步:初始化
使用变量
t
保存num
的值,避免直接修改num
。使用变量
res
记录满足条件的数字个数,初始值为0
。第二步:逐位提取数字
使用
while
循环遍历t
的每一位数字:
t % 10
:获取t
的最后一位数字。
t /= 10
:去掉t
的最后一位数字。对每一位数字进行判断:
如果
num % (t % 10) == 0
,说明当前数字能整除num
。将
res
的值加1
。第三步:返回结果
循环结束后,
res
中存储的就是满足条件的数字个数。返回
res
。代码实现的关键点
1. 逐位提取数字
使用
t % 10
获取当前位的数字。使用
t /= 10
去掉当前位的数字。2. 判断是否能整除
使用
num % (t % 10) == 0
判断当前数字是否能整除num
。3. 边界条件
如果
num
的某一位是0
,则需要跳过,因为除数不能为0
。
在这段代码中,如果
t % 10 == 0
,num % 0
会导致运行时错误。因此,代码假设num
不包含0
。示例运行
步骤:
初始化:
t = 1248
,res = 0
。第一次循环:
t % 10 = 8
。
1248 % 8 == 0
,满足条件。
res = 1
。
t = 1248 / 10 = 124
。第二次循环:
t % 10 = 4
。
1248 % 4 == 0
,满足条件。
res = 2
。
t = 124 / 10 = 12
。第三次循环:
t % 10 = 2
。
1248 % 2 == 0
,满足条件。
res = 3
。
t = 12 / 10 = 1
。第四次循环:
t % 10 = 1
。
1248 % 1 == 0
,满足条件。
res = 4
。
t = 1 / 10 = 0
。循环结束,返回
res = 4
。时间复杂度分析
循环次数:
while
循环的次数等于num
的位数,即O(log num)
。总体时间复杂度:
O(log num)
。
相关文章:
双指针算法思想——OJ例题扩展算法解析思路
大家好!上一期我发布了关于双指针的OJ平台上的典型例题思路解析,基于上一期的内容,我们这一期从其中内容扩展出来相似例题进行剖析和运用,一起来试一下吧! 目录 一、 基于移动零的举一反三 题一:27. 移除…...
初始Linux(7):认识进程(下)
1. 进程优先级 cpu 资源分配的先后顺序,就是指进程的优先权( priority )。 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的 linux 很有用,可以改善系统性能。 还可以把进程运行到指定的CPU 上,这样一来…...
人工智能第2章-知识点与学习笔记
结合教材2.1节,阐述什么是知识、知识的特性,以及知识的表示。人工智能最早应用的两种逻辑是什么?阐述你对这两种逻辑表示的内涵理解。什么谓词,什么是谓词逻辑,什么是谓词公式。谈谈你对谓词逻辑中的量词的理解。阐述谓词公式的解…...
Kotlin 协程 与 Java 虚拟线程对比测试(娱乐性质,请勿严谨看待本次测试)
起因 昨天在群里聊到虚拟线程的执行效率问题的时候虽然最后的结论是虚拟线程在针对IO密集型任务时具有很大的优势。但是讨论到虚拟线程和Kotlin 的协程的优势对比的话,这时候所有人都沉默了。所以有了本次的测试 提前声明:本次测试是不严谨的࿰…...
C++中的拷贝构造器(Copy Constructor)
在C中,拷贝构造器(Copy Constructor)是一种特殊的构造函数,用于创建一个新对象,该对象是另一个同类型对象的副本。当使用一个已存在的对象来初始化一个新对象时,拷贝构造器会被调用。 拷贝构造器的定义 拷…...
Spring Boot项目如何使用MyBatis实现分页查询
写在前面:大家好!我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正,感谢大家的不吝赐教。我的唯一博客更新地址是:https://ac-fun.blog.csdn.net/。非常感谢大家的支持。一起加油,冲鸭&#x…...
独立开发经验谈:如何借助 AI 辅助产品 UI 设计
我在业余时间开发了一款自己的独立产品:升讯威在线客服与营销系统。陆陆续续开发了几年,从一开始的偶有用户尝试,到如今线上环境和私有化部署均有了越来越多的稳定用户,在这个过程中,我也积累了不少如何开发运营一款独…...
笔灵ai写作技术浅析(三):深度学习
笔灵AI写作的深度学习技术主要基于Transformer架构,尤其是GPT(Generative Pre-trained Transformer)系列模型。 1. Transformer架构 Transformer架构由Vaswani等人在2017年提出,是GPT系列模型的基础。它摒弃了传统的循环神经网络(RNN)和卷积神经网络(CNN),完全依赖自…...
https数字签名手动验签
以bing.com 为例 1. CA 层级的基本概念 CA 层级是一种树状结构,由多个层级的 CA 组成。每个 CA 负责为其下一层级的实体(如子 CA 或终端实体)颁发证书。层级结构的顶端是 根 CA(Root CA),它是整个 PKI 体…...
为什么LabVIEW适合软硬件结合的项目?
LabVIEW是一种基于图形化编程的开发平台,广泛应用于软硬件结合的项目中。其强大的硬件接口支持、实时数据采集能力、并行处理能力和直观的用户界面,使得它成为工业控制、仪器仪表、自动化测试等领域中软硬件系统集成的理想选择。LabVIEW的设计哲学强调模…...
C# 操作符重载对象详解
.NET学习资料 .NET学习资料 .NET学习资料 一、操作符重载的概念 在 C# 中,操作符重载允许我们为自定义的类或结构体定义操作符的行为。通常,我们熟悉的操作符,如加法()、减法(-)、乘法&#…...
git:恢复纯版本库
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...
java异常处理——try catch finally
单个异常处理 1.当try里的代码发生了catch里指定类型的异常之后,才会执行catch里的代码,程序正常执行到结尾 2.如果try里的代码发生了非catch指定类型的异常,则会强制停止程序,报错 3.finally修饰的代码一定会执行,除…...
【架构面试】二、消息队列和MySQL和Redis
MQ MQ消息中间件 问题引出与MQ作用 常见面试问题:面试官常针对项目中使用MQ技术的候选人提问,如如何确保消息不丢失,该问题可考察候选人技术能力。MQ应用场景及作用:以京东系统下单扣减京豆为例,MQ用于交易服和京豆服…...
A4988一款常用的步进电机驱动芯片
A4988 是一款常用的步进电机驱动芯片,广泛应用于 3D 打印机、CNC 机床和小型自动化设备中。它可以驱动多种类型的步进电机,但需要根据电机的参数(如电压、电流、相数等)进行合理配置。 一、A4988 的主要特性 驱动能力:…...
TypeScript语言的语法糖
TypeScript语言的语法糖 TypeScript作为一种由微软开发的开源编程语言,它在JavaScript的基础上添加了一些强类型的特性,使得开发者能够更好地进行大型应用程序的构建和维护。在TypeScript中,不仅包含了静态类型、接口、枚举等强大的特性&…...
A星算法两元障碍物矩阵转化为rrt算法四元障碍物矩阵
对于a星算法obstacle所表示的障碍物障碍物信息,每行表示一个障碍物的坐标,例如2 , 3; % 第一个障碍物在第二行第三列,也就是边长为1的正方形障碍物右上角横坐标是2,纵坐标为3,障碍物的宽度和高度始终为1.在rrt路径规划…...
什么情况下,C#需要手动进行资源分配和释放?什么又是非托管资源?
扩展:如何使用C#的using语句释放资源?什么是IDisposable接口?与垃圾回收有什么关系?-CSDN博客 托管资源的回收有GC自动触发,而非托管资源需要手动释放。 在 C# 中,非托管资源是指那些不由 CLR(…...
【最长上升子序列Ⅱ——树状数组,二分+DP,纯DP】
题目 代码(只给出树状数组的) #include <bits/stdc.h> using namespace std; const int N 1e510; int n, m; int a[N], b[N], f[N], tr[N]; //f[i]表示以a[i]为尾的LIS的最大长度 void init() {sort(b1, bn1);m unique(b1, bn1) - b - 1;for(in…...
day37|完全背包基础+leetcode 518.零钱兑换II ,377.组合总和II
完全背包理论基础 完全背包与01背包的不同在于01背包的不同物品每个都只可以使用一次,但是完全背包的不同物品可以使用无数次 在01背包理论基础中,为了使得物品只被使用一次,我们采取倒序遍历来控制 回顾:>> for(int j …...
【VM】VirtualBox安装ubuntu22.04虚拟机
阅读本文之前,请先根据 安装virtualbox 教程安装virtulbox虚拟机软件。 1.下载Ubuntu系统镜像 打开阿里云的镜像站点:https://developer.aliyun.com/mirror/ 找到如图所示位置,选择Ubuntu 22.04.3(destop-amd64)系统 Ubuntu 22.04.3(desto…...
Qt事件处理:理解处理器、过滤器与事件系统
1. 事件 事件 是一个描述应用程序中、发生的某些事情的对象。 在 Qt 中,所有事件都继承自 QEvent ,并且每个事件都有特定的标识符,如:Qt::MouseButtonPress 代表鼠标按下事件。 每个事件对象包含该事件的所有相关信息ÿ…...
DeepSeek 云端部署,释放无限 AI 潜力!
1.简介 目前,OpenAI、Anthropic、Google 等公司的大型语言模型(LLM)已广泛应用于商业和私人领域。自 ChatGPT 推出以来,与 AI 的对话变得司空见惯,对我而言没有 LLM 几乎无法工作。 国产模型「DeepSeek-R1」的性能与…...
【论文复现】基于Otsu方法的多阈值图像分割改进鲸鱼优化算法
目录 1.摘要2.鲸鱼优化算法WOA原理3.改进策略4.结果展示5.参考文献6.代码获取 1.摘要 本文提出了一种基于Otsu方法的多阈值图像分割改进鲸鱼优化算法(RAV-WOA)。RAV-WOA算法能够在分割灰度图像和彩色图像时,自动选择最优阈值,并确…...
Hive之数据定义DDL
Hive之数据定义DDL 文章目录 Hive之数据定义DDL写在前面创建数据库查询数据库显示数据库查看数据库详情切换当前数据库 修改数据库删除数据库创建表管理表(内部表)外部表管理表与外部表的互相转换 修改表重命名表增加、修改和删除表分区增加/修改/替换列信息 删除表 写在前面 …...
Golang 应用的 Docker 部署方式介绍及使用详解
本文将介绍如何使用 Docker 部署一个基于 Go 语言的后台服务应用 godco,并介绍如何配置 MongoDB 数据库容器的连接,确保应用能够成功启动并连接到容器方式部署的mongoDB数据库。 前提条件 1.已安装 Docker/Podman 2.已安装 MongoDB 数据库容器ÿ…...
SuccessFactors OData OAuth with SAP IAS-generated SAML assertion
导读 IAS:一句话说明白。SAP相关的系统可以通过IAS登录,只要IAS登录,其他系统免密登录。 作者:vivi,来源:osinnovation 上图有三个角色:brower,就是自己的浏览器,sp就是我们的目标…...
vue入门到实战 三
目录 3.1 v-bind 3.1.1 v-bind指令用法 编辑3.1.2 使用v-bind绑定class 3.1.3 使用v-bind绑定style 3.2.1 v-if指令 3.2.1 v-if指令 3.2.2 v-show指令 3.3 列表渲染指令v-for 3.3.1 基本用法 3.3.2 数组更新 3.3.3 过滤与排序 3.4 事件处理 3.4.1 使用v-on指令…...
音视频入门基础:RTP专题(7)——RTP协议简介
一、引言 本文对RTP协议进行简介。在简介之前,请各位先下载RTP的官方文档《RFC 3550》。该文档总共有89页,本文下面所说的“页数”是指在pdf阅读器中显示的页数: 二、RTP协议简介 根据《RFC 3550》第5页,实时传输协议(…...
06-机器学习-数据预处理
数据清洗 数据清洗是数据预处理的核心步骤,旨在修正或移除数据集中的错误、不完整、重复或不一致的部分,为后续分析和建模提供可靠基础。以下是数据清洗的详细流程、方法和实战示例: 一、数据清洗的核心任务 问题类型表现示例影响缺失值数值…...
《逆向工程核心原理》第三~五章知识整理
查看上一章节内容《逆向工程核心原理》第一~二章知识整理 对应《逆向工程核心原理》第三章到第五章内容 小端序标记法 字节序 多字节数据在计算机内存中存放的字节顺序分为小端序和大端序两大类 大端序与小端序 BYTE b 0x12; WORD w 0x1234; DWORD dw 0x12345678; cha…...
影视文件大数据高速分发方案
在当今的数字时代,影视行业的内容创作和传播方式经历了翻天覆地的变化。随着4K、8K高清视频的普及,以及虚拟现实(VR)和增强现实(AR)技术的发展,影视文件的数据量正以前所未有的速度增长。这就要求行业内的参与者必须拥有高效的大数据传输解决…...
使用朴素贝叶斯对散点数据进行分类
本文将通过一个具体的例子,展示如何使用 Python 和 scikit-learn 库中的 GaussianNB 模型,对二维散点数据进行分类,并可视化分类结果。 1. 数据准备 假设我们有两个类别的二维散点数据,每个类别包含若干个点。我们将这些点分别存…...
pytorch线性回归模型预测房价例子
人工智能例子汇总:AI常见的算法和例子-CSDN博客 import torch import torch.nn as nn import torch.optim as optim import numpy as np# 1. 创建线性回归模型类 class LinearRegressionModel(nn.Module):def __init__(self):super(LinearRegressionModel, self).…...
微信登录模块封装
文章目录 1.资质申请2.combinations-wx-login-starter1.目录结构2.pom.xml 引入okhttp依赖3.WxLoginProperties.java 属性配置4.WxLoginUtil.java 后端通过 code 获取 access_token的工具类5.WxLoginAutoConfiguration.java 自动配置类6.spring.factories 激活自动配置类 3.com…...
C++运算符重载
C的运算符重载:使对象的运算表现得和编译器内置类型一样 以复数类为例: #include <iostream> using namespace std;class CComplex { public:CComplex(int r 0, int i 0): mreal(r), mimage(i){}// 指导编译器怎么做CComplex类对象的加法操作CC…...
pandas(三)Series使用
一、Series基础使用 import pandasd {x:100,y:200,z:300} s1 pandas.Series(d) #将dict转化为Series print(s1)print("") l1 [1, 2, 3] l2 [a, b, c] s2 pandas.Series(l1, indexl2) #list转为Series print(s2)print("") s3 pandas.Series([11…...
PVE 中 Debian 虚拟机崩溃后,硬盘数据怎么恢复
问题 在 PVE 中给 Debian 虚拟机新分配硬盘后,通过 Debian 虚拟机开启 Samba 共享该硬盘。如果这个 Debian 虚拟机崩溃后,怎么恢复 Samba 共享硬盘数据。 方法 开启 Samba 共享相关知识:挂载硬盘和开启Samba共享。 新建一个虚拟机…...
【大数据技术】案例01:词频统计样例(hadoop+mapreduce+yarn)
词频统计(hadoop+mapreduce+yarn) 搭建完全分布式高可用大数据集群(VMware+CentOS+FinalShell) 搭建完全分布式高可用大数据集群(Hadoop+MapReduce+Yarn) 在阅读本文前,请确保已经阅读过以上两篇文章,成功搭建了Hadoop+MapReduce+Yarn的大数据集群环境。 写在前面 Wo…...
PySPARK带多组参数和标签的SparkSQL批量数据导出到S3的程序
设计一个基于多个带标签SparkSQL模板作为配置文件和多组参数的PySPARK代码程序,实现根据不同的输入参数自动批量地将数据导出为Parquet、CSV和Excel文件到S3上,标签和多个参数(以“_”分割)为组成导出数据文件名,文件已…...
分享刷题过程中有价值的两道题目
小编在这里先祝大家新的一年里所愿皆得,万事顺意,天天开心!!! 一.水仙花数 题目描述: 求100∼999中的水仙花数。若三位数ABCA^3B^3C^3,则称ABC为水仙花数。例如153,135333112527153&…...
Java篇之继承
目录 一. 继承 1. 为什么需要继承 2. 继承的概念 3. 继承的语法 4. 访问父类成员 4.1 子类中访问父类的成员变量 4.2 子类中访问父类的成员方法 5. super关键字 6. super和this关键字 7. 子类构造方法 8. 代码块的执行顺序 9. protected访问修饰限定符 10. 继承方式…...
7.DP算法
DP 在C中,动态规划(Dynamic Programming,DP)是一种通过将复杂问题分解为重叠子问题来高效求解的算法设计范式。以下是DP算法的核心要点和实现方法: 一、动态规划的核心思想 重叠子问题:问题可分解为多个重…...
[SAP ABAP] 在ABAP Debugger调试器中设置断点
在命令框输入/H,点击回车以后,调试被激活,点击触发任意事件进入ABAP Debugger调试器界面 点击按钮,可以在Debugger调试器中新增临时断点 我们可以从ABAP命令、方法、功能、表单、异常、消息、源代码等多个维度在Debugger调试器中设…...
使用LLaMA-Factory对AI进行认知的微调
使用LLaMA-Factory对AI进行认知的微调 引言1. 安装LLaMA-Factory1.1. 克隆仓库1.2. 创建虚拟环境1.3. 安装LLaMA-Factory1.4. 验证 2. 准备数据2.1. 创建数据集2.2. 更新数据集信息 3. 启动LLaMA-Factory4. 进行微调4.1. 设置模型4.2. 预览数据集4.3. 设置学习率等参数4.4. 预览…...
2 [GitHub遭遇严重供应链投毒攻击]
近日,有黑客针对 Discord Top.gg 的GitHub 账户发起了供应链攻击,此次攻击导致账户密码、凭证和其他敏感信息被盗,同时也影响到了大量开发人员。 Checkmarx 在一份技术报告中提到,黑客在这次攻击中使用了多种TTP,其中…...
[c语言日寄]C语言类型转换规则详解
【作者主页】siy2333 【专栏介绍】⌈c语言日寄⌋:这是一个专注于C语言刷题的专栏,精选题目,搭配详细题解、拓展算法。从基础语法到复杂算法,题目涉及的知识点全面覆盖,助力你系统提升。无论你是初学者,还是…...
Python魔法函数
在Python中,的确有“魔法函数”(Magic Methods)这种说法,也被称为特殊方法(Special Methods)。这些函数的名称以双下划线开始和结束,例如 __init__、__len__ 等。它们为Python提供了一种约定俗成…...
Cypher入门
文章目录 Cypher入门创建数据查询数据matchoptional matchwhere分页with 更新数据删除数据实例:好友推荐 Cypher入门 Cypher是Neo4j的查询语言。 创建数据 在Neo4j中使用create命令创建节点、关系、属性数据。 create (n {name:$value}) return n //创建节点&am…...
excel如何查找一个表的数据在另外一个表是否存在
比如“Sheet1”有“张三”、“李四”“王五”三个人的数据,“Sheet2”只有“张三”、“李四”的数据。我们通过修改“Sheet1”的“民族”或者其他空的列,修改为“Sheet2”的某一列。这样修改后筛选这个修改的列为空的或者为出错的,就能找到两…...