算法沉淀——双指针算法(leetcode真题剖析)

news2025/1/18 7:35:26

在这里插入图片描述

算法沉淀——双指针算法

    • 01.移动零
    • 02.复写零
    • 03.快乐数
    • 04.盛最多水的容器
    • 05.有效三角形的个数
    • 06.和为s的两个数字
    • 07.三数之和
    • 08.四数之和

双指针算法(Two Pointer Algorithm)是一种常用于数组(或链表)操作的算法技巧。它的核心思想是通过维护两个指针,在数组中高效地解决一些问题,这里的指针不一定是真实的指针,是一种抽象的概念,比如数组的下标,C++的迭代器等等。这两个指针可以分别指向数组的不同位置,也可以分别指向数组的开始和结束。

常见的双指针算法有两种类型:快慢指针和左右指针。

  1. 快慢指针:
    • 用于解决一些查找或判断问题,比如判断链表是否有环、找到链表的中间节点等。
    • 快指针每次移动两步,慢指针每次移动一步。
    • 当两个指针相遇时,说明存在环,或者慢指针所指位置即为中间节点。
  2. 左右指针(又称对撞指针):
    • 用于解决一些区间或子数组的问题,比如在有序数组中找到两个数使其和等于目标值、判断一个字符串是否为回文等。
    • 左指针和右指针分别指向数组的两端,根据问题的要求,移动其中一个或两个指针。
    • 根据移动规则,可以有效地缩小问题的搜索范围,提高算法的效率。

下面我们通过实际算法题来进行讲解

01.移动零

题目链接:https://leetcode.cn/problems/move-zeroes/description/

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

思路

核心思路是使用两个指针,一个指针(cur)用于遍历数组,另一个指针(dest)用于指示当前非零元素的插入位置。通过遍历数组,当发现非零元素时,将其与dest位置的元素进行交换,同时递增dest指针,确保非零元素的相对顺序保持不变。

下面是算法的详细流程:

  1. 初始化两个指针:curdest,初始值为0和-1,因为cur指针先走。
  2. 从左到右遍历数组,用cur指针指向当前元素。
  3. 如果当前元素不为零,将其与dest位置的元素进行交换,并递增dest指针。
  4. 继续遍历,重复步骤3,直到数组遍历完毕。
  5. 此时,所有非零元素已经移动到数组的前面,而dest指针的位置之后都是零。因为dest初始值为-1,所以dest + 1即为第一个零的位置。
  6. 遍历完成后,数组中所有零已经被移动到数组的末尾。

这个算法的优点在于它只需要遍历一次数组,并且在原地进行操作,不需要额外的空间。这使得它在处理大规模数组时非常高效,时间复杂度只有O(n)。

以下是对应的C++代码:

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        for(int cur=0,dest=-1;cur<nums.size();++cur){
            if(nums[cur])
                swap(nums[++dest],nums[cur]);
        }
    }
};

02.复写零

题目链接:https://leetcode.cn/problems/duplicate-zeros/

给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

示例 1:

输入:arr = [1,0,2,3,0,4,5,0]
输出:[1,0,0,2,3,0,0,4]
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]

示例 2:

输入:arr = [1,2,3]
输出:[1,2,3]
解释:调用函数后,输入的数组将被修改为:[1,2,3]

思路

这里我们能够想到最简单的一种算法就是,我们再创建一个容器数组逐个遍历,进行零的重写,最后直接覆盖或交换原数组,但是这种写法花费的时间和特别是空间代价太大了,所以我们这种时候利用双指针的算法可以很好的解决这个问题。

算法的核心思想是通过两个步骤实现对数组中的零的复制:

  1. 统计零的个数: 通过遍历数组,统计其中零的个数,并在遍历过程中确定是否需要额外的位置来容纳复制的零。
  2. 从后向前复制零: 从数组的末尾开始向前复制元素,遇到非零元素直接复制,遇到零则复制两个零。这样的方式确保了零的复制不会影响到原数组中的元素。

下面是算法的详细步骤:

  1. 初始化变量 count 表示数组中零的个数,变量 i 表示当前遍历的位置。
  2. 第一次遍历数组,统计零的个数,并在遍历过程中判断是否需要额外的位置。同时记录遍历结束的位置 i
  3. 初始化变量 r 表示从后向前复制元素的位置,如果复制零后的数组长度超过了原数组长度,补充一个零到最后。
  4. 从位置 i 开始,从后向前遍历数组,根据数组中的元素值进行复制操作,确保零被复制两次,非零元素直接复制。
  5. 完成从后向前的复制后,原数组 arr 中的零已经被复制一份,实现了题目的要求。

