【ONE·基础算法 || 分治·快排并归】

在这里插入图片描述

总言

  主要内容:编程题举例,理解分治的思想(主要是对快排、并归的应用)。
  
  

文章目录

  • 总言
  • 1、基本介绍
  • 2、颜色分类(medium)
    • 2.1、题解
  • 3、快速排序(medium)
    • 3.1、题解:三指针版本的快排
  • 4、快速选择算法(medium)
    • 4.1、题解
  • 5、最小的 k 个数(medium)
    • 5.1、题解
  • 6、归并排序(medium)
    • 6.1、题解:复习快排(二路归并)
  • 7、数组中的逆序对(hard)
    • 7.1、题解
  • 8、计算右侧小于当前元素的个数(hard)
    • 8.1、题解
  • 9、翻转对(hard)
    • 9.1、题解
  • Fin、共勉。

  
  
  
  
  

1、基本介绍

  分治是一种解决问题的策略,它将一个大问题分解成若干个小问题,这些小问题与原问题类型相同但规模更小,然后递归地解决这些小问题,最后将小问题的解合并,从而得到原问题的解。这种策略在许多算法中都有应用,如排序、搜索、图论问题等。

  快速排序就是基于分治策略的一种排序算法。它的基本思想是选取一个基准值,通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。快速排序的时间复杂度为O(nlogn),是目前基于比较的内部排序里被认为是最好的方法,特别适用于大数据集。

  归并排序则是另一种基于分治策略的排序算法。它的主要思路是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的,然后再把有序子序列合并为整体有序序列。归并排序的过程可以分为分解和合并两个步骤,分解是将序列每次折半划分,合并则是将划分后的序列段两两合并后排序。这种排序算法是稳定的,适用于各种规模的数据集。
  
  
  
  

2、颜色分类(medium)

  题源:链接

在这里插入图片描述

  

2.1、题解

  1)、思路分析
  此题的思路本质可划分为双指针(双指针复习链接:移动零。),但对此进行了一点变动,使用的是三指针:一个用于遍历数组的指针+两个用于划分区域的指针

在这里插入图片描述
  PS:上述指针如何取名完全可随意,不必生搬硬套。
  

  如何判断移动?
  1、初始时: i = 0left = -1right = numsSize(若数组尾元素下标为n-1right指向尾元素下一个位置,即n
  2、i从左到右遍历过程中:
  ①、若nums[cur] == 0 ;说明 i 位置指向的元素要纳入左区域范围内。因此,交换 left + 1 与 i 位置的元素,并让 left++ (因为纳入了新元素, 0 序列的右边界应当右滑扩展),cur++ (为什么可以 ++ ?因为 left + 1 位置要么是 0 ,要么是 1,交换完毕之后,这个位置的值已经符合我们的要求,因此 cur++ );
  ②、nums[cur] == 1 ;说明这个位置应该在 left 和 cur 之间,此时⽆需交换,直接让 cur++ ,判断下⼀个元素即可;
  ③、nums[cur] == 2 ;说明这个位置的元素应该在 right - 1 的位置,因此交换 right - 1 与 cur 位置的元素,并且让 right-- (指向 2 序列的左边界),cur 不变(因为交换过来的数是没有被判断过的,因此需要在下轮循环中判断)
  
  
  2)、题解

class Solution {
public:void sortColors(vector<int>& nums) {int left = -1, right = nums.size(), i = 0;while(i < right)//right表⽰的是2序列的左边界,因此当碰到right时,说明已经将所有数据扫描完毕了{if(nums[i] == 0)swap(nums[i++],nums[++left]);else if(nums[i] == 1)i++;else //nums[i] == 2swap(nums[i],nums[--right]);//cur 不变,因为交换过来的数是没有被判断过的}}
};

  
  
  
  
  
  

3、快速排序(medium)

  题源:链接

在这里插入图片描述
  
  

3.1、题解:三指针版本的快排

