算法合集 —— 数组篇

news2024/11/15 13:53:30

算法 —— 数组

目录

      • 算法 —— 数组
        • 1.二分查找
          • 1.1二分查找习题集
        • 2.双指针法
          • 2.1双指针法习题集
        • 3.滑动窗口
          • 3.1滑动窗口习题集
        • 4.二维数组
          • 4.1二维数组习题集

1.二分查找

二分查找适用于,在有序排列的数组中查找某一指定元素。

其原理为范围搜索:如果这个元素在某一范围内,那么就一直缩小这个范围;如果这个元素不在此范围内,那么就换一个范围搜索。

假设我们有一有序数组{2,3,3,5,6,8},在此数组中查找5,流程图可以看成是这样:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Nydq7B7-1672462681017)(C:\Users\19433\AppData\Roaming\Typora\typora-user-images\image-20221228150615254.png)]

1.1二分查找习题集

704.二分查找

此题是二分查找的直接应用。需要注意的是,上述有关于二分查找的算法描述里的 end 指针,指向的是有序数组的最后一个元素,是一个左闭右闭的区间 [begin,end] ;但是在题目当中,使用左闭右开的区间 [begin,end) ,即 end 指针指向了有序数组中最后一个元素的下一个位置(end指向的是一个无效元素)。

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //遵循左闭右开的原则 [begin,end)

        int begin=0,end=nums.size();
        while(begin < end)      //遵循左闭右开
        {
            int mid = (begin+end)/2;        //锁定范围
            
            if(nums[mid] < target)
            {
                begin = mid+1;      //mid指向的元素已经确定了比target小,所以+1
            }
            else if(nums[mid] > target)
            {
                end = mid;      //遵循左闭右开原则,end=mid表示此范围不包括end指向的元素
            }
            else 
            {
                return mid;
            }
        }
        return -1;
    }
};

35.搜索插入位置

此题代码与上一个题一致。不过在最后没有找到指定的元素时,需要处理:返回一个位置,这个位置是指定元素应该在此有序数组中出现的位置。

分析可知,两个指针( begin 和 end )相邻的时候就是最后一次二分查找。又因为我们遵循左闭右开的原则,实际上这一次查找, begin 指向的元素就是最后一个元素了,如果这个元素都不是我们要查找的指定元素,就说明我们需要处理返回值的问题了。即使没有找到指定元素,但是一定可以保证的是:二分查找已经把该指定元素可能出现的范围缩小到最小、最精确了。也就是说,当这次二分查找没有找到指定元素的时候,又会进行一次 begin 和 end 的更新,更新之后 begin 和 end 一定是指向同一个位置的(即 begin = end),所以他们两个指向的位置,就是指定元素本该出现的位置。

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        //本题代码与上一题一致

        int begin=0,end=nums.size();

        while(begin < end)      //遵循左闭右开
        {
            int mid = (begin+end)/2;        //锁定范围

            if(nums[mid] < target)
            {
                begin = mid+1;      //mid指向的元素已经确定了比target小,所以+1
            }
            else if(nums[mid] > target)
            {
                end = mid;      //遵循左闭右开原则,end=mid表示此范围不包括end指向的元素
            }
            else
            {
                return mid;
            }
        }

        //return end;   
        return begin;       //两种都行    
    }
};

34.在排序数组中查找元素的第一个和最后一个位置

由上面两题的经验可以得出,每一次二分查找都能锁定一个位置( mid 位置),那么要查找指定元素(可能多次出现)在有序数组中的起始位置和结束位置,就一定有两次二分查找。那么查找该元素的起始位置一定是这个元素出现的区间的左边界;结束位置一定是这个元素出现的区间的右边界。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AQiaiHy4-1672462681018)(C:\Users\19433\AppData\Roaming\Typora\typora-user-images\image-20221228155549928.png)]

