专题七_分治_快排_归并_算法专题详细总结

news2024/11/15 21:50:17

目录

分治

一、分治思想的概念

二、分治思想的步骤

1. 颜⾊分类(medium)

解析:

2. 快速排序(medium)

解析:

总结:

3. 快速选择算法(medium)

解析:

1)暴力:

2)优化:快速选择算法

总结:

4. 最⼩的 k 个数(medium)

解析:

1)暴力:

2)优化:快速选择排序

总结:

分治 - 归并排序

5. 归并排序(medium)

解析:

1)快排前面专题讲的很清楚,可以试试

2)堆排

3)归并排序

6. 归并排序(medium)

​编辑解析:

1)暴力:

2)优化:

1.左半部分跳完->右半部分->一左一右​编辑

2.左半部分跳完->左排序->右半部分跳完->右排序->一左一右 + 排序

3.通过2的排序,此时已经变成了一个归并排序来解决问题。

4.拓展:

总结:

7. 计算右侧⼩于当前元素的个数(hard)

解析:

1)暴力:

2)优化:分治_归并

总结:

8. 翻转对(hard)

解析:

归并排序:


分治

一、分治思想的概念

分治,即 “分而治之”。其核心思想是将一个复杂的问题分成若干个规模较小、相互独立且与原问题形式相同的子问题,分别求解这些子问题,然后将子问题的解合并起来,得到原问题的解。

二、分治思想的步骤

  1. 分解(Divide):

    • 将原问题分解为若干个规模较小、相互独立的子问题。这些子问题的形式与原问题相同,只是规模更小。
    • 例如,在归并排序中,将待排序的数组分成两个规模大致相等的子数组。
  2. 解决(Conquer):

    • 递归地求解各个子问题。如果子问题的规模足够小,则直接求解。
    • 对于归并排序,对子数组继续进行划分,直到子数组的长度为 1 或 2 时,直接进行排序。
  3. 合并(Combine):

    • 将子问题的解合并成原问题的解。
    • 在归并排序中,将两个已排序的子数组合并成一个有序的数组。

将一个大问题分解成许多个小问题,然后这些小问题在一一进行解决后合并,这种思想就像快排一一,是一个很好的切入点。

先来一道简单的例题,理解一下分治的简单思想,数组分三块,这里跟前面专题移动零一样运用双指针,这里多加了一个指针,也可以称为三指针,其中mid指针来分别将当前数组的元素跟left right位置的元素进行比较,然后进行交换。简单的分治思想将数组分三块,这里了解后,后面运用数组分三块思想真的很常见。

1. 颜⾊分类(medium)

题目意思就是让我们把数组有序排列,数组里面只有0 1 2三种元素

解析:

那么最开始想到的肯定就是三指针办法,定义left=-1 , mid=0 ,right=n,三个指针然后开始遍历数组,将数组分成三块

这里的数组就包含3种元素,0,1,2,那么1就可以当作是key值来让它跟nums[mid]进行比较。

如果nums[mid] < key , 就说明nums[mid]==0,要往前进行交换,那么就让left先往前走一步,两者就开始进行交换 mid就在往后走一步,即

if(nums[mid]<1) swap(nums[++left],nums[mid++]); 

如果nums[mid]==1,就证明此时mid指针正走在中间区域,那么就直接跳过就好,这又就是为什么要进行数组分三块,只有这样,才能将快排的时间复杂度降低,否则数组分两块,当整个数组全是重复元素的时候,时间复杂度就又退化到O(N^2) ,而数组分三块却只是O(N),只用遍历一遍。

else if(nums[mid]==1) mid++;

最后如果nums[mid]>key 那么就要跟最后面的right进行交换,先--right,防止越界,交换后,mid不能动,因为不能保证交换过来的数字是否满足条件,所以要重新判断

else swap(nums[--right],nums[mid]);

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int left=-1,right=nums.size(),mid=0;

        while(mid<right)
        {
            if(nums[mid]<1) swap(nums[++left],nums[mid++]);
            else if(nums[mid]==1) mid++;
            else swap(nums[--right],nums[mid]);
        }
    }
};