以下是对应的C++代码:

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int n=arr.size(),count=0,i=0;
        for(i=0;i<n;i++){
            if(arr[i]==0) count++;
            if(i+count+1>=n) break;//题目规定不能超过数组固定长度
        }
        
        int r=n-1;
        if(i+count+1>n){ //处理边界情况,算出复写后位置大于n就说明最后那个位置一定是0
            arr[r--]=0;
            i--;
        } 
        
        //从后向前通过i和r的下标相对位置完成复写0 
        while(i>=0){
            if(arr[i]) arr[r--]=arr[i--];
            else{
                arr[r--]=0;
                arr[r--]=0;
                i--;
            }
        }
    }
};

03.快乐数

题目链接:https://leetcode.cn/problems/happy-number/description/

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n快乐数 就返回 true ;不是,则返回 false

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

思路

这道题其实我们可以根据一个数学知识知道如果经过不断计算无线循环的话,其中是一定会有重复的数字的,其实这里最好的解法应该是使用哈希思想,但是在这里我们使用双指针也可以有很简单的写法,我们先来看看双指针的写法

解法一:快慢指针

  1. 定义一个函数 nextSum,该函数用于计算一个数每位数字的平方和。通过对输入数字每位取模得到个位数,然后累加每位数字的平方。
  2. 使用两个指针 slowfast,初始时都指向输入的数 n。在循环中,slow每次计算一次 nextSum,而 fast每次计算两次 nextSum,这就相当于在一个链表中 slow 每次走一步,fast 每次走两步。
  3. 如果存在一个循环,那么 slowfast 最终都会进入这个循环,并相遇。如果 slow 最终等于1,则这个数是快乐数;如果 slowfast 相遇但不等于1,说明存在循环,这个数不是快乐数。

以下是对应的C++代码:

class Solution {
public:
    int nextSum(int n){
        int sum=0;
        while(n){
            int tmp=n%10;
            sum+=tmp*tmp;
            n/=10;
        }
        return sum;
    }
    bool isHappy(int n) {
        int slow=n,fast=nextSum(n);
        while(slow!=fast){
            slow=nextSum(slow);
            fast=nextSum(nextSum(fast));
        }
        return slow==1;
    }
};

解法二:哈希

这个算法也是通过计算每位数字的平方和,然后不断迭代,检测是否能够最终得到1。不同之处在于,这个算法使用了一个哈希集合 unordered_set 来记录已经出现过的数字,以便检测循环。

以下是对这个算法的核心思想和流程的详细解释:

  1. 初始化: 创建一个空的哈希集合 seen,用于记录已经出现过的数字。
  2. 循环检测: 在一个循环中,检测当前的数字是否等于1,并且是否已经在 seen 集合中出现过。如果是,则说明这个数是快乐数,直接返回 true
  3. 迭代计算: 如果当前数字不等于1且未出现在 seen 中,那么将当前数字加入到 seen 中,并计算下一个数字的平方和。这个过程通过迭代计算每位数字的平方和,然后将结果赋值给 n
  4. 循环继续: 继续在循环中执行上述步骤,直到 n 等于1或者 n 已经在 seen 中出现过。
  5. 返回结果: 最终判断 n 是否等于1,如果是则返回 true,否则返回 false

这个算法使用了哈希集合来检测循环,避免了在链表中进行双指针遍历的方式。这样的实现在空间上相对较高效,因为哈希集合的查找和插入操作都是平均 O(1) 的时间复杂度。算法的时间复杂度取决于是否存在循环,最坏情况下是 O(logN)。

以下是对应的C++代码:

class Solution {
public:
    bool isHappy(int n) {
        // 使用一个集合来存储已经出现过的数字,以检测循环
        unordered_set<int> seen;
        
        while (n != 1 && seen.find(n) == seen.end()) {
            seen.insert(n);
            int sum = 0;
            while (n > 0) {
                int digit = n % 10;
                sum += digit * digit;
                n /= 10;
            }
            n = sum;
        }
        
        return n == 1;
    }
};

04.盛最多水的容器

题目链接:https://leetcode.cn/problems/container-with-most-water/

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

**说明:**你不能倾斜容器。