那么我们二分查找的目的,就是查找这两个边界。

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        //获取 target 出现的区间的两个边界
        int leftBorder = getLeftBorder(nums,target);
        int rightBorder = getRightBorder(nums,target);

        cout << leftBorder << " " << rightBorder << endl;
        if(leftBorder==-1 || rightBorder==-1)       //我们规定当target不存在时,返回值为-1
        {
            return {-1,-1};
        }

        else if(rightBorder - leftBorder >= 1)
        {
            return {leftBorder,rightBorder-1};
        }

        return {-1,-1};
    }
private:
    int getLeftBorder(vector<int>& nums, int target)
    {
        //遵循左闭右开原则
        
        int begin=0,end=nums.size();

        int leftBorder = -1;        //左边界
        while(begin < end)
        {
            int mid = (begin+end)/2;

            if(nums[mid] >= target)      //既然mid位置的元素大于或等于了target,那么继续搜索的范围就一定在左边
            {
                end = mid;
                leftBorder = end;
            }
            else 
            {
                begin = mid+1;
            }
        }

        return leftBorder;
    }

    int getRightBorder(vector<int>& nums, int target)
    {
        //遵循左闭右开原则
        
        int begin=0,end=nums.size();

        int rightBorder = -1;        //右边界
        while(begin < end)
        {
            int mid = (begin+end)/2;

            if(nums[mid] > target)      
            {
                end = mid;
            }
            else        //既然mid位置的元素小于或等于了target,那么继续搜索的范围就一定在右边
            {
                begin = mid+1;
                rightBorder = begin;
            }
        }

        return rightBorder;
    }
};

69.x的平方根

这个题也是一道典型的二分查找问题。就是在 0~x 区间内,查找 x 的算数平方根。

这道题的关键在于到底是从右往左找还是从左往右找。因为 x 的算数平方根可能不是一个整数,是一个浮点数,但是测试用例明确表示了最后的结果左取整(即使算数平方根是 2.999……,左取整也是 2),所以我们必须从左往右找,才能符合左取整这个条件。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tZj2woQp-1672462681019)(C:\Users\19433\AppData\Roaming\Typora\typora-user-images\image-20221228164943138.png)]

class Solution {
public:
    int mySqrt(int x) {

        //在 0~x 范围内查找满足条件的数字

        long long begin=0,end=(long long)x+1;        //遵循左闭右开原则

        int last = 0;
        while(begin < end)
        {
            int mid = (begin+end)/2;

            if((long long)mid*mid <= x)     //从左往右找
            {
                last = mid;
                begin = mid+1;

            }
            else
            {
                end = mid;
            }
        }

        return last;
    }
};

367.有效的完全平方数

这道题是纯粹的二分查找算法,分析过程不再赘述。

class Solution {
public:
    bool isPerfectSquare(int num) {

        //遵循左闭右开原则
        long long begin=0,end=(long long)num+1;

        while(begin < end)
        {
            int mid=(begin+end)/2;

            if((long long)mid*mid < num)
            {
                begin = mid+1;
            }
            else if((long long)mid*mid > num)
            {
                end = mid;
            }
            else    
            {
                return mid;
            }
        }

        return false;
    }
};

2.双指针法

双指针法可以说是数组算法里最重要的算法。双指针的算法,第一能够提高代码效率;第二能够在基本的双指针操作上衍生出其他进阶算法(例如滑动窗口算法)。

双指针适用于任何物理内存空间连续的数组或者字符串。下面使用一道习题,来体会双指针的算法。

27.移除元素

这道题是基本的双指针法的直接应用,使用双指针算法后,能够将以前的暴力删除元素(时间复杂度为O(N^2))优化为时间复杂度只有O(N)的算法。

class Solution {
public:
   int removeElement(vector<int>& nums, int val) {
       
       //思路就是将数组中非 val 的元素赋给新数组
       //只不过这个新数组就是原数组

       int slow=0,fast=0;
       while(fast < nums.size())
       {
           if(nums[fast] != val)
           {
               nums[slow++]=nums[fast];
           }

           ++fast;
       }

       return slow;        //slow 指向删除元素后的数组的最后一个元素位置的下一个位置,就是长度
   }
};
2.1双指针法习题集