总结:

相对来说这题比较简单,数据量也比较少,只用考虑 0 1 2的位置关系

了解数组分三块后,我们就开始进行分治,可能我们只进行一趟,不能够满足我们的条件,只是把==key的值放在它正确的位置,而左右两边只是无序的小于key值 或大于key值,那么我们进行递归操作,就可以完成整个数组的排序任务。

2. 快速排序(medium)

题意很简单,就是在O(nlogn)下完成排序,那么首先想到的就是快排,也是本章分治思想。

解析:

这里分治思想体现的淋漓尽致,那么我们只需要想上一题一样,数组分三块,然后进行排序交换,后面再递归给出我的子数组的范围,只要达到结束条件(left>=right) 即可返回整个数组。

快排,数组分三块思想,这样可以将数组分两块的不足给避免
当数组分两块:如果数组里面全部都是相同的元素,那么时间复杂度就会降低到O(N^2)

当数组分三块,那么数组内就会变成【小于key值的元素】  【==key值的元素】  【大于key值的元素】  那么当数组内全部都是相同元素的时候,就可以只移动mid指针,之对数组进行一次遍历,时间复杂度为O(N^2)  当一趟排序完成后,那么就进行递归,因为给的范围是【l,r】 那么要创建移动的 指针left,right,mid,来表示left和right最终移动的位置,然后就可以得出递归的范围,因为【left+1,right-1】 是==key的元素,那么【l,left】 【right,r】 的两个范围就要继续进行递归完成

最后就是随机数,用srand(time(NULL)) 来种下一颗随机数的种子,然后获取随机数int r=rand() 然后以免取得的随机数下标越界,那么就要对小标进行控制在[l,r]之间r%(right-left+1)+left

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        srand(time(NULL)); //开始随机
        qsort(nums,0,nums.size()-1);
        return nums;
    }
    void qsort(vector<int>& nums,int l,int r)
    {
        if(l>=r) return;
        
        //定义三个指针
        int left=l-1,right=r+1,mid=l;

        //获得随机数
        int key=getRand(nums,l,r);
        while(mid<right)
        {
            if(nums[mid]<key) swap(nums[++left],nums[mid++]);
            else if(nums[mid]==key) mid++;
            else swap(nums[--right],nums[mid]);
        }

        //递归
        //[l,left] [left+1,right-1] [right,r]
        qsort(nums,l,left);
        qsort(nums,right,r);
    }

    int getRand(vector<int>& nums,int left,int right)
    {
        int r=rand();
        return nums[r%(right-left+1)+left];
    }
};

总结:

这个代码真的很完美强烈建议默写一百遍!随机取值,数组分三块~

3. 快速选择算法(medium)

这题也是本个章节的重点,topK问题

解析:

1)暴力:

肯定就是先将数组完全排序好后,然后再返回第k大的元素,但是题目要求O(N) 所以如果排序就成了O(NlogN)

2)优化:快速选择算法

快速选择算法也可以认为是快排的一种小变形,只是返回的是特定的值或者区间,所以没有必要完全将数组排完序后再进行返回,那么这样就可以有效的降低时间复杂度

求出数组中第K个最大元素,在时间复杂度达到O(N)的条件下,首先就该考虑快排,将数组分三块,能够很接近O(N) 

那么这一题只是求出数组第K个最大的元素,只要返回那一个值就行,那么最开始我就是运用快排,然后返回k大的下标,后来发现确实也可以不用全部都排完序后在返回,可以排完k大的数后直接返回即可。