  1)、思路分析
  这题的题解方法有多种,这里我们主要学习快排,后续讲以同样的题讲解归并。
  
  快排,我们在排序章节讲解过几种写法:Hoare法、挖坑法、双指针法,并且当时对key值的优化使用的是三数取中。这里我们讲解三指针法,以及随机数法选取key值。
  
  三指针法: 这里三指针的原理同上述颜色分类。
  从待排序的数组中选择一个元素作为基准值(key),以该基准值进行排序,将数组划分为左、中 、右三部分(以升序为例)。
在这里插入图片描述
  三指针排序的过程在上述颜色分类讲解过,这里不做赘述。
  
  在对当前序列进行三块划分处理后,再去递归排序左边部分和右边部分即可(可以舍去大量的中间部分,减少不必要的交换操作。 在处理有大量重复元素的数组时,效率会大大提升)。
在这里插入图片描述
  
  
  随机数法取key值: 在主函数中种一颗随机数种子, 由于我们要随机产生一个满足[left,right]区间范围内的基准元素值,因此可以将生成随机数转换成为生成当前[left,right]区间的随机下标。如何做到?

(rand() % (right -left +1 )) + left

  解释:这里我们设区间大小为n,让随机数 % 上区间大小,可得 [0,n-1]范围内的随机数,加上区间的左边界,即可得到 [left, left + (n -1)] 范围内的值,即[left, right]区间范围内的值。
  
  
  
  2)、题解

class Solution {
public:void quick(vector<int>& nums, int left, int right){if(left >= right) return; //递归结束条件//随机数法选取key值int n = right - left + 1;//当前段区间内元素总数int index = (rand() % n) + left;//获取到[left, right]区间段内的随机下标int key = nums[index];//这里不能直接用key的下标进行排序(即与nums[index]比较是错误的)。//因为快排属于交换排序,index下标位置的值会在排序过程中被交换。//三指针法进行区间排序:[left,right]int i = left, l = left - 1, r = right + 1;while(i < r){if(nums[i] < key) swap(nums[++l],nums[i++]);else if(nums[i] == key) i++;else swap(nums[--r],nums[i]);//交换过来的数是没有被判断过,此处i不能++}//对左右排序:[left, l] [l+1, r-1] [r,right]quick(nums,left,l);quick(nums,r,right);}vector<int> sortArray(vector<int>& nums) {srand(time(nullptr));// 种下⼀个随机数种⼦quick(nums,0,nums.size()-1);//使用递归法排序,这里传入[left,right]区间return nums;}
};

  
  
  
  
  
  

4、快速选择算法(medium)

  题源:链接

在这里插入图片描述

  

4.1、题解

  1)、思路分析
  这题若使用的是选择排序,比如直接选择排序或堆排序(堆排时间复杂度为 N l o g N NlogN NlogN),也可以解决此题:

class Solution {
public:int findKthLargest(vector<int>& nums, int k) {//建堆priority_queue<int> maxHeap(nums.begin(),nums.end());//取前K-1个数while(--k)//此写法下要用前置自减{maxHeap.pop();}//取第K个数return maxHeap.top();}
};

  
  
  这里我们主要学习应用快排:

在这里插入图片描述

  
  

  2)、题解
  使用升序的写法:

class Solution {
public:int qsort(vector<int>& nums, int k, int left, int right) {if (left >= right) // 递归调用return nums[left];int n = right - left + 1;   // 当前区间的元素总数int id = rand() % n + left; // 获取当前区间段的随机下标int key = nums[id]; // 获取该下标上的元素值(作为key值使用)int i = left, l = left - 1, r = right + 1;while (i < r) // 排升序,找第k大。{if (nums[i] < key)swap(nums[i++], nums[++l]);else if (nums[i] == key)i++;elseswap(nums[i], nums[--r]);}// 用于判断下一轮递归区间:[left,l]  [l+1,r-1]  [r, right]int a = l - left + 1;int b = r - 1 - (l + 1) + 1;int c = right - r + 1;if (c >= k)return qsort(nums, k, r, right);else if (b + c >= k)return key;elsereturn qsort(nums, k - b - c, left, l);}int findKthLargest(vector<int>& nums, int k) {srand(time(nullptr)); // 种下随机种子return qsort(nums, k, 0, nums.size() - 1); // 传入的区间边界应该是闭区间[left,right]}
};