26.删除有序数组中的重复项

我们用画图的形式来描述我们的思路:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uhcfs8pz-1672462681019)(C:\Users\19433\AppData\Roaming\Typora\typora-user-images\image-20221229132117814.png)]

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {

        int slow = 0,fast = 0;

        while(fast < nums.size())
        {
            if(nums[fast] != nums[slow])
            {
                ++slow;
                nums[slow] = nums[fast];
            }

            ++fast;
        }

        return slow+1;		//最后 slow 一定指向最后一个有效元素,所以 slow+1 为长度
    }
};

283.移动零

思路与上题一致,是双指针算法的直接体现。

具体步骤为:slow 和 fast 指向数组的起始位置,fast 一直向后遍历,如果 fast 指向的元素不为 0 ,那么此元素就与 slow 指向的元素进行交换,然后 slow 向后移动一个位置,fast 继续向后遍历。这个操作会保证当 slow 和 fast 都指向非 0 元素时发生一次原地交换,也就是说只要 fast 指向的为非零元素,就无差别的进行交换,这样可以保证非零元素的相对顺序不会被破坏。

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int slow = 0,fast = 0;

        while(fast < nums.size())
        {
            if(nums[fast] != 0)
            {
                swap(nums[slow++],nums[fast]);
            }

            ++fast;
        }

    }
};

977.有序数组的平方

我们要把有序数组的每个元素进行平方运算,然后将此数组再进行升序排列。最容易想到的暴力思就是挨个遍历数组的每个元素然后进行平方运算,最后将此数组排序。但是我们不用暴力的做法。

我们运用双指针的算法。我们可以发现,有序数组是升序排列的并且含有负数,这就意味着,每个元素进行平方运算后,总是呈“两边大,中间小”。那么我们就使用两个指针 begin 和 end 分别指向此数组的头和尾,案后比较这两个指针指向的元素大小,将较大元素头插到另一个新的数组,然后 begin 和 end 向中间靠拢。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OKzELV6D-1672462681020)(C:\Users\19433\AppData\Roaming\Typora\typora-user-images\image-20221230124857651.png)]

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {

        vector<int> ret(nums.size());       //等大小的新数组
        int index = ret.size()-1;     //从后往前放

        int begin=0,end=nums.size()-1;      //双指针
        while(begin <= end)     //左闭右闭区间,当最后一次 begin==end 时也要进入循环
        {
            long long numBegin = nums[begin]*nums[begin];
            long long numEnd = nums[end]*nums[end];

            if(numBegin > numEnd)
            {
                ret[index--] = numBegin;
                ++begin;
            }
            else
            {
                ret[index--] = numEnd;
                --end;
            } 
        }

        return ret;
    }
};

3.滑动窗口

滑动窗口就是双指针法的进阶算法,两个指针在某一区间内滑来滑去像一个滑动的窗口一样。具体看一道例题。

209.长度最小的子数组

暴力解法就是利用两个嵌套的 for 循环解决,这里不再赘述(超时,过不了OJ)。

我们利用滑动窗口的算法来解决这道题。首先定义两个指针分别为 begin 和 end 指向数组的起始位置,然后 end 一直向后移动,直到 begin 和 end 这个闭区间([begin,end])内的所有元素和大于等于 target,此时记录这个区间的长度;然后 begin 也向后移动,如果每次移动之后的 begin 和 end 区间内的所有元素和大于等于 target ,begin 就一直向后移动,直到不满足这个条件。也就是说,begin 和 end 区间内所有元素和并没有大于等于 target ,那么 end 就一直往后移动;如果满足这个条件,那么就是 begin 一直往后移动。满足条件的时候记录长度,最后的结果只需要这些长度中的最小长度即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Wjka6aOc-1672462681020)(C:\Users\19433\AppData\Roaming\Typora\typora-user-images\image-20221230133311627.png)]

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {

        int begin=0,end=0;      //一开始 begin 和 end 指向同一位置
        int lenMin = INT32_MAX;     //最小长度

        int sum = 0;        //区间和
        while(end < nums.size())
        {
            sum += nums[end];
            
            while(sum >= target)        //如果满足条件 begin 就一直向后移动
            {
                lenMin = min(lenMin,end-begin+1);       //挑选长度最小的区间

                sum -= nums[begin];     //每次移动都会导致区间和改变
                ++begin;
            }

            ++end;
        }

        if(lenMin == INT32_MAX)     //没有任何一种情况满足 >=target时
        {
            return 0;
        }
        return lenMin;
    }
};
3.1滑动窗口习题集