数组分三块【<key】 【==key】  【>key】 
1) 当大于key的数组里面排序在[right,r]之间数字个数为k的时候就直接返回
2)当大于key的数字个数不够k个,那就再加上==key的数字个数大于等于k个的时候就返回key
3)当==key和>key的数字个数和都小于k,那么就要到<key里面去找满足条件的,
 

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        srand(time(nullptr));
        return qsort(nums,0,nums.size()-1,k);
    }

    int qsort(vector<int>& nums,int l,int r,int k)
    {
        if(l>=r) return nums[l];

        int left=l-1,right=r+1,mid=l;
        int key=getRand(nums,l,r); 
        while(mid<right)
        {
            if(nums[mid]<key) swap(nums[++left],nums[mid++]);
            else if(nums[mid]==key) mid++;
            else swap(nums[--right],nums[mid]);
        }

        //分情况讨论:
        int c=r-right+1,b=right-left-1;
        if(c>=k) return qsort(nums,right,r,k); //缩小排序范围
        else if(b+c>=k) return key;
        else return qsort(nums,l,left,k-b-c);
    }

    int getRand(vector<int>& nums,int left,int right){
        int r=rand();
        return nums[r%(right-left+1)+left];
    }
};

总结:

这题是跟上题快排大差不差,唯一不同就是再最后的递归部分,考虑清除边界条件

b=right - 1 - (left + 1) +1 = right - left - 1;

//分情况讨论:
        int c=r-right+1,b=right-left-1;
        if(c>=k) return qsort(nums,right,r,k);
        else if(b+c>=k) return key;
        else return qsort(nums,l,left,k-b-c);

4. 最⼩的 k 个数(medium)

这一题仍然是TopK问题,那么这题正好跟上一题相反,找到最小的k个数

解析:

1)暴力:

仍然就是快排后返回数组

2)优化:快速选择排序

快速选择排序,仍然是topK问题,不用完全排序只需要排序排个大概,了解大概元素的分布,前几个元素在哪,然后直接返回,时间复杂度O(N),但是其实我觉得还是排序方便O(NlogN) 只要你排好序了,想怎么返回就怎么返回

class Solution {
public:
    vector<int> inventoryManagement(vector<int>& nums, int k) {
        srand(time(nullptr));
        qsort(nums,0,nums.size()-1,k);
        return {nums.begin(),nums.begin()+k};
    }

    void qsort(vector<int>& nums,int l,int r,int k)
    {
        if(l>=r) return;

        int left=l-1,right=r+1,mid=l;
        int key=getRand(nums,l,r);
        while(mid<right)
        {
            if(nums[mid]<key) swap(nums[++left],nums[mid++]);
            else if(nums[mid]==key) mid++;
            else swap(nums[--right],nums[mid]);
        }

        //求[<key] [==key] [>key] 的个数
        int a=left-l+1,b=right-left-1;
        if(a>=k) qsort(nums,l,left,k);
        else if(a+b>=k) return;
        else qsort(nums,right,r,k-a-b);

    }

    int getRand(vector<int>& nums,int left,int right)
    {
        return nums[rand()%(right-left+1)+left];
    }
};

总结:

想着一系列TopK问题都是利用数组分三块,然后在递归部分来进行缩小范围,直到满足结束条件,最后终止。

分治 - 归并排序

5. 归并排序(medium)

题目意思就是排序这个数组,但是我们这个专题采用归并的思想来进行,将大数组分成小数组,然后合并已经排好序的小数组。

解析:

1)快排
前面专题讲的很清楚,可以试试

2)堆排

也是很不错的排序O(NlogK)

3)归并排序

将大数组分成一小份一小份的小数组,然后对小数组进行排序,再将两个小数组进行归并,一直取较小的值合并到原数组中。

然后对没有排完的数组进行剩余的加入,最后再将排好序数组放入到原数组里。

 //快排版

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        srand(time(NULL)); //开始随机
        qsort(nums,0,nums.size()-1);
        return nums;
    }
    void qsort(vector<int>& nums,int l,int r)
    {
        if(l>=r) return;
        
        //定义三个指针
        int left=l-1,right=r+1,mid=l;

        //获得随机数
        int key=getRand(nums,l,r);
        while(mid<right)
        {
            if(nums[mid]<key) swap(nums[++left],nums[mid++]);
            else if(nums[mid]==key) mid++;
            else swap(nums[--right],nums[mid]);
        }

        //递归
        //[l,left] [left+1,right-1] [right,r]
        qsort(nums,l,left);
        qsort(nums,right,r);
    }

    int getRand(vector<int>& nums,int left,int right)
    {
        int r=rand();
        return nums[r%(right-left+1)+left];
    }
};