  使用降序的写法:只是对当前序列的排序部分及判断下一轮递归的条件做了变动。

        while (i < r) // 排降序,找第k大。{if (nums[i] < key)swap(nums[i], nums[--r]);else if (nums[i] == key)i++;elseswap(nums[i++], nums[++l]);}// 用于判断下一轮递归区间:[left,l]  [l+1,r-1]  [r, right]int a = l - left + 1;int b = r - 1 - (l + 1) + 1;int c = right - r + 1;if (a >= k)return qsort(nums, k, left, l);else if (a + b >= k)return key;elsereturn qsort(nums, k - b - a, r, right);

  
  
  
  
  

5、最小的 k 个数(medium)

  题源:链接

在这里插入图片描述
  
  

5.1、题解

  1)、思路分析
  此题解法多种,可用堆的TOP-K( N l o g K NlogK NlogK)、可用排序(如快排: N l o g N NlogN NlogN)、还可以用快速选择算法(即上述题4讲解的原理。)
  这里主要演示快速选择算法。
在这里插入图片描述
  
  
  2)、题解
  以升序为例: 最后我们返回时,前K个元素区间虽然没有完全有序,但已经满足了找出题目最小的K个数的要求。

class Solution {
public:void qsort(vector<int>& arr, int left, int right, int k){if(left >= right) return;int n = right - left + 1;int index = rand() % n + left;int key = arr[index];//三指针排序: [left,right],排升序int L = left - 1 , R = right + 1, i = left;while(i < R){if(arr[i] < key) swap(arr[++L], arr[i++]);else if(arr[i] == key) ++i;else swap(arr[--R], arr[i]);}//对左右区间:[left, L] [L+1, R-1] [R,right]int a = L - left + 1;int b = R-1 - (L+1) + 1;int c = right - R + 1;if(a >= k)  qsort(arr, left, L, k);else if(a + b >= k) return;else qsort(arr, R, right, k-a-b);}vector<int> smallestK(vector<int>& arr, int k) {srand(time(nullptr));qsort(arr,0,arr.size()-1,k);return {arr.begin(),arr.begin()+k};}
};

  
  
  
  
  
  
  
  

6、归并排序(medium)

  题源:链接

在这里插入图片描述

  

6.1、题解:复习快排(二路归并)

  1)、思路分析
  在上述,我们用快排解过此题,这里我们使用归并排序来解决。PS:归并排序相关复习见博文:常见排序。
  这里主要是指二路归并。 总体思想不变,细节实现看个人写法:
  1、分割: 将待排序的数组从中间分割成两个子数组,直到子数组的大小为1(即每个子数组只包含一个元素,自然是有序的)。
  2、递归排序: 递归地对子数组进行归并排序(「左半部分排序」 + 「右半部分排序」)。
  3、合并: 将两个已排序的子数组合并成一个有序的大数组。(通常借助一个辅助数组,可以是每次归并时创建临时变量,也可以用全局变量或者在堆区开辟)
  
  
  2)、题解

class Solution {
public:vector<int> temp;void MergeSort(vector<int>& nums, int left, int right){if(left >= right) return;//这里使用二路归并,选择中间点将区间划分为两段:[left,mid][mid+1,right]int mid = ( right + left ) / 2;//题中给出数据不大(也可以使用防越界版本的求中间值)//先对左右区间排序MergeSort(nums,left,mid);MergeSort(nums,mid+1,right);//再合并两个有序数组(来到此处,意味着当前左右两段区间各自有序)int cur1 = left; int cur2 = mid+1;int i = 0;while(cur1 <= mid && cur2 <= right)temp[i++] =  nums[cur1] < nums[cur2] ? nums[cur1++] : nums[cur2++];//处理剩余区间while(cur1 <= mid) temp[i++] = nums[cur1++];while(cur2 <= right) temp[i++] = nums[cur2++];//将排序好的元素重新返回原数组中(可借助memcpy等函数)for(int j = left; j <= right; ++j){nums[j] = temp[j - left];}}vector<int> sortArray(vector<int>& nums) {temp.resize(nums.size());//归并需要借助一个辅助数组,这里可以每次归并时定义,也可以直接搞一个全局变量(或者堆上申请)MergeSort(nums,0,nums.size()-1);return nums;}
};

  