示例 1:
在这里插入图片描述

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

思路

首先看到这种题的第一种想法可能都是暴力枚举每一种情况,但是这样做的复杂度太大,是会超时的,其实这里我们可以通过对撞指针的方式不断改变一边的高度,进而更新最大容量,直至指针相遇。

核心思想和流程的详细解释:

  1. 初始化: 使用两个指针 leftright 分别指向数组的起始和结束位置,同时初始化变量 ret 为0,用来记录最大的容器面积。
  2. 循环迭代: 在一个循环中,计算当前 leftright 指向的两个线段之间的容器面积,并将其与 ret 中记录的最大面积进行比较。然后,将 leftright 中较小的那个指针向内移动一步。
  3. 移动指针: 移动指针的规则是选择两个线段中较短的那个向内移动。这是因为如果移动较长的线段,容器的宽度减小,而高度最大不会增加;而如果移动较短的线段,有可能找到更高的线段,从而提高容器的高度。
  4. 更新最大面积: 在每次计算完容器的面积后,更新 ret 的值为当前面积与 ret 中记录的最大面积的较大者。
  5. 循环继续: 重复上述步骤,直到 leftright 指针相遇。
  6. 返回结果: 返回 ret,即找到的最大容器面积。

这个算法的核心在于通过不断移动指针,选择较短的线段向内移动,以期望找到更高的线段来提高容器的高度。这样的策略保证了在寻找最大容器面积的过程中,不漏过可能的最优解。算法的时间复杂度是 O(n)。

以下是对应的C++代码:

class Solution {
public:
    int maxArea(vector<int>& height) {
        int left=0,right=height.size()-1,ret=0;
        while(left<right){
            int v=min(height[left],height[right])*(right-left);
            ret=max(ret,v);
            if(height[left]<height[right]) left++;
            else right--;
        }
        return ret;
    }
};

05.有效三角形的个数

题目链接:https://leetcode.cn/problems/valid-triangle-number/description/

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

示例 1:

输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是: 
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

示例 2:

输入: nums = [4,2,3,4]
输出: 4

思路

这里使用暴力枚举同样会超时,所以这里同样可以使用双指针的方式来解决

核心思想是通过排序数组,然后使用双指针的方式,依次选择一个较大的元素作为三角形的最大边,然后在左边的子数组中使用双指针寻找满足三角形条件的组合。

以下是这个算法的详细解释:

  1. 排序数组: 首先对输入数组 nums 进行排序,以便于使用双指针的方式进行查找。
  2. 遍历最大边: 从数组的最后一个元素开始,即 i = n-1,向前遍历数组。这个元素作为三角形的最大边。
  3. 双指针查找: 使用两个指针 leftright 分别指向当前最大边的前两个元素,即 left = 0right = i-1
  4. 判断是否构成三角形: 在一个循环中,判断 nums[left] + nums[right] > nums[i] 是否成立。如果成立,说明当前的组合 (nums[left], nums[right], nums[i]) 可以构成一个三角形。此时,由于数组已经排序,那么左边的元素 nums[left] 和任何 nums[k](其中 left < k < right)都能够构成三角形。因此,ret += right - left 表示当前 left 对应的元素与 right 之间的元素均能够构成三角形,加到结果中。
  5. 更新指针: 根据当前判断的结果,更新指针的位置,即 right--left++
  6. 循环继续: 继续上述步骤,直到 left >= right,然后将 i 减一,进入下一轮循环。
  7. 返回结果: 最终得到的 ret 即为满足条件的三角形组合的数量。

以下是对应的C++代码:

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        
        int ret=0;
        int n=nums.size();
        for(int i=n-1;i>=2;i--){
            int left=0;
            int right=i-1;
            while(left<right){
                if(nums[left]+nums[right]>nums[i]){
                    ret+=right-left;
                    right--;
                }else left++;
            }
        }
        return ret;
    }
};

06.和为s的两个数字

题目链接:https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/description/

购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。

示例 1:

输入:price = [3, 9, 12, 15], target = 18
输出:[3,15] 或者 [15,3]

示例 2:

输入:price = [8, 21, 27, 34, 52, 66], target = 61
输出:[27,34] 或者 [34,27]

思路