//归并版

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        mergeSort(nums,0,nums.size()-1);
        return nums;
    }

    void mergeSort(vector<int>& nums,int left,int right)
    {
        if(left>=right) return;

        int mid=(left+right)/2;
        mergeSort(nums,left,mid);
        mergeSort(nums,mid+1,right);

        vector<int> tmp(right-left+1);
        //合并两个有序数组
        int cur1=left,cur2=mid+1,i=0;
        while(cur1<=mid&&cur2<=right)
            tmp[i++]=nums[cur1]<=nums[cur2]?nums[cur1++]:nums[cur2++];

        //处理没有遍历完的数组
        while(cur1<=mid) tmp[i++]=nums[cur1++];
        while(cur2<=right) tmp[i++]=nums[cur2++];

        //还原
        for(int i=left;i<=right;i++) nums[i]=tmp[i-left];//tmp从0开始计数
    }
};

6. 归并排序(medium)

求解数组里面前一个数大于后一个数的 对数。

解析:

1)暴力:

就是两层for循环来暴力枚举所有两个数之间的情况,符合ret++,但是肯定会超时

2)优化:

先将数组分两块,

1.左半部分跳完->右半部分->一左一右

2.左半部分跳完->左排序->右半部分跳完->右排序->一左一右 + 排序

3.通过2的排序,此时已经变成了一个归并排序来解决问题。

算法原理:数组程升序状态

策略一:找出该数之前,有多少个数比我大

4.拓展:

为什么这题要用升序数组?不能用降序数组吗?降序数组就没有作用吗?

那么思考再什么情况下利用降序比较合理呢?

策略二:找出该数之后,有多少个数比我小(适合用降序)

因为采用降序,nums[cur1] 是第一次比nums[cur2]要大的,所以就完全可以计算出cur2后面所有元素的个数,因为cur2 前面的元素都要比cur1要大。

class Solution {
public:
    int tmp[50001];
    int reversePairs(vector<int>& record) {
        return mergeSort(record,0,record.size()-1);
    }

    int mergeSort(vector<int>& nums,int left,int right)
    {
        if(left>=right) return 0;
        int ret=0;

        int mid=(left+right)/2;
        //1.左统计+左排序
        ret+=mergeSort(nums,left,mid);

        //2.右统计+右排序
        ret+=mergeSort(nums,mid+1,right);

        //3.一左一右 统计+排序
        int cur1=left,cur2=mid+1,i=0;
        while(cur1<=mid&&cur2<=right)
        {
            if(nums[cur1]<=nums[cur2])
            {
                tmp[i++]=nums[cur1++];
            }
            else 
            {
                ret+=mid-cur1+1;
                tmp[i++]=nums[cur2++];
            }
        }
        while(cur1<=mid) tmp[i++]=nums[cur1++];
        while(cur2<=right) tmp[i++]=nums[cur2++];
        for(int j=left;j<=right;j++) nums[j]=tmp[j-left];

        return ret;
    }
};

总结:

首先由数组能不能分成小块进行引入,如果可以,那么就分小块进行,这样讲整体细化成一个个小问题。再从这里想到对数组划分后能不能进行排序,想到分治归并上。主要就是要明白再挑选一左一右统计次数的时候要分清什么情况下是可以一次统计完所有次数的,大体思路就跟归并没什么两样。

7. 计算右侧⼩于当前元素的个数(hard)

读完题发现这题简直跟上一题求逆序对的个数一模一样,唯一的难点就是要求,求出每一个小于数字的个数然后存入数组内。

解析:

1)暴力:

两层for()循环,肯定会超时的

