算法——分治

思想:分而治之,将大问题转化为若干个相同或相似的子问题。快排的题目常见的方法是利用三指针法将数组分三块搭配随机选择基准元素的思想
image.png

颜色分类(分治_快排

颜色分类

题目解析

  1. 原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
  2. 我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
  3. 必须在不使用库内置的 sort 函数的情况下解决这个问题。

算法原理

  • 解法:三指针(数组分三块)
    • 将数组划分为三个区域,一部分区域全是0,一部分全是1,一部分全是2.定义i指针,用来扫描整个数组;left指针标记0区域的最右侧,right标记2区域的最左侧。image.png
    • 区间划分好,接下来我们就分类讨论每个区间应该怎么处理后,就可以写代码了。
    • 当i位置是0的情况:
      • 要把该元素加入左边的区间里,即加到left+1的位置。left+1这个位置是1,让i和left+1交换位置,然后让i++外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
      • 还有一种情况,当i的值等于left+1,即i此时所指的位置也是0,但是i是在left的后面,此时我们依旧要执行交换操作,执行交换操作的依然是left+1的位置和i的位置,但是相当于是自己和自己交换。交换完之后依旧要让left++,i++image.png
    • 当i位置是1的情况:要保证让1全部在left+1和i-1的区间内,所以让i++即可。
    • 当i位置是2的情况:此时我们要把他加入到right-1的位置,因为我们要把它加入到right最右边的区域的话,相当于是把他加入到right-1的区域。所以要i和right-1位置交换。并且要让right–。在交换完之前[i,right-1]这个区间全是待扫描的元素。当交换完之后,此时i所指的位置依旧是带扫描的元素,所以i不能++image.png
  • 当i和right相遇之后,此时没有待扫描的元素,此时停止循环。

下面模拟一下流程

  1. i所指元素是2,执行第三种情况,让i所指的元素和right-1位置的元素0交换,然后i不动,right–。

image.png

  1. 此时i指的元素是0,和left+1的位置(其实还是i所指的)元素0交换(那自己和自己交换就不动啦嘻嘻)。交换完之后让i++。left也++。交换完之后咱就发现目前而言左边区域就全是0.

image.png

3.然后i所指的元素是0,将left+1位置元素和他交换(还是自己和自己交换),交换完之后i++、left++
image.pngimage.png

  1. 接下来,i所指的元素是2,和right+1位置交换,交换完right–,i不动image.png
  2. 当i是1,很简单直接++

image.png

当i与right相遇停止循环。

代码实现

class Solution {
public:void sortColors(vector<int>& nums) {int n = nums.size();int left = -1, right = n, i = 0;while(i < right){if(nums[i] == 0) swap(nums[++left], nums[i++]);else if(nums[i] == 1) i++;else swap(nums[--right], nums[i]);}}
};

排序数组(分治_快排

排序数组

题目解析

用数组划分的思想实现快排从而解决这个问题

算法原理

  • 解法:快速排序:
    1. 普通版本:选择一个基准元素k,将原数组分成两部分,一部分小于等于k,另一部分全部大于k(这一步数据划分是关键,称为partation),此时选择的基准所在的位置就是排序之后所在的位置,此时只需要排序基准元素左右两边的数字即可;然后再选择一个基准元素,如此循环。但有一种极端情况,是数组元素全部重复的时候,时间复杂度就会退化为O(n2)image.png
    2. 数组分三块思想:时间复杂度O(n)
      1. 分三类情况讨论
        1. 当nums[i] < k,把当前位置元素加到左边的区域,执行交换操作,与left+1位置交换,然后left++,i也++
        2. 当nums[i] = k,i++
        3. 当nums[i] > k,交换nums,–rightimage.png
    3. 优化:用随机的方式选择基准元素,时间复杂度渐近到O(nlogn)
      1. 给定一个数组,一个左区间,一个右区间,要等概率的返回这个区间上的任意一个数。所以我们用随机数的方式选择基准元素。偏移量:r%(right-left+1)取值就是[0,n-1]。此时再让left加上偏移量就映射到这个区间随缘选一个点。image.png

代码实现

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 key = getRandom(nums, l, r);int i = l, left = l - 1, right = r + 1;while(i < right){if(nums[i] < key) swap(nums[++left], nums[i++]);else if(nums[i] == key) i++;else swap(nums[--right], nums[i]);}// [l, left] [left + 1, right - 1] [right, r]qsort(nums, l, left);qsort(nums, right, r);}int getRandom(vector<int>& nums, int left, int right){int r = rand();return nums[r % (right - left + 1) + left];}
};

数组中第k个最大元素(分治_快排)

数组中第k的最大元素

题目解析

本题是我们之前写过的TOP—K问题,共有四种问法:第K大、第K小、前K大、前K小。解决此问题有两种方法:一种是堆排序,时间复杂度O(nlogn);另一种就是这次的快速选择算法,时间复杂度O(n)。

  • 需要找的是数组排序后的第 k 个最大的元素

  • 设计并实现时间复杂度为 O(n) 的算法

算法原理

该算法是基于快排改良的
数组分三块+随机选择基准元素:

  1. 在l和r区间(区间两个端点),随机选择一个基准元素k,将区间分为三部分:<k =k >k。因为题目要求找出第k大元素,所以当我们可以确定处于上面三部分中的其中一部分时,另外两部分就不用考虑,这样就提高了效率。
  2. 我们设在<k的区间里有a个数,=k区间里有b个数,>k区间里有c个数,此时分三种情况讨论。因为题目中说了数组已经排过序,所以按照常理我们从>k区间里先去找,概率大一点。
    1. 落在 >key 区间的判断条件为:c>=k,因为题中要第k大的元素,这个区间里都是较大的数,当k小于等于c时,该数字一定在这个区间里。
    2. 落在 =key区间的判断条件:b+c>=k,这里我们约定如果在b情况,那么a情况绝对不成立。此时k>=c(范围为蓝色箭头所指),所以,那么>key区间里的数就会符合题意,直接返回key
    3. 当前两种情况都不成立时。说明k很大(范围为红色箭头所指),后两部分区间(里面存的都是较大的数)已经找了b+c个,所以还需要在<key区间里找第k-b-c大的数

image.png

代码实现

class Solution {
public:int findKthLargest(vector<int>& nums, int k){srand(time(NULL));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];// 1. 随机选择基准元素int key = getRandom(nums, l, r);// 2. 根据基准元素将数组分三块int left = l - 1, right = r + 1, i = l;while(i < right){if(nums[i] < key) swap(nums[++left], nums[i++]);else if(nums[i] == key) i++;else swap(nums[--right], nums[i]);}// 3. 分情况讨论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 getRandom(vector<int>& nums, int left, int right){return nums[rand() % (right - left + 1) + left];}
};

最小的K个数(分治_快排)

最小的k个数——库存管理III

题目解析

输入整数数组 arr ,找出其中最小的 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

算法原理

  1. 解法一:排序:直接调用容器排序数组。然后把最小的k个数字摘出来。时间复杂度O(nlogn)
  2. 解法二:堆:创建一个大小为k的大根堆,存储的上限设为k,把所有的数依次丢入到大根堆里,最后堆里剩下的k个数就是最小的k个数.时间复杂度O(nlogk)
  3. 解法三:快速选择.随机选择基准元素+数组分三块。时间复杂度O(n)
    1. 题中要求第k小,所以从最左边的区间先开始分析。落在最左边区间的条件为a>k,再[l,left]区间里找
    2. (第一种情况不成立后再判断第二种)。落在=key区间的条件为a+b>=k,因为此时我们默认第一种情况不成立,说明此时k>=a,我们就在图中红线的区间里找,无论落在哪里,<key区间里的数就是符合题意的,直接返回
    3. (此时前两种情况不成立)说明k很大,此时区间在蓝色箭头所指的范围里已经找a+b个小的数,还要去>key区间里找最小的k-a-b小的数

image.png
快速选择算法仅仅是把最小的k个数丢到了前面,并没有把前面几个数字排序
这个算法是在递归的过程中直接去对应符合条件的区间里找数字,而不是去区间里排序。所以快速选择算法比快排更快。并且在《算法导论》里有证明,当我们用随机选择基准元素的方法时,我们的三个区间都是等概率划分的,此时他的时间复杂度会逼近与O(N)。

代码实现

class Solution {
public:vector<int> inventoryManagement(vector<int>& stock, int cnt) {srand(time(NULL));qsort(stock, 0, stock.size() - 1, cnt);//这里是快速选择,不是排序,所以我们只需要返回前k个数就行,里面是无序的return {stock.begin(), stock.begin() + cnt};}void qsort(vector<int>& stock, int l, int r, int cnt){if(l >= r) return;// 1. 随机选择⼀个基准元素 + 数组分三块int key = getRandom(stock, l, r);int left = l - 1, right = r + 1, i = l;while(i < right){if(stock[i] < key) swap(stock[++left], stock[i++]);else if(stock[i] == key) i++;else swap(stock[--right], stock[i]);}// [l, left][left + 1, right - 1] [right, r]
// 2. 分情况讨论int a = left - l + 1, b = right - left - 1;if(a > cnt) qsort(stock, l, left, cnt);else if(a + b >= cnt) return;else qsort(stock, right, r, cnt - a - b);}int getRandom(vector<int>& stock, int l, int r){return stock[rand() % (r - l + 1) + l];}
};

排序数组(分治_归并)

排序数组

题目解析

整数数组 nums,请你将该数组升序排列。

归并算法回顾

用归并算法给数组排序,首先先选择mid中间点,先把左边部分排序,排左边的时候相当于又是一个归并排序的过程,直至只剩下一个元素的时候,向上返回,排右边区间,直至剩下一个元素时,开始向上返回,当这一层都排完时,合并两个有序数组。相当于二叉树中的后序遍历,快排的过程是先把数组分两块,然后把左边继续用一个key值分成左右两部分。相当于前序遍历

合并有序数组时需要创建辅助数组
image.png

代码实现

class Solution {vector<int>tmp; //节省时间消耗
public:vector<int> sortArray(vector<int>& nums) {tmp.resize(nums.size());  //在归并前更改大小srand(time(NULL)); // 种下⼀个随机数种⼦mergeSort(nums, 0, nums.size() - 1);return nums;}void mergeSort(vector<int>& nums, int left, int right){if(left >= right) return;// 1. 选择中间点划分区间int mid = (left + right) >> 1;// [left, mid] [mid + 1, right]// 2. 把左右区间排序mergeSort(nums, left, mid);mergeSort(nums, mid + 1, right);// 3. 合并两个有序数组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++];// 4. 还原for(int i = left; i <= right; i++)nums[i] = tmp[i - left];}
};

数组中的逆序对

数组中的逆序对

题目解析

逆序对:前面的数大于后面的数 image.png

算法原理

  1. 暴力枚举:把所有的二元组列举出来,判断是不是逆序对。先固定其中一个数,在这个数的后面的区间找找有几个比他小的数。两层for循环。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 左半部分->右半部分->一左一右:将数组从中间劈成两部分,求整个数组的逆序对的时候,先去求左边部分有a个逆序对,右边部分有b个逆序对。也就是说求a的时候不看b。接着分别在左区间挑一个,右区间挑一个;一左一右统计有c个逆序对,这样本质其实和遍历一样。最终a+b+b就是最终个数image.png
  2. **左半部分->左排序->右半部分->右排序->一左一右+排序:**这个与2相比,只是在一左一右的时候有些不同。在左边选完一个数后,只需要看右边区间有没有比这个数小就行。(+排序是为了和前半部分+排序保持一致,因为归并的子过程要相同)

image.png

  1. **利用归并排序解决:**先去搞左半部分有多少逆序对,如果数组很大,继续拆,…这个过程非常类似我们的归并过程。所以上面两种策略刚好对应递归排序。(我们这里只需要搞定一左一右+排序,因为左半部分+排序和右半部分+排序可以在递归中完成)。我们只需要算出一左一右有多少逆序对就行。此时数组升序。时间复杂度O(NlogN)

image.png


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

这时候在cur1之前的数都是比它小的,所以cur1之前的数就会比cur2之前的数字小,(因为cur1比cur2位置的数字小,cur1会先归并到辅助数组中)。我们找逆序对是在找到比我大的数之前,有多少数字能和我组成逆序对。所以我们分情况讨论:

  1. 当cur1[num] <= cur2[num]:说明此时还没有比cur2位置上大的数,就继续找,直到找到cur1位置大于cur2位置的数,所以让cur1++(本质上是先把cur1位置的数放到辅助数组里面,然后让cur1++)

  2. 当cur1[num] > cur2[num]:此时cur1后面的数全都比cur2大。我们就根据归并排序的以此比较,就找出了一堆比cur2大的数,此时我们用ret+=mid-cur1+1 记录cur1后面有多少个数字。并且让cur2++image.png

  3. 处理细节问题:如果数组降序,可以怎样处理呢

    1. 先选大的数归并到辅助数组里面,此时cur1和cur2左边的数都是比他们各自大 。
    2. 当cur1[num] > cur2[num]:此时统计一下cur1左边数字的个数,然后让cur1++,但此时会面临一个问题,如果cur1往后移动的数字依然比cur2大,此时再统计个数就重复统计了。因此策略1只能降序数组。

  • **策略2:找出该数之后有多少个比我小 ** 该策略只能用降序(因为升序也会重复统计)
    • 当升序时,此时我们固定nuns1,让较大的指针cur2放入辅助数组里外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
    • 数组降序,此时各自左边部分的数字都比cur1和cur2大(cur2左边部分的数比cur1大)。当cur1的位置数比cur2大时,说明是cur1第一次比cur2大,此时比cur2后面的区间全都大.统计个数image.png

代码实现

class Solution {int tmp[50010];
public:int reversePairs(vector<int>& nums){return mergeSort(nums, 0, nums.size() - 1);}int mergeSort(vector<int>& nums, int left, int right){if(left >= right) return 0;int ret = 0;// 1. 找中间点,将数组分成两部分int mid = (left + right) >> 1;// [left, mid][mid + 1, right]// 2. 左边的个数 + 排序 + 右边的个数 + 排序ret += mergeSort(nums, left, mid);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++];}}// 4. 处理⼀下排序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;}
};
class Solution
{int tmp[50010];
public:int reversePairs(vector<int>& nums){return mergeSort(nums, 0, nums.size() - 1);}int mergeSort(vector<int>& nums, int left, int right){if(left >= right) return 0;int ret = 0;// 1. 找中间点,将数组分成两部分int mid = (left + right) >> 1;// [left, mid][mid + 1, right]// 2. 左边的个数 + 排序 + 右边的个数 + 排序ret += mergeSort(nums, left, mid);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[cur2++];}else{ret += right - cur2 + 1;tmp[i++] = nums[cur1++];}}// 4. 处理⼀下排序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;}
};

计算右侧小于当前元素的个数

计算右侧小于当前元素的个数

题目解析

  • 返回的新数组要与原数组同等规模。
  • 返回该位置之后比他小的数字的个数

image.png

算法原理

归并排序(分治):因为要找比该位置小的数,所以我们可以用上到题的策略二——当前元素后面有多少个比我小的数。数组降序

  • 将数组劈成两部分,先将左边的结果找到,再将右边的结果找到。快速找到某一个位置之后比他小的数,就盯着cur1.此时开始讨论:
    • 当nums[cur1] <= nums[cur2]:此时没找到比cur1小的,那么让cur2++,继续向后移动
    • 当nums[cur1] > nums[cur2]:此时cur1比cur2右边部分的数字都大,此时要记录个数不能用ret记录,而是cur1对应的位置里面的ret(因为返回是通过数组形式)image.png
  • 那么问题来了,如何找nums元素对应的原始下标是多少呢?因为我们将原数组分治完之后排序了,所以此时下标已经乱了,当前位置的cur1并不是真实下标。
    • 我们可以搞一个index数组,专门记录nums数组当前位置元素的原始下标。然后无论nums数组中的元素怎么变,我们让他绑定移动
    • 我们一共要搞两个辅助数组tmp,一个是合并nums两个有序数组,另一个绑定

image.png

代码实现

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;
// 1. 根据中间元素,划分区间int mid = (left + right) >> 1;// [left, mid] [mid + 1, right]
// 2. 先处理左右两部分mergeSort(nums, left, mid);mergeSort(nums, mid + 1, right);// 3. 处理⼀左⼀右的情况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++];}}// 4. 处理剩下的排序过程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];}
}
};

翻转对

翻转对

题目解析

找两个数,使前面的数大于后面的数2倍
image.png

算法原理

分治: 将整个数组分治为两部分,求出左半部分翻转对数a,右半部分翻转对数为b,一左一右翻转对数为c,最后a+b+c即为所求。但有些细节问题

  1. 该题比较条件是前面的数大于后面的数二倍,此时就不能按照归并排序的流程进行。所以我们要在归并排序之前进行翻转对。利用两个数组有序的性质。我们可以在一次归并中用O(N)的时间复杂度搞定该层的翻转对的个数(利用单调性,使用同向双指针)image.png
    1. 策略一:计算当前元素后面有多少个比两倍还小的数,降序排列
      1. cur1不动,如果cur2当前所指的元素比cur1两倍还大,往后移。直到找到第一个比cur1两倍还小的(因为数组降序),记ret+=right-cur2+1
      2. 之后移动cur1时,不要让cur2回滚到之前的位置否则时间复杂度为O(n^2logn)。让cur2在第一个找到的比cur1小的位置继续往后移动即可。直到cur1移动到最后结束image.png
    2. 策略二:计算当前元素之前有多少个元素的一半比我大,升序排列
      1. cur2不动,如过当前cur2的位置比cur1位置的一半还要小,cur1右移。直到出现比cur1位置一半大的,记ret+=mid-cur1+1.然后cur2++,cur1同理只需要在当前位置向后移动即可,不需要会退到第一个位置。直到cur2移动到最后结束。image.png
  2. 合并两个有序数组

代码实现

class Solution 
{int tmp[50010];
public:int reversePairs(vector<int>& nums){return mergeSort(nums, 0, nums.size() - 1);}int mergeSort(vector<int>& nums, int left, int right){if(left >= right) return 0;int ret = 0;// 1. 先根据中间元素划分区间int mid = (left + right) >> 1;// [left, mid] [mid + 1, right]// 2. 先计算左右两侧的翻转对ret += mergeSort(nums, left, mid);ret += mergeSort(nums, mid + 1, right);// 3. 先计算翻转对的数量int cur1 = left, cur2 = mid + 1, i = left;while(cur1 <= mid) // 降序的情况{while(cur2 <= right && nums[cur2] >= nums[cur1] / 2.0) cur2++;if(cur2 > right)break;ret += right - cur2 + 1;cur1++;}// 4. 合并两个有序数组cur1 = left, cur2 = mid + 1;while(cur1 <= mid && cur2 <= right)tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur2++] : nums[cur1++];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];return ret;
}
};

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

bugku -- eval

<?phpinclude "flag.php";$a $_REQUEST[hello];eval( "var_dump($a);");show_source(__FILE__); ?> //这段代码包含了一个PHP脚本。首先&#xff0c;它包含了一个名为"flag.php"的文件。然后&#xff0c;它定义了一个变量$a&#xff0c…

15个电脑小技巧

01.磁盘清理 电脑C盘满了就会变的很卡,先不着急打开清理软件,用电脑自带的磁盘清理工具先清理一下,也能腾出不少空间。 打开【此电脑】,鼠标右击C盘,点击【属性】-【磁盘清理】即可。 02.虚拟键盘 玩游戏的时候喜欢用虚拟键盘,教你如何显示出来。按【Win+R】输入“osk…

链表基础知识(二、双向链表头插、尾插、头删、尾删、查找、删除、插入)

目录 一、双向链表的概念 二、 双向链表的优缺点分析​与对比 2.1双向链表特点&#xff1a; 2.2双链表的优劣&#xff1a; 2.3循环链表的优劣 2.4 顺序表和双向链表的优缺点分析​ 三、带头双向循环链表增删改查实现 3.1SList.c 3.2创建一个新节点、头节点 3.3头插 3.…

成为软件测试工程师需要学什么?

成为软件测试工程师需要学习测试环境的搭建、前端开发知识、数据库知识、测试理论基础、开发语言基础、自动化测试、进阶内容。 1、测试环境的搭建 本部分主要是学习从操作系统开始&#xff0c;有关的计算机基础知识、软件和硬件知识、计算机理论知识、网络知识、如何在一个操…

C/C++ 表达式求值(含多位数)

个人主页&#xff1a;仍有未知等待探索_C语言疑难,数据结构,算法-CSDN博客 专题分栏&#xff1a;算法_仍有未知等待探索的博客-CSDN博客 目录 一、前言 二、解析 分析 最后直接上代码&#xff01; 一、前言 表达式求值是一个比较基础的代码关于栈的使用。在写的时候充分锻炼…

WPF——命令commond的实现方法

命令commond的实现方法 属性通知的方式 鼠标监听绑定事件 行为&#xff1a;可以传递界面控件的参数 第一种&#xff1a; 第二种&#xff1a; 附加属性 propa&#xff1a;附加属性快捷方式

【谭浩强C语言:前八章编程题(多解)】

文章目录 第一章1. 求两个整数之和(p7) 第二章2. 求三个数中的较大值&#xff08;用函数&#xff09;(p14、p107)3.求123...n(求n的阶乘&#xff0c;用for循环与while循环)(P17)1.循环求n的阶乘2.递归求n的阶乘(n< 10) 4.有M个学生&#xff0c;输出成绩在80分以上的学生的学…

【C++】封装:练习案例-点和圆的关系

练习案例&#xff1a;点和圆的关系 设计一个圆形类&#xff08;Circle&#xff09;&#xff0c;和一个点类&#xff08;Point&#xff09;&#xff0c;计算点和圆的关系。 思路&#xff1a; 1&#xff09;创建点类point.h和point.cpp 2&#xff09;创建圆类circle.h和circle…

pytorch实现DCP暗通道先验去雾算法及其onnx导出

pytorch实现DCP暗通道先验去雾算法及其onnx导出 简介实现ONNX导出导出测试 简介 最近在做图像去雾&#xff0c;于是在Pytorch上复现了一下dcp算法。暗通道先验去雾算法是大神何恺明2009年发表在CVPR上的一篇论文&#xff0c;还获得了当年的CVPR最佳论文。 实现 具体原理就不…

【贪心算法】【中位贪心】LeetCode:100123.执行操作使频率分数最大

涉及知识点 双指针 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 贪心算法 题目 给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。 你可以对数组执行 至多 k 次操作&#xff1a; 从数组中选择一个下标 i &#xff0c;将 nums[i] …

网络编程day2作业

1.tcp实现通信 服务器&#xff1a; //tcp服务端#include <head.h>#define SERPORT 8888 #define IP "192.168.125.6"int main(int argc, const char *argv[]) { //1.创建套接字int sfdsocket(AF_INET,SOCK_STREAM,0);//2.绑定struct sockaddr_in ser;ser.sin…

喜报丨迪捷软件入选2023年浙江省信息技术应用创新典型案例

12月6日&#xff0c;浙江省经信厅公示了2023年浙江省信息技术应用创新典型案例入围名单。本次案例征集活动&#xff0c;由浙江省经信厅、省密码管理局、工业和信息化部网络安全产业发展中心联合组织开展&#xff0c;共遴选出24个优秀典型解决方案&#xff0c;迪捷软件“基于全数…

LeetCode刷题--- 找出所有子集的异或总和再求和

个人主页&#xff1a;元清加油_【C】,【C语言】,【数据结构与算法】-CSDN博客 个人专栏 力扣递归算法题 http://t.csdnimg.cn/yUl2I 【C】 http://t.csdnimg.cn/6AbpV 数据结构与算法 http://t.csdnimg.cn/hKh2l 前言&#xff1a;这个专栏主要讲述递归递归、搜…

互联网加竞赛 python 机器视觉 车牌识别 - opencv 深度学习 机器学习

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于python 机器视觉 的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;3分 &#x1f9ff; 更多资…

猫头虎博主揭秘:令人叹为观止的编程语言与代码技巧 ‍

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

python如何发送企业微信群消息

一、创建机器人&#xff0c;并获取webhook 1.1 进入企业微信中&#xff0c;添加群机器人&#xff0c;添加完成后可以获取到一个webhook的地址 1.2 群机器人企业微信接口的调用可以参考这个文件 https://developer.work.weixin.qq.com/document/path/99110#%E5%A6%82%E4%BD%…

C语言:求和1+1/2-1/3+1/4-1/5+……-1/99+1/100

#include<stdio.h> int main() {int i 0;double sum 0.0;int flag 1;for (i 1;i < 100;i){sum 1.0 / i * flag;flag -flag;}printf("sum%lf\n", sum);return 0; }

Centos7 配置Git

随笔记录 目录 1&#xff0c; 新建用户 2. 给用户设置密码相关操作 3. 为新用户添加sudo 权限 4. 配置Git 4.1 配置Git 4.2 查看id_ras.pub 5, 登录Git 配置SSH 秘钥 6. Centos7 登录Git 7. clone 指定branch到本地 8. 将新代码复制到指定路径 9. 上传指定代码 …

堆与二叉树(上)

本篇主要讲的是一些概念&#xff0c;推论和堆的实现&#xff08;核心在堆的实现这一块&#xff09; 涉及到的一些结论&#xff0c;证明放到最后&#xff0c;可以选择跳过&#xff0c;知识点过多&#xff0c;当复习一用差不多&#xff0c;如果是刚学这一块的&#xff0c;建议打…

微信小程序---自定义组件

目录 1.局部引用组件 2.全局引用组件 3.组件和页面的区别 4.自定义组件样式 5.properties属性 6.data和properties的区别 7.数据监听器 8.纯数据字段 9.自定义组件-组件的生命周期 lifetimes节点 10.组件所在的页面的生命周期 pageLifetimes节点 11.插槽 &#x…