904.水果成篮

与上一道题一样,这道题也是滑动窗口的经典习题。题目的意思就是求一个"长度最长的子数组",只不过这个子数组有且仅有两个不同的元素。

思路可以是这样的:既然我们最后的结果必须包含两个不同的元素,那么我们定义一个用来记录种类的变量 types ,然后定义一个计数数组,end 指针向后移动时将碰到的每一个元素计数(计数之后如果为 1 ,那么 types 就加 1);直到 begin 和 end 这个区间内 types 为 3(types 为 3 时,刚好不满足子数组的要求),end 停止移动,并将现在的有效区间(begin 和 end区间内 types 为 2)长度做记录,然后向后移动 begin ,直到 begin 和 end 这个区间内 types 不为 3,begin 停止移动,然后再移动 end。

由此可见,滑动窗口的套路都是一样的。最后的结果,我们只需要返回一个最长的长度即可。

class Solution {
public:
    int totalFruit(vector<int>& fruits) {

        //无脑定义两个指针
        int begin=0,end=0;

        int types = 0;      //种类变量
        int cnt[fruits.size()];     //根据题目要求定义 0<=fruits[i]<fruits.length
        memset(cnt,0,sizeof(cnt));

        int lenMax = 0;     //长度
        while(end < fruits.size())
        {
            if(++cnt[fruits[end]] == 1)     //将 end 碰到的每个元素做一个计数
            {
                ++types;
            }

            while(types > 2)        //当 types 为3时,就能保证找到最长子数组
            {

                if(--cnt[fruits[begin]] == 0)       //begin 向后移动,计数就得减少
                {
                    --types;
                }
                ++begin;
            }

            /*当types <= 2 时,对长度进行记录*/
            lenMax = max(lenMax,end-begin+1);       
            ++end;
        }
        return lenMax;
    }
};

4.二维数组

二维数组常见的算法就是按要求打印一些图案,这实际上并没有什么算法,就是逻辑问题。我们以一道题举例。

59. 螺旋矩阵 II

题目的意思很简单,顺时针遍历二维数组。我们要思考的关键就在于每一行每一列到底遍历多少个元素,我们采用的做法是左闭右开原则。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SS67qxV9-1672462681021)(C:\Users\19433\AppData\Roaming\Typora\typora-user-images\image-20221231121847544.png)]

最后就剩下中间的位置没有遍历到,单独处理即可。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>> ret(n);
        for(int i=0;i<n;i++)
        {
            ret[i].resize(n);
        }

        int start_x=0,start_y=0;        //每一圈的起始位置
        int cnt = n/2;      //遍历这个二维数组需要的圈数
        
        int i=0,j=0;        //行、列
        int offset = 1;     //左闭右开,需要记录一下偏移量

        int num = 1;
        while(cnt--)
        {
            for(j=start_y;j<n-offset;j++)
            {
                ret[start_x][j] = num++;
            }

            for(i=start_x;i<n-offset;i++)
            {
                ret[i][j] = num++;
            }

            for(;j>start_y;j--)
            {
                ret[i][j] = num++;
            }

            for(;i>start_x;i--)
            {
                ret[i][j] = num++;
            }

            /*每一圈结束后,偏移量、起始位置都需要更新*/
            ++offset;
            ++start_x;
            ++start_y;
        }

        if(n%2 == 1)        //n为奇数时,要处理最后的中间位置
        {
            ret[start_x][start_y] = num++;      //最后的起始位置就是中间位置
        }
        return ret;
    }
};
4.1二维数组习题集