2)优化:分治_归并

这一题就是运用上一题的策略二:当前元素的后面有多少个比我小的元素

这里需要讲nums数组的下标进行绑定到index数组里面

class Solution {
    vector<int> ret;
    vector<int> index; // 记录 nums 中当前元素的原始下标
    int tmpNums[500010];
    int tmpIndex[500010];

public:
    vector<int> countSmaller(vector<int>& nums) {
        int n = nums.size();
        ret.resize(n);
        index.resize(n);
        // 初始化⼀下 index 数组
        for (int i = 0; i < n; i++)
            index[i] = i;
        mergeSort(nums, 0, n - 1);
        return ret;
    }

    void mergeSort(vector<int>& nums, int left, int right) {
        if (left >= right)
            return;

        int mid = (left + right) >> 1;
        // 先搞搞左边,在搞搞右边
        mergeSort(nums, left, mid);
        mergeSort(nums, mid + 1, right);

        // 处理一左一右的情况
        int cur1 = left, cur2 = mid + 1, i = 0;
        while (cur1 <= mid && cur2 <= right) // 降序
        {
            if (nums[cur1] <= nums[cur2]) {
                tmpNums[i] = nums[cur2];
                tmpIndex[i++] = index[cur2++];
            } else {
                ret[index[cur1]] += right - cur2 + 1; // 重点+=
                tmpNums[i] = nums[cur1];
                tmpIndex[i++] = index[cur1++];
            }
        }

        // 处理没有遍历完的数组
        while (cur1 <= mid) {
            tmpNums[i] = nums[cur1];
            tmpIndex[i++] = index[cur1++];
        }
        while (cur2 <= right) {
            tmpNums[i] = nums[cur2];
            tmpIndex[i++] = index[cur2++];
        }

        // 还原数组
        for (int j = left; j <= right; j++) {
            nums[j] = tmpNums[j - left];
            index[j] = tmpIndex[j - left];
        }
    }
};

总结:

这题跟上一题大差不差,唯一不同的就是要多创建一个数组index来绑定nums数组的下标。

8. 翻转对(hard)

这一题跟逆序对超级一样,题目意思就是说前面的数要大于后面数的两倍

解析:

归并排序:

在归并排序的过程中,假设对于数组 nums[l..r] 而言,我们已经分别求出了子数组 nums[l..m] 与 nums[m+1..r] 的翻转对数目,并已将两个子数组分别排好序,则 nums[l..r] 中的翻转对数目,就等于两个子数组的翻转对数目之和,加上左右端点分别位于两个子数组的翻转对数目。

我们可以为两个数组分别维护指针 i,j。对于任意给定的 i 而言,我们不断地向右移动 j,直到 nums[i]≤2⋅nums[j]。此时,意味着以 i 为左端点的翻转对数量为 j−m−1。随后,我们再将 i 向右移动一个单位,并用相同的方式计算以 i 为左端点的翻转对数量。不断重复这样的过程,就能够求出所有左右端点分别位于两个子数组的翻转对数目。

 

class Solution {
public:
    int reversePairsRecursive(vector<int>& nums, int left, int right) {
        if (left == right) {
            return 0;
        } else {
            int mid = (left + right) / 2;
            int n1 = reversePairsRecursive(nums, left, mid);
            int n2 = reversePairsRecursive(nums, mid + 1, right);
            int ret = n1 + n2;

            // 首先统计下标对的数量
            int i = left;
            int j = mid + 1;
            while (i <= mid) {
                while (j <= right && (long long)nums[i] > 2 * (long long)nums[j]) j++;
                ret += (j - mid - 1);
                i++;
            }

            // 随后合并两个排序数组
            vector<int> sorted(right - left + 1);
            int p1 = left, p2 = mid + 1;
            int p = 0;
            while (p1 <= mid || p2 <= right) {
                if (p1 > mid) {
                    sorted[p++] = nums[p2++];
                } else if (p2 > right) {
                    sorted[p++] = nums[p1++];
                } else {
                    if (nums[p1] < nums[p2]) {
                        sorted[p++] = nums[p1++];
                    } else {
                        sorted[p++] = nums[p2++];
                    }
                }
            }
            for (int i = 0; i < sorted.size(); i++) {
                nums[left + i] = sorted[i];
            }
            return ret;
        }
    }