  题外话:
  理论上也可以实现k路归并排序(k-way merge sort),其中k是大于1的整数。在k路归并排序中,待排序的数组被分割成k个更小的子数组,而不是仅仅两个。然后,这k个子数组被分别排序,并最终合并成一个完整的有序数组。
  k路归并排序在某些特定场景下可能具有优势,比如当待排序的数据分布在多个不连续的内存区域时,或者当使用并行计算资源时。然而,实现k路归并排序通常比实现二路归并排序更为复杂,并且不一定总是带来性能上的提升。因此,在实际应用中,二路归并排序更为常见和流行。
  
  
  
  
  

7、数组中的逆序对(hard)

  题源:链接

在这里插入图片描述

  
  

7.1、题解

  1)、思路分析
  直接解法: 双层循环暴力枚举,看在难度hard的份上,大概率超时。
  
  问题一:为什么可以使用归并排序?
  1、题目要求找出数组中所有逆序对,既如此,将数组一分为二,先找出左区间中的逆序对,再找出右区间的逆序对,最后选出一左一右在两区间的逆序对。效果与从左到右/从右到左线性遍历查找等同。
在这里插入图片描述

  
  2、对此进行优化。在找出左区间中的逆序对后我们对其排个序,同理,在找出右区间的逆序对后也对其排序。此时,尽管左右两区间内部元素顺序发生改变,但对于在两区间中分别选取元素组成一左一右的逆序对并无影响。
  3、回顾上述历程,这不就和归并的思想一样吗?当然,在选取出一左一右的逆序对后,我们要对当前整体区间也进行排序

归并排序的过程:
• 先排序左数组;
• 再排序右数组;
• 左数组和右数组合⼆为⼀。逆序对中两个元素:
• 全部从左数组中选择逆序对
• 全部从右数组中选择逆序对
• ⼀个选左数组另⼀个选右数组,组成逆序对

  
  
  
  问题二:如何使用归并排序?及,为什么这里使用归并会提高效率(单调性)
  除了这里举例的两种(升序+固定右值找左侧;降序+固定左值找右侧),如何选取与组合看个人风格。
在这里插入图片描述
  
  
  
  
  2)、题解
  升序写法如下:

class Solution {
public:int tmp[50005]={0};int mergesort(vector<int>& record, int left, int right){if(left >= right) return 0;//取中数,分区间:[left, mid] [mid+1, right]int mid = (left+right) / 2;int sum = 0;//用于统计//左区间找逆序对+排序、右区间找逆序对+排序sum += mergesort(record,left,mid)+ mergesort(record,mid+1,right);//一左一右找逆序对+排序int cur1 = left, cur2 = mid + 1;int i = 0;while(cur1 <= mid && cur2 <= right)//排升序,找左数比右数大{if(record[cur1] <= record[cur2])tmp[i++] = record[cur1++];else//record[cur1] > record[cur2]{sum += mid - cur1 + 1;tmp[i++] = record[cur2++];}}//排序:处理剩余元素while(cur1 <= mid) tmp[i++] = record[cur1++];while(cur2 <= right) tmp[i++] = record[cur2++];//将有序数列返回原数列中for(int j = left; j <= right; ++j)record[j]=tmp[j-left];//返回return sum;}int reversePairs(vector<int>& record) {return mergesort(record,0,record.size()-1);}
};

  降序写法总体不变,只需稍加改动即可:

        while(cur1 <= mid && cur2 <= right)//排降序,找左数比右数大{if(record[cur1] <= record[cur2])tmp[i++] = record[cur2++];else//record[cur1] > record[cur2]{sum += right - cur2 + 1;tmp[i++] = record[cur1++];}}

  
  
  
  
  
  

8、计算右侧小于当前元素的个数(hard)

  题源:链接

在这里插入图片描述
  
  

8.1、题解

  1)、思路分析
  有了上一题的铺垫,这一道题的解法与之类似,但是这一道题要求的不是求总的个数,而是要返回一个数组,记录每一个元素的右边有多少个元素比自己小
在这里插入图片描述

  这里存在一个问题,在归并排序的过程中,元素的下标是会跟着变化的。 当前我们查找出的顺序与需要返回的顺序不一定完全匹配。
在这里插入图片描述
  因此,为了确保返回时数组输出的元素顺序,我们需要一个额外数组 index,将数组元素和对应的下标绑定在一起归并,也就是在归并nums中元素的时候,顺势将其下标index也转移到对应的位置上。(意味着辅助数组也需要两个,分别用于排序归并后的nums、index。)
  
  
  
  2)、题解
  这是vector<int> indexvector<int> count使用全局变量的版本。

class Solution {
public:int tmp_n[100005];//辅助数组1:归并时用于排序numsint tmp_i[100005];//辅助数组2:归并时用于排序indexvector<int> index;//记录元素对应下标vector<int> count;//用于返回输出结果void mergesort(vector<int>& nums, int left, int right){if(left>=right) return;//求中值划分区间:[left,mid] [mid+1,right]int mid = (left + right) /2;//先对左右区间进行找数+归并排序:mergesort(nums, left, mid);mergesort(nums,mid+1, right);//再对当前整段区间进行找数+排序:int cur1 = left, cur2 = mid+1;int i = 0;while(cur1<=mid && cur2 <= right){if(nums[cur1] <= nums[cur2]){tmp_n[i] = nums[cur2];tmp_i[i++] = index[cur2++];//注意这里一次处理两个数组}else//nums[cur1] > nums[cur2]{count[index[cur1]] += right - cur2 + 1;tmp_n[i] = nums[cur1];tmp_i[i++] = index[cur1++];}}//处理剩余区间while(cur1 <= mid){tmp_n[i]=nums[cur1];tmp_i[i++]=index[cur1++];}while(cur2 <= right){tmp_n[i]=nums[cur2];tmp_i[i++]=index[cur2++];}//将获取到的有序数据写回原数组中for(int j = left; j <= right; ++j){nums[j]=tmp_n[j-left];index[j]=tmp_i[j-left];}}vector<int> countSmaller(vector<int>& nums) {int n = nums.size();index.resize(n);//重新扩容count.resize(n);for(int i = 0; i < n; ++i)//初始化下标{index[i] = i;}mergesort(nums, 0, n-1);return count;}
};

  
  如果不使用全局变量,也可如下,但需要传参时多增几个参数。总之写法不一。

class Solution {
public:int tmp_n[100005];int tmp_i[100005];void mergesort(vector<int>& nums, int left, int right, vector<int>& index, vector<int>& count){if(left >= right) return;//[left,mid] [mid+1,right]int mid = (left + right) /2;//左右区间:mergesort(nums, left, mid, index,count);mergesort(nums,mid+1, right, index,count);//当前整个区间:int cur1 = left, cur2 = mid+1;int i = 0;while(cur1<=mid && cur2 <= right){if(nums[cur1] <= nums[cur2]){tmp_n[i] = nums[cur2];tmp_i[i++] = index[cur2++];}else//nums[cur1] > nums[cur2]{count[index[cur1]] += right - cur2 + 1;tmp_n[i] = nums[cur1];tmp_i[i++] = index[cur1++];}}//处理剩余区间while(cur1 <= mid){tmp_n[i]=nums[cur1];tmp_i[i++]=index[cur1++];}while(cur2 <= right){tmp_n[i]=nums[cur2];tmp_i[i++]=index[cur2++];}//写回原数组中for(int j = left; j <= right; ++j){nums[j]=tmp_n[j-left];index[j]=tmp_i[j-left];}}vector<int> countSmaller(vector<int>& nums) {int n = nums.size();vector<int> index(n);vector<int> count(n);for(int i = 0; i < n; ++i){index[i] = i;}mergesort(nums, 0, n-1, index, count);return count;}
};

  
  关于count[index[cur1]] += right - cur2 + 1; 为什么要用+=,而不能使用+
  要知道归并的过程,元素位置是变化的。 使用 += 是因为我们需要累计 nums[cur1] 右侧小于它的元素数量。在归并排序的合并过程中,cur1 会遍历左子数组的所有元素,每次遇到一个比右子数组当前元素大的左子数组元素时,我们都需要将右子数组中剩余的元素数量(即 right - cur2 + 1)累加到对应的 count 中。因此,这是一个累加操作,每次都需要将新的数量加到之前累计的数量上。