同样暴力枚举会超时,因为这里是升序数组,我们使用双指针的解法可以非常轻松解决

  1. 初始化指针: 使用两个指针 leftright 分别指向数组的第一个元素和最后一个元素。
  2. 循环查找: 在一个循环中,计算当前 leftright 指向的两个元素的和 sum。如果 sum > target,说明当前和过大,需要将 right 向左移动一步;如果 sum < target,说明当前和过小,需要将 left 向右移动一步;如果 sum == target,则找到了满足条件的两个元素,返回结果 {nums[left], nums[right]}
  3. 循环继续: 继续上述步骤,直到 left >= right,循环结束。
  4. 返回结果: 如果循环结束时仍未找到满足条件的两个元素,则返回一个空数组。

这个算法的核心思想是利用有序数组的特性,通过双指针在数组中夹逼的方式,不断调整指针的位置,直到找到满足条件的两个元素或者循环结束。

这个算法的时间复杂度是 O(n)。因为每次循环中,leftright 至少有一个向中间移动一步,所以总体的时间复杂度是线性的。

以下是对应的C++代码:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> ret;
        for(int left=0,right=nums.size()-1;left<right;){
            int sum=nums[left]+nums[right];
            if(sum>target) right--;
            else if(sum<target) left++;
            else return {nums[left],nums[right]};
        }
        return {};
    }
};

07.三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

**注意:**答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

思路

其实这道题和两数之和解法类似,还是使用双指针的方式,只不过这里需要我们先排序,具体思路如下

  1. 排序: 对输入数组 nums 进行升序排序,这样可以使得相同的元素相邻,方便后续的去重操作。
  2. 遍历: 使用一个外层循环,固定一个数 nums[i] 作为三元组的第一个元素。
  3. 双指针: 在内层循环中,使用两个指针 leftright,分别指向当前数 nums[i] 的下一个元素和数组的最后一个元素。计算当前三个数的和 sum
  4. 判断和与目标值的关系:
    • 如果 sum > 0,说明右侧的数太大,将 right 向左移动一步。
    • 如果 sum < 0,说明左侧的数太小,将 left 向右移动一步。
    • 如果 sum == 0,说明找到了一个满足条件的三元组,加入结果集中,并进行去重操作。
  5. 去重操作: 在找到一个满足条件的三元组后,需要对 leftright 进行去重操作,即跳过相同的元素,避免结果中出现重复的三元组。
  6. 去重 i: 在外层循环中,找到一个满足条件的三元组后,也需要对 i 进行去重操作,即跳过相同的数,避免结果中出现相同的三元组。
  7. 返回结果: 最终返回所有满足条件的三元组组成的结果集。

以下是对应的C++代码:

class Solution
{
public:
	vector<vector<int>> threeSum(vector<int>& nums)
	{
		vector<vector<int>> ret;
		sort(nums.begin(), nums.end());
		int n = nums.size();
        
		for (int i = 0; i < n; ) 
		{
			if (nums[i] > 0) break; //没有负数或等于0的情况和不可能为0故直接跳出
			int left = i + 1, right = n - 1, target = -nums[i];
			while (left < right)
			{
				int sum = nums[left] + nums[right];
				if (sum > target) right--;
				else if (sum < target) left++;
				else
				{
					ret.push_back({ nums[i], nums[left], nums[right] });
					left++, right--;
					// 去重操作 left 和 right
					while (left < right && nums[left] == nums[left - 1]) left++;
					while (left < right && nums[right] == nums[right + 1])
						right--;
				}
			}
			// 去重 i
			i++;
			while (i < n && nums[i] == nums[i - 1]) i++;
		}
		return ret;
	}
};

08.四数之和

题目链接:https://leetcode.cn/problems/4sum/description/

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abcd 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

示例 1:

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

示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

思路