    int reversePairs(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        return reversePairsRecursive(nums, 0, nums.size() - 1);
    }
};

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

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

相关文章

【BurpSuite】Cross-site scripting (XSS 学徒部分:1-9)

&#x1f3d8;️个人主页&#xff1a; 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞&#x1f44d;收藏&#x1f497;支持一下哦 【BurpSuite】Cross-site scripting (XSS 学徒部分:1-9&#xff09; 实验一 Lab: Reflected XSS into HTML context with nothing…

maven手动导入本地仓库

maven手动导入本地仓库 1.在maven仓库下载对应的依赖 一定要把jar包下载到maven仓库的bin下 2.找到自己仓库的maven仓库下的bin目录cmd进去 在cmd窗口中输入以下命令&#xff1a;&#xff08;这里根据你的groupId、artifactId、version修改即可&#xff09; <!-- https:…

乱弹篇(53)丹桂未飘香

今天是2024年“秋分”节气&#xff0c;也是第7个中国“农民丰收节”&#xff0c;本“人民体验官”推广人民日报官方微博文化产品《文化中国行看丰收之美》。 截图&#xff1a;来源“人民体验官”推广平台 人民微博说&#xff1a;“春华秋实&#xff0c;岁物丰成。”又说&#…

dhtmlxGantt 甘特图 一行展示多条任务类型

效果如图: 后台拿到数据 处理之后如图: 含义: 如上图所示, 如果一行需要展示多个 需要给父数据的那条添加render:split属性, 子数据的parent为父数据的Id即可 切记 父数据的id 别为0 为0 时 会出现错乱 因为有些小伙伴提出分段展示的数据结构还是有点问题,下面展示一个完整…

机器人时代的“触觉革命”:一块小传感器如何颠覆你的认知?

你是否曾经想过,机器人也能像人类一样有“触觉”?不再是简单的机械操作,而是具备真正的感知能力,能够学会精细的任务。今天我想和你聊聊一种让机器人“长出触觉”的技术:一种小巧的触觉传感器,它的名字叫“AnySkin”。别看它小,它的潜力可一点都不小,或许能彻底改变我们…

Windows下如何定时执行自定义任务

目录 一.前言二.设置定时自动执行自定义任务 一.前言 本文环境是Windows11系统。 有时候我们希望能够在Windows下定时自动执行自定义任务&#xff0c;比如检测数据库服务的状态。那在Windows下怎么定时自动执行自定义任务&#xff0c;这篇文章介绍一种方法。 二.设置定时自动…

NLP 主流应用方向

主流应用 文本分类文本匹配序列标注生成式任务 应用细分 文本纠错话者分离 本质为文本分类任务数字归一化 实现数字映射&#xff0c;提高内容可读性 如将一九九九转1999

AI基础 L26 Introduction to Automated Planning - II

ADL Action Description Language (ADL) is a richer language than STRIPS. It allows for • Positive and negative literals in states • The open world assumption • Quantified variables in goals as well as conjunctions and disjunctions • Conditional effects …

Web_php_include 攻防世界