54.螺旋矩阵

这道题与上一题非常相似,但是这道题的难度要稍微高一些。

第一,这道题并不一定是正方形矩阵;第二,不好掌握圈数;第三,不好掌握最后剩下的一些元素没有遍历到该如何处理。

我们可以使用两个变量 row 和 col 分别记录二维数组的行、列。那么圈数就是行和列的最小值再除以2;最后有一些元素没有遍历到,如果 row > col ,那么就一定剩下一列没有处理;如果 row < col ,那么就一定剩下一行没有处理。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nl6kdmrZ-1672462681021)(C:\Users\19433\AppData\Roaming\Typora\typora-user-images\image-20221231123852168.png)]

那么这一行或者这一列的起始位置与上一道题一样。在这个基础上,处理一下到底是再进行一次行便利还是列遍历,遍历多少个元素即可。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {

        //无脑写两个起始位置
        int start_x=0,start_y=0;

        int row = matrix.size();        //行
        int col = matrix[0].size();     //列

        int cnt = min(row,col)/2;       //圈数

        vector<int> ret;

        int offset = 1;
        int i=0,j=0;

        /*老套路*/
        while(cnt--)
        {
            for(j=start_y;j<col-offset;j++)
            {
                ret.push_back(matrix[start_x][j]);
            }

            for(i=start_x;i<row-offset;i++)
            {
                ret.push_back(matrix[i][j]);
            }

            for(;j>start_y;j--)
            {
                ret.push_back(matrix[i][j]);
            }

            for(;i>start_x;i--)
            {
                ret.push_back(matrix[i][j]);
            }

            ++offset;
            ++start_x;
            ++start_y;
        }

        if(min(row,col)%2 == 1)     //如果是奇数,就必定剩下某一行或者某一列需要处理
        {
            if(row > col)       //此时剩下一列没有处理
            {
                int times = row - col + 1;      //剩下的元素个数
                int i=start_x;

                while(times--)
                {
                    ret.push_back(matrix[i++][start_y]);
                }
            }
            else
            {
                int times = col - row + 1;      //剩下的元素个数
                int j=start_y;

                while(times--)
                {
                    ret.push_back(matrix[start_x][j++]);
                }
            }
        }

        return ret;
    }
};

剑指 Offer 29. 顺时针打印矩阵

这一道题与上一道题是一模一样的,只不过需要注意,这道题需要我们对形参进行判空。即当形参的有效元素为 0 时,我们需要返回一个空容器。

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        if(matrix.size() == 0)
        {
            return {};
        }

        //无脑写两个起始位置
        int start_x=0,start_y=0;

        int row = matrix.size();        //行
        int col = matrix[0].size();     //列

        int cnt = min(row,col)/2;       //圈数

        vector<int> ret;

        int offset = 1;
        int i=0,j=0;

        /*老套路*/
        while(cnt--)
        {
            for(j=start_y;j<col-offset;j++)
            {
                ret.push_back(matrix[start_x][j]);
            }

            for(i=start_x;i<row-offset;i++)
            {
                ret.push_back(matrix[i][j]);
            }

            for(;j>start_y;j--)
            {
                ret.push_back(matrix[i][j]);
            }

            for(;i>start_x;i--)
            {
                ret.push_back(matrix[i][j]);
            }

            ++offset;
            ++start_x;
            ++start_y;
        }

        if(min(row,col)%2 == 1)     //如果是奇数,就必定剩下某一行或者某一列需要处理
        {
            if(row > col)       //此时剩下一列没有处理
            {
                int times = row - col + 1;      //剩下的元素个数
                int i=start_x;

                while(times--)
                {
                    ret.push_back(matrix[i++][start_y]);
                }
            }
            else
            {
                int times = col - row + 1;      //剩下的元素个数
                int j=start_y;

                while(times--)
                {
                    ret.push_back(matrix[start_x][j++]);
                }
            }
        }

        return ret;
    }
};

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

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