  如果使用 + 而不是 +=,那么每次只会将 right - cur2 + 1 赋值给 count[index[cur1]],而不会保留之前累计的数量。这会导致 count 数组中每个位置只存储了最后一次计算得到的数量,而不是所有累计的数量,从而得到错误的结果。

在这里插入图片描述

  
  
  
  
  
  

9、翻转对(hard)

  题源:链接

在这里插入图片描述

  
  

9.1、题解

  1)、思路分析
  翻转对和逆序对的定义大同小异,逆序对是前面的数要大于后面的数。而翻转对是前面的一个数要大于后面某个数的两倍。因此,我们依旧可以用归并排序的思想来解决这个问题。
  
  而与上个问题不同的是,上一道题我们可以一边合并一遍计算小于当前元素右侧元素,但是这道题要求的是左边元素大于右边元素的两倍,若直接合并的话,是无法快速计算出翻转对的数量的。
  因此,在归并排序之前,我们可以借助左右区间已经排序好的单调性,先完成对翻转对的统计。由于两个指针都是不回退的的扫描到数组的结尾,因此两个有序序列求出翻转对的时间复杂度是 O ( N ) O(N) O(N)

在这里插入图片描述

  
  2)、题解
  以升序为例:

class Solution {
public:int tmp[50005] = {0};int mergesort(vector<int>& nums, int left, int right) {if (left >= right)return 0;//[left,mid] [mid+1, right]int mid = (left + right) / 2;int sum = 0;sum += mergesort(nums, left, mid) + mergesort(nums, mid + 1, right);// 统计:(单调性为升序)int cur1 = left, cur2 = mid + 1;while(cur1 <= mid && cur2 <= right){if(nums[cur1]/2.0 > nums[cur2]){sum += mid - cur1 + 1;cur2++;}else cur1++;}// while (cur2 <= right) // 统计部分其它写法:升序的情况// {//     while (cur1 <= mid && nums[cur2] >= nums[cur1] / 2.0)//         cur1++;//     if (cur1 > mid)//         break;//     sum += mid - cur1 + 1;//     cur2++;// }// 排序:升序版,[left, mid][mid+1, right]cur1 = left, cur2 = mid + 1;int i = left;while (cur1 <= mid && cur2 <= right) {if (nums[cur1] > nums[cur2])tmp[i++] = nums[cur2++];elsetmp[i++] = 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 sum;}int reversePairs(vector<int>& nums) {return mergesort(nums, 0, nums.size()-1);}
};

  
  
  
  