看到这个题目时,我们不难发现,可以用双指针的算法进行求解,这道题目还是使用类似三数之和的操作,只不过这里多了一个操作数,我们只需再加一层循环嵌套,以及一些去重优化即可,具体思路如下:

  1. 排序: 对输入数组 nums 进行升序排序,这样可以使得相同的元素相邻,方便后续的去重操作。
  2. 遍历: 使用两个外层循环,分别固定两个数 nums[i]nums[j] 作为四元组的前两个元素。
  3. 双指针: 在内层循环中,使用两个指针 leftright,分别指向当前数 nums[i]nums[j] 的下一个元素。计算当前四个数的目标和 aim
  4. 判断和与目标值的关系:
    • 首先这里不管是aim值还是sum值都要注意一个溢出的问题,所以我们这里都要使用long long进行类型的提升
    • 如果 sum > aim,说明右侧的数太大,将 right 向左移动一步。
    • 如果 sum < aim,说明左侧的数太小,将 left 向右移动一步。
    • 如果 sum == aim,说明找到了一个满足条件的四元组,加入结果集中,并进行去重操作。
  5. 去重操作: 在找到一个满足条件的四元组后,需要对 leftrightij 进行去重操作,即跳过相同的元素,避免结果中出现重复的四元组。
  6. 返回结果: 最终返回所有满足条件的四元组组成的结果集。
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        vector<vector<int>> ret;
        int n = nums.size();
        for(int i=0;i<n;){
            for(int j=i+1;j<n;){
                int left=j+1,right=n-1;
                long long aim=(long long)target-nums[i]-nums[j];

                while(left<right){
                    long long sum=(long long)nums[left]+nums[right];
                    if(sum>aim) right--;
                    else if(sum<aim) left++;
                    else{
                        ret.push_back({nums[i],nums[j],nums[left++],nums[right--]});
                        while(left<right && nums[left]==nums[left-1]) left++;
                        while(left<right && nums[right]==nums[right+1]) right--;
                    }
                }
                j++;
                while(j<n && nums[j]==nums[j-1]) j++;
            }
            i++;
            while(i<n && nums[i]==nums[i-1]) i++;
        }
        return ret;
    }
};

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

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

相关文章

2024年1月的论文推荐

又到月底了&#xff0c;在月初推荐论文的基础上又整理了10篇推荐阅读的论文 1、MosaicBERT https://mosaicbert.github.io/ 一种用于快速预训练的双向编码器。MosaicBERT是针对快速预训练优化的自定义BERT架构。主要架构修改:FlashAttention, ALiBi&#xff0c;门控线性单元…

【JavaWeb程序】【C00150】基于SSM的二手交易平台管理系统-(论文+PPT)

基于SSM的二手交易平台管理系统-&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目包运行、免费远程调试 项目简介 这是一个基于ssm的二手交易平台管理系统 本系统分为用户和管理员两个模块。 其中用户的权限为&#xff1a;修改个人信息、闲置商…

log4j2 java api 入门介绍

概述 Log4j 2 API 提供了应用程序应该编码的接口&#xff0c;并提供了实现者创建日志实现所需的适配器组件。 虽然 Log4j 2 在 API 和实现之间被分解&#xff0c;但这样做的主要目的不是允许多个实现&#xff0c;尽管这当然是可能的&#xff0c;而是明确定义在“正常”应用程…

探索机器学习的奥秘

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;网络奇遇记、数据结构 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 &#x1f4cb;前言一. 机器学习的定义二. 机器学习的发展历程三. 机器学习的原理四. 机器学习的分类…

路由、组件目录存放

文章目录 单页应用程序&#xff1a;SPA- Single Page Application路由的介绍VuePouter的介绍VueRouted 的使用 组件目录存放问题&#xff08;组件分类&#xff09; 单页应用程序&#xff1a;SPA- Single Page Application 单页应用&#xff08;SPA&#xff09;:所有功能在一个…

四. 基于环视Camera的BEV感知算法-BEVFormer实战

目录 前言1. BEVFormer实战 前言 自动驾驶之心推出的《国内首个BVE感知全栈系列学习教程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习下课程第四章——基于环视Camera的BEV感知算法&#xff0c;一起去学习下 BEVFormer 的相关代码 课程…

MySQL之索引分类,语法以及SQL性能分析(慢日志,profile,explain)

索引分类 分类含义特定关键字主键索引针对于表中主键创建的索引默认自动创建&#xff0c;只能有一个PRIMARY唯一索引避免同一个表中某数据列中的值重复可以有多个UNIQUE常规索引快速定位特定数据可以有多个全文索引全文索引查找的文本中的关键字&#xff0c;而不是比较索引中的…

04.领域驱动设计:了解聚合和聚合根,怎样设计聚合

目录 1、概述 2、聚合 3、聚合根 4、怎么设计聚合 4.1 聚合的构建过程主要步骤 第 1 步&#xff1a;采用事件风暴。 第 2 步&#xff1a;选出聚合根。 第 3 步&#xff1a;找出与聚合根关联的所有紧密依赖的实体和值对象。 第 4 步&#xff1a;画出对象的引用和依赖模型…

web前端项目-五子棋【附源码】