<?php show_source(__FILE__); echo $_GET[hello]; $page$_GET[page]; while (strstr($page, "php://")) { 以是否检测到php://为判断执行循环$pagestr_replace("php://", "", $page);//传入空值&#xff0c;替换 } include($page); ?&g…

226. 翻转二叉树之多种解法(递归法、深度优先(迭代法)、广度优先【层序遍历】)

文章目录 226. 翻转二叉树题外话思路递归法迭代法:深度优先遍历层序遍历&#xff1a;广度优先遍历拓展总结 226. 翻转二叉树 226. 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;r…

【JAVA开源】基于Vue和SpringBoot的在线文档管理系统

本文项目编号 T 038 &#xff0c;文末自助获取源码 \color{red}{T038&#xff0c;文末自助获取源码} T038&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

单片机原理及应用详解

目录 1. 什么是单片机&#xff1f; 2. 单片机的基本组成 3. 单片机的工作原理 4. 常见的单片机分类 5. 单片机的应用领域 6. 单片机开发流程 7. 单片机开发中的常见问题及解决方案 8. 单片机的未来发展趋势 9. 总结 1. 什么是单片机&#xff1f; 单片机&#xff08;Mi…

美食共享圈:Spring Boot校园周边美食平台

第二章 系统分析 2.1 可行性分析 可行性分析的目的是确定一个系统是否有必要开发、确定系统是否能以最小的代价实现。其工作主要有三个方面&#xff0c;分别是技术、经济和社会三方面的可行性。我会从这三个方面对网上校园周边美食探索及分享平台进行详细的分析。 2.1.1技术可行…

springboot实战学习笔记(5)(用户登录接口的主逻辑)

接着上篇博客学习。上篇博客是已经基本完成用户模块的注册接口的开发以及注册时的参数合法性校验。具体往回看了解的链接如下。 springboot实训学习笔记&#xff08;4&#xff09;(Spring Validation参数校验框架、全局异常处理器)-CSDN博客文章浏览阅读576次&#xff0c;点赞7…

[云服务器13] 如何正确选择云服务器?

【非广告&#xff0c;仅提供建议&#xff0c;没有强制消费引导】 这期我们不讲搭建教程了&#xff0c;因为我想到前面12篇的教程&#xff0c;有关套餐配置的教程好像都有点敷衍…… 所以这期我们主要来说一说服务器的配置选择和不同配置的应用场景。 网站: 雨云 打开后&…

Cisco 基础网络汇总

⭕个人主页 可惜已不在 ⭕可以分享给身边有需要的人 ⭕有用的话就留下一个三连吧 目录 前言: 一.网络及网络设备认识 二. 二层网络 三. 生成树、端口 四. 三层网络 五.访问控制 六.NAT 七.DHCP 八.PPP 九.帧中继 十.热备份 十一.综合实验 十二.WLAN 十三.Cisco P…

Compiler Explorer 开源项目-在线编译器网站

Compiler Explorer 开源项目&#xff0c;一个交互式编译器探索网站。在 C、C、C♯、F♯、Rust、Go、D、Haskell、Swift、Pascal、ispc、Python、Java 或其他 30 多种支持的语言组件中编辑代码&#xff0c;并实时查看不同编译器&#xff08;包括不同cpu架构&#xff09;编译后的…

STM32—MPU6050

1.MPU6050简介 MPU6050是一个6轴姿态传感器可以测量芯片自身X、Y、Z轴的加速度、角速度参数&#xff0c;通过数据融合&#xff0c;可进一步得到姿态角&#xff0c;常应用于平衡车、飞行器等需要检测自身姿态的场景3轴加速度计(Accelerometer&#xff1a;测量X、Y、Z轴的加速度3…

构建未来企业的理论基石:业务能力建模指南的深度解析与战略实施框架

数字化转型已经成为全球企业的战略焦点&#xff0c;在这个过程中&#xff0c;如何有效地将复杂的业务需求、技术架构和市场变化结合&#xff0c;形成具备长期竞争力的企业能力框架&#xff0c;是企业成败的关键。《业务能力指南》提供了一套经过验证的理论体系&#xff0c;帮助…

数字图像面积计算一般方法及MATLAB实现

一、引言 在数字图像处理中&#xff0c;经常需要获取感兴趣区域的面积属性&#xff0c;下面给出图像处理的一般步骤。 1.读入的彩色图像 2.将彩色图像转化为灰度图像 3.灰度图像转化为二值图像 4.区域标记 5.对每个区域的面积进行计算和显示 二、程序代码 %面积计算 cle…