相关文章

opencv-python常用函数解析及参数介绍(四)——图像阈值

图像阈值处理前言1.改变图像颜色灰度图HSV图2.图像阈值图像中数值对应的效果函数与参数阈值处理效果前言 在很多任务当中&#xff0c;首要的任务就是对图像进行阈值处理&#xff0c;为后续其他操作做准备&#xff0c;本文将介绍5种阈值处理的方法以及参数设置&#xff0c;同时…

API 概述

API 概述目录概述需求&#xff1a;设计思路实现思路分析1.High-Level API &#xff1a;用于事务边界定义、控制及事务状态查询。2.2. High-Level API5.2.2 GlobalTransactionContextTransactionalTemplateLow-Level API参考资料和推荐阅读Survive by day and develop by night.…

网络协议总结

网络协议总结网络模型网络协议TCP/IP 模型网络接入层封装与解封装实际数据传输举例发送数据包接收数据包网络接口处理IP 模块处理TCP 模块处理应用程序处理网络构成通信介质与数据链路网卡二层交换机路由器 / 三层交换机![在这里插入图片描述](https://img-blog.csdnimg.cn/a8e…

F280049C General-Purpose Input/Out(GPIO)

​ 文章目录GPIO8.1 简介8.2 配置概述8.3 ADC引脚上的数字输入&#xff08;AIO&#xff09;8.4 数字通用I/O控制8.5 输入限定8.5.1 异步输入8.5.2 仅与SYSCLKOUT同步8.5.3 使用采样窗口进行鉴定8.6 SPI信号8.7GPIO和外设引脚复用8.7.1GPIO复用8.7.2 外设复用8.8 内部上拉配置要…

基础架构:一条SQL查询语句是如何执行的?

这是专栏的第一篇文章,我想来跟你聊聊 MySQL 的基础架构。我们经常说,看一个事儿千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题。同样,对于 MySQL 的学习也是这样。平时我们使用数据库,看到的通常都是一个整体。比如,你有个最简单的表,表…

DML语句

DML语句目录概述需求&#xff1a;设计思路实现思路分析1.SQL 实例2.UPDATE3.DELETE4.SELECT5.是TRUNCATE参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wai…

数字DNA盗窃可能会在2023年到来

攻击者总是在不断发展并寻找访问数字系统的方法。随着人工智能的使用越来越多&#xff0c;量子计算有望很快成为现实&#xff0c;网络威胁格局的变化比以往任何时候都快。 当谈到网络安全时&#xff0c;我们应该始终尝试着眼于即将发生的事情以及它将产生的影响。我们不能只是…

操作系统实验7:终端设备字符显示的控制

实验目的 加深对操作系统设备管理基本原理的认识&#xff0c;实践键盘中断、扫描码等概念&#xff1b;通过实践掌握Linux 0.11对键盘终端和显示器终端的处理过程。 实验内容 本实验的基本内容是修改Linux 0.11的终端设备处理代码&#xff0c;对键盘输入和字符显示进行非常规…

2022-我的年终总结

去年年末&#xff0c;我也写了一篇年终总结。去年这一年是极度繁忙的一年&#xff0c;因各种原因&#xff0c;过年没回家&#xff0c;一个人在宿舍度过了凄凉的春节。而今年是丰收的一年&#xff0c;去年所付出的一切都在今年获得了回报&#xff0c;我也迎来新的生活。 新的生活…

过年春联不可少,python带你制作春联,体验不一样的过年氛围

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 每逢春节&#xff0c;无论城市还是农村&#xff0c; 家家户户都要挑漂亮的红春联贴于门上&#xff0c;辞旧迎新&#xff0c;增加喜庆的节日气氛。 据说这一习俗起于宋代&#xff0c;在明代开始盛…

我是阿豪我的2022年年终总结.

时光如白驹过隙般&#xff0c;飞逝而过&#xff0c;来不及细品岁月的美好。一晃&#xff0c;2022年就过去了&#xff01; 明天新的一年就来了。回忆一下2022一年都干了什么。 3月份背了大概200多道的前端面试题&#xff0c;疯狂的刷面试题&#xff0c;一天不刷几道面试题心里…

ffmpeg从某站提取视频、音频、详解

ffmpeg从某站提取视频、音频、详解 事件背景 准备链接 第一步安装下载 ffmpeg是开源软件&#xff0c;安装网址http://ffmpeg.org/download.html#build-windows 本人用的windows10系统 打开网址后随便你怎么下载都行&#xff0c;Git、或者直接下等等 按图片输入上述网址也…

【攻防世界】Web very_easy_sql

做了web才发现&#xff0c;原来自己是真的什么都不懂啊&#xff0c;不过也好&#xff0c;说明我有很大的进步空间呢 不闲聊了&#xff0c;来看题目 打开是一个登录界面&#xff0c;我们抓包看看返回些什么 返回包有三个需要注意的地方&#xff0c;我都用框框圈起来了 有一个S…

【C++】map 与 set 的介绍与使用、力扣:692. 前K个高频单词

目录 一、关联式容器 二、键值对 三、set 3.1 set 的介绍 3.2 set 的使用 3.3. set 的使用举例 四、map 4.1 map的介绍 3.2 map 的使用 4.3 map的使用举例 五、经典练习题 1.set的使用 2.map的使用 思路一(稳定排序)&#xff1a; 思路二(priority_queue)&#x…

jvm参数说明

-Xmx3550m&#xff1a;设置JVM最大堆内存为3550M。 -Xms3550m&#xff1a;设置JVM初始堆内存为3550M。此值可以设置与-Xmx相同&#xff0c;以避免每次垃圾回收完成后JVM重新分配内存。 -Xss128k&#xff1a;设置每个线程的栈大小。JDK5.0以后每个线程栈大小为1M&#xff0c;之…

新式 AIMD 拥塞控制

周三晚上发了一则朋友圈&#xff0c;今天整理一下&#xff1a; ​ AIMD 过程可推导出 TCP 吞吐公式&#xff1a; TaRTTbpT\dfrac{a}{RTT}\dfrac{b}{\sqrt{p}}TRTTa​p​b​ a&#xff0c;b 分别为与 AIMD 参数和过程有关&#xff0c;该公式结论内置公平性。设 MSS 1460&…

【MySQL】九,MySQL逻辑架构剖析

服务器处理客户端请求 Connectors 外部的各种类型的连接客户端。 第一层&#xff1a;连接层 客户端访问 MySQL 服务器前&#xff0c;首先要建立 TCP 连接。 经过三次握手成功建立连接后&#xff0c;MySQL对传输过来的账号密码做身份认证、权限获取。 如果用户名密码错误&am…

【Iava】抽象类和接口

祝早日驱散阴霾 文章目录1. 抽象类1.1 抽象类的概念1.2 抽象类的使用注意事项1.3 抽象类的作用2. 接口2.1 接口的定义2.2 接口的使用规则2.3 创建对象拷贝,实现Cloneable3. 抽象类和接口的区别1. 抽象类 1.1 抽象类的概念 抽象类,顾名思义,这是不是一个具体的类,没有实际的功…

四旋翼无人机学习第17节--封装上传github与gitee

0 前言 经过一段时间的绘制&#xff0c;终于绘制完项目所需的封装。为了更好的管理封装&#xff0c;我准备把封装与焊盘上传到github与gitee&#xff0c;方便之后的管理工作。 1 文件上传gitee 注册这里就不作介绍咯。 1、首先点击新建仓库。 2、设置仓库的名称与项目介绍&…

GO语言初始化数据结构的方法你知道吗?

xdm 我是阿兵云原生 使用 golang 进行编码过程中&#xff0c;你们都是如何初始化数据结构的呢 GO 里面提供了 2 个关键字来进行初始化数据结构 newmake 不过有时候我也会直接使用花括号的方式直接就初始化&#xff0c;例如这样&#xff1a; name : []string{"xiaomot…