  以降序为例:

class Solution {
public:int tmp[50005] = {0};int mergesort(vector<int>& nums, int left, int right) {if (left >= right)return 0;//[left,mid] [mid+1, right]int mid = (left + right) / 2;int sum = 0;sum += mergesort(nums, left, mid) + mergesort(nums, mid + 1, right);// 统计:(单调性为降序)int cur1 = left, cur2 = mid + 1;while (cur1 <= mid && cur2 <= right) {if (nums[cur1] / 2.0 > nums[cur2]) {sum += right - cur2 + 1;cur1++;} elsecur2++;}// while (cur1 <= mid) // 统计部分其它写法:降序的情况// {//     while (cur2 <= right && nums[cur2] >= nums[cur1] / 2.0)//         cur2++;//     if (cur2 > right)//         break;//     ret += right - cur2 + 1;//     cur1++;// }// 排序:降序版,[left, mid][mid+1, right]cur1 = left, cur2 = mid + 1;int i = left;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 j = left; j <= right; ++j) {nums[j] = tmp[j];}return sum;}int reversePairs(vector<int>& nums) {return mergesort(nums, 0, nums.size() - 1);}
};

  
  
  
  
  
  
  
  

Fin、共勉。

在这里插入图片描述

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

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

相关文章

Vivado使用(1)——综合的约束与策略

目录 一、概述 二、约束与策略 2.1 约束 2.1.1 物理约束 2.1.2 时序约束 2.2 综合策略 2.2.1 flatten_hierarchy 2.2.2 gated_clock_conversion 2.2.3 bufg 2.2.4 fanout_limit 2.2.5 directive 2.2.6 retiming 2.2.7 fsm_extraction 2.2.8 keep_equivalent_regi…

达梦数据库 创建外部表 [-7082]:外部表数据错误.

1&#xff1a;定义 外部表&#xff0c;是指不存在于数据库中的表。通过向达梦提供描述外部表的元数据&#xff0c;可以把一 个操作系统文件当成一个只读的数据库表&#xff0c;就像这些数据存储在一个普通数据库表中一样来 进行访问。 外部表的数据存储在操作系统中&#xff0…

NineData与StarRocks商业化运营公司镜舟科技完成产品兼容认证

近日&#xff0c;镜舟科技与NineData完成产品兼容测试。在经过联合测试后&#xff0c;镜舟科技旗下产品与NineData云原生智能数据管理平台完全兼容&#xff0c;整体运行高效稳定。 镜舟科技致力于帮助中国企业构建卓越的数据分析系统&#xff0c;打造独具竞争力的“数据护城河”…

专题:一个自制代码生成器(嵌入式脚本语言)之模型开发

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 专题&#xff1a;一个自制代码…

FFMPEG对于处理rtp流出现马赛克问题处理

背景 本项目是基于FFMPEG 3.3版本进行的开发。 近期5G发展迅速&#xff0c;无线集群中的带宽不再是瓶颈&#xff0c;对于视频质量的要求也越来越高&#xff0c;现在使用720P、1080P、2K、4K进行视频通话成为了日常。 问题描述 本项目之前对于CIF和VGA格式的视频进行录…

Spring Boot 一些常用的高级特性

Spring Boot 提供了许多高级特性&#xff0c;这些特性旨在简化开发流程、提高开发效率、增强应用的功能和性能。下面是一些重要的高级特性&#xff1a; 1. 自动配置&#xff08;Auto-configuration&#xff09; Spring Boot 的自动配置尝试根据添加到项目中的jar依赖自动配置…

通过 key 管理状态

Vue 默认按照“就地更新”的策略来更新通过 v-for 渲染的元素列表。当数据项的顺序改变时&#xff0c;Vue 不会随之移动 DOM 元素的顺序&#xff0c;而是就地更新每个元素&#xff0c;确保它们在原本指定的索引位置上渲染。 默认模式是高效的&#xff0c;但只适用于列表渲染输…

【python 数据可视化】 WordCloud词云图

目录 词云简介 准备工作 安装方法一&#xff1a; 安装方法二&#xff1a; 生成词云步骤 数据预处理&#xff1a; 分词&#xff1a; 统计词频出现的次数&#xff1a; 去除词语&#xff1a; 生成词云&#xff1a; 显示词云&#xff1a; 保存词云&#xff1a; 完整代码 词…

AugmentedReality之路-通过蓝图启动AR相机(2)

本文实现打开AR相机和关闭AR相机功能&#xff0c;在主界面点击Start AR按钮后打开AR相机&#xff0c;在主界面点击Stop AR按钮后关闭AR相机 1、启动AR相关插件 通过Edit->Plugins启用AugmentedReality下面的所有插件 2、自定义Pawn 在Content->ARBase目录右键&…

iOS开发进阶(十一):ViewController 控制器详解

文章目录 一、前言二、UIViewController三、UINavigationController四、UITabBarController五、UIPageViewController六、拓展阅读 一、前言 iOS 界面开发最重要的首属ViewController和View&#xff0c;ViewController是View的控制器&#xff0c;也就是一般的页面&#xff0c;…

Hive详解(3)

Hive 数据类型 struct类型 struct&#xff1a;结构体&#xff0c;对应了Java中的对象&#xff0c;实际上是将数据以json形式来进行存储和处理 案例 原始数据 a tom,19,male amy,18,female b bob,18,male john,18,male c lucy,19,female lily,19,female d henry,18,male davi…

基于ssm网上服装销售系统论文

摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于网上服装销售系统系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了网上服装销售系统系统&#xff0c;它彻底…

UNDERSTANDING HTML WITH LARGE LANGUAGE MODELS

UNDERSTANDING HTML WITH LARGE LANGUAGE MODELS 相关链接&#xff1a;arXiv 关键字&#xff1a;大型语言模型、HTML理解、Web自动化、自然语言处理、机器学习 摘要 大型语言模型&#xff08;LLMs&#xff09;在各种自然语言任务上表现出色。然而&#xff0c;它们在HTML理解方…

【JS笔记】JavaScript语法 《基础+重点》 知识内容,快速上手(六)

面向对象OOP 首先&#xff0c;我们要明确&#xff0c;面向对象不是语法&#xff0c;是一个思想&#xff0c;是一种 编程模式面向&#xff1a; 面&#xff08;脸&#xff09;&#xff0c;向&#xff08;朝着&#xff09;面向过程&#xff1a; 脸朝着过程 》 关注着过程的编程模…

shell脚本发布docker springboot项目示例

docker、git、Maven、jdk8安装略过。 使git pull或者git push不需要输入密码操作方法 约定&#xff1a; 路径&#xff1a;/opt/springbootdemo&#xff0c; 项目&#xff1a;springbootdemo&#xff0c; 打包&#xff1a;springbootdemo.jar&#xff0c; docker容器名字&#x…

Netty 代理TCP 转发集群方案

使用 Netty 自定义协议连接物联网设备&#xff0c;业务增大之后&#xff0c;势必需要使用集群方案。 #nginx负载均衡 Nginx 1.9 已经支持 TCP 代理和负载均衡&#xff0c;并可以通过一致性哈希算法将连接均匀的分配到所有的服务器上。 修改配置文件 http{ … } stream{ ups…

Android ImageView以及实现截图

实现效果 截图前 截图后 代码 package cn.jj.huaweiad;import android.annotation.SuppressLint; import android.graphics.Bitmap; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.view.ViewGro…

硬件项目中的turn-key 是啥意思?案例应用

在硬件项目中&#xff0c;turn-key是指一种工程项目模式&#xff0c;即交钥匙工程。这种模式通常由独立的第三方软件厂商直接与芯片厂商合作&#xff0c;基于芯片厂商的硬件方案和协议&#xff0c;集成成熟的上层软件和应用&#xff0c;并整套提供给电子产品生产厂商。这种模式…

LLM之RAG实战(三十五)| 使用LangChain的3种query扩展来优化RAG

RAG有时无法从矢量数据库中检索到正确的文档。比如我们问如下问题&#xff1a; 从1980年到1990年&#xff0c;国际象棋的规则是什么&#xff1f; RAG在矢量数据库中进行相似性搜索&#xff0c;来查询与国际象棋规则问题相关的相关文档。然而&#xff0c;在某些情况下&#xff0…

Ioc容器创建 和 读取组件的测试类

A接口 package com.atguigu.Ioc_03;public interface A {void dowork(); }HappyComponent.java package com.atguigu.Ioc_03;public class HappyComponent implements A {// 默认包含无参的构造方法Overridepublic void dowork() {System.out.println("我是&#xff1a;…