五子棋&#xff08;人机对弈&#xff09; 本项目【五子棋】是一款人机对弈的策略型棋类游戏。可以选择落子方&#xff1b;游戏难度和是否显示落子次序。游戏双方分别使用黑白两色的棋子&#xff0c;在棋盘直线与横线的交叉点上进行对弈。五子棋可以促进大脑发育、提高思维能力…

go语言基础之泛型

1.泛型 泛型是一种独立于所使用的特定类型的编写代码的方法。使用泛型可以编写出适用于一组类型中的任何一种的函数和类型。 1.1 为什么需要泛型 func reverse(s []int) []int {l : len(s)r : make([]int, l)for i, e : range s {r[l-i-1] e}return r }fmt.Println(reverse…

Docker—入门及Centos7安装

1、Docker入门 1.1、Docker是什么&#xff1f; Docker是基于Go语言实现的云开源项目。 Docker的主要目标是“Build&#xff0c;Ship&#xff0c;and Run Any App,Anywhere”&#xff0c;也就是通过对应组件的封装、分发、部署、运行等生命周期的管理&#xff0c;使用户的APP&…

指数计算(填空)

解题思路&#xff1a; 7的2020次方很大&#xff0c;需要用BigInteger来进行运算。 pow用来算指数运算。 remainder用来算BigInteger之间的取余。 解题代码&#xff1a; public static void main(String[] args) {BigInteger xnew BigInteger ("7");BigInteger ynew…

Tools工具安装及模板制作

Tools工具&#xff1a; 如何安装tools 1、右键单击——tools——挂载tools 2、把光盘里面的内容挂载到系统的临时挂载目录里面 mount /dev/cdrom /mnt 先卸载光盘 安装zip包 ********************************************** 使用yum源 1、挂载光盘 2、配置yum 写文件 安装…

java servlet勤工助学家教管系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java servlet 勤工助学家教管系统是一套完善的java web信息管理系统 serlvetdaobean mvc 模式开发 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myecli…

Vite+Vue3使用Vue-i8n笔记

一、下载依赖 vue-i18n yarn add vue-i18n创建存放语言文件的目录 以及配置文件的配置 我是在src/lang 新建index.ts、cn.ts、en.ts以及test文件夹其中再分别新建cn.ts以及en.ts /lang/index.ts 用于导出vue-i18n需要的配置对象 import en from "./en.ts"; import…

(八)循环控制中的break和continue关键字

文章目录 break提前结束整个循环示例代码现象 continue提前结束本次循环示例代码现象 break提前结束整个循环 示例 代码 #include <stdio.h>int main() {int numOfPerson ;int totalmoney 0;int money ;printf("这是一个使用break关键字的程序\n");for(numO…

2024年阿里云幻兽帕鲁Palworld游戏服务器优惠价格表

自建幻兽帕鲁服务器租用价格表&#xff0c;2024阿里云推出专属幻兽帕鲁Palworld游戏优惠服务器&#xff0c;配置分为4核16G和4核32G服务器&#xff0c;4核16G配置32.25元/1个月、10M带宽66.30元/1个月、4核32G配置113.24元/1个月&#xff0c;4核32G配置3个月339.72元。ECS云服务…

【Git配置代理】Failed to connect to github.com port 443 问题解决方法

前言&#xff1a; 在学习代码审计时&#xff0c;有时会需要使用git去拉取代码&#xff0c;然后就出现了如下错误 看过网上很多解决方法&#xff0c;觉得问题的关键还是因为命令行在拉取/推送代码时并没有使用VPN进行代理。 解决办法 &#xff1a; 配置http代理&#xff1a;…

前端canvas项目实战——简历制作网站(三)——右侧属性栏(线条宽度样式)

目录 前言一、效果展示二、实现步骤1. 实现线条宽度&#xff08;strokeWidth&#xff09;的属性模块2. 实线线条样式&#xff08;strokeDashArray&#xff09;的属性模块3. 意料之外的“联动” 三、Show u the code后记 前言 上一篇博文中&#xff0c;我们初步实现了右侧属性栏…

理顺 QR 分解算法

咱们网站的这个公式编辑器&#xff0c;估计是后台生成图片后贴回来的&#xff0c;固定分辨率而且分辨率不高。 还不如先离线 latex 生成 pdf 后再截图上来 1. Why QR When A and b are known, to solver the minimization of , where . The reduction of A to various canoni…