leetcodehot100刷题——排序算法总结(完结)

排序算法总结

冒泡排序

介绍

冒泡排序(Bubble Sort)是一种简单的比较排序算法,其工作原理类似于气泡在水中上升的过程。它通过重复遍历要排序的列表,比较相邻的两个元素,如果它们的顺序不正确就交换它们的位置。这个过程会持续进行,直到整个列表没有需要交换的元素为止。

步骤(以升序排序为例)

  1. 从列表的第一个元素开始,比较相邻的两个元素,如果前者比后者大,则交换它们的位置。
  2. 继续这个过程,直到遍历完整个列表。此时,最大的元素会“冒泡”到列表的末尾。
  3. 重复以上过程,每次遍历的范围逐渐减少(因为每次遍历都会把最大的元素放在正确的位置),直到整个列表有序。

算法实现

void bubbleSort(vector<int> &arr){
	int n=arr.size();//复习size()
	for(int i=0;i<n-1;i++){//控制比较次数
		for(int j=0;j<n-1-i;j++){//控制相邻元素的比较和交换,上层循环完一次,最大的数会到最右边固定住,所以循环次数是n-1-i
		if(arr[j]>arr[j+1]{
			swap(arr[j],arr[j+1]);
			}
		}
	}
}

复杂度分析

时间复杂度

(1)最好情况:当输入数组已经是有序的时候,冒泡排序只需要遍历一次数组即可完成排序。时间复杂度为 O(n)。
(2)最坏情况:当输入数组完全倒序时,每两个相邻元素都需要进行比较和交换,时间复杂度为 O(n^2)。
(3)平均情况:对于一个随机排列的数组,需要进行多次比较和交换操作,时间复杂度为 O(n^2)。

空间复杂度

冒泡排序是一种原地排序算法,它只需要一个额外的临时变量用于交换元素,不需要额外的空间。因此,其空间复杂度为 O(1)。

是否为稳定排序:是

稳定排序的定义

如果一个排序算法能够保证在排序后,数据中相同元素之间的相对顺序与排序前相同,那么这个算法就是稳定排序算法。

在冒泡排序中,当比较和交换相邻元素时,只有当前者大于后者时才会交换它们的位置如果两个元素相等,它们不会被交换,因此它们的相对顺序得以保持不变。

选择排序

介绍

选择排序(Selection Sort)工作原理是:每次从未排序的部分中找到最小(或最大)的元素,然后将其交换未排序部分起始位置,直到整个数组排序完成。

步骤(以升序排序为例)

1.从数组的第 i 个元素开始,找到从第 i 到第 n−1 个元素中最小的元素。
2. 将找到的最小元素第 i 个元素交换位置。
3. 重复步骤 1 和 2,每次从下一个位置开始,直到整个数组有序。

算法实现

void selectionSort(vector<int> &arr){
	int n=arr.size();//复习size()
	for(int i=0;i<n-1;i++){//对应步骤1的话
		int minIndex=i;// 当前最小元素的索引
		for(int j=i+1;j<n;j++){
			if(arr[j]<arr[minIndex]){
				minIndex=j;
			}
		}
		// 将找到的最小元素与第 i 个元素交换
		if(minIndex!=i)
			swap(arr[minIndex],arr[i]);
	}
}

复杂度分析

时间复杂度

(1)最好情况:即使数组已经完全有序,选择排序仍然需要遍历整个数组来寻找最小元素。因此,最好情况下的时间复杂度为O(n^2)。
(2)最坏情况:数组完全倒序时,同样需要遍历整个数组,且每次都需要交换元素。最坏情况下的时间复杂度为 O(n^2)。
(3)平均情况:对于一个随机排列的数组,需要进行多次比较和交换操作,时间复杂度为 O(n^2)。

空间复杂度

选择排序是一种原地排序算法,它只需要一个额外的临时变量用于交换元素,不需要额外的空间。因此,其空间复杂度为 O(1)。

是否为稳定排序:否

选择排序不是稳定排序算法。在选择排序中,当找到一个更小的元素并与前面的元素交换时,可能会改变相同元素之间的相对顺序。

举个栗子!

假设有一个数组 [3a, 3b, 2],其中 3a 和 3b 是两个值相同的元素,但它们的相对顺序在排序前是 3a 在前,3b 在后。我们的目标是通过选择排序对这个数组进行升序排序。
(1)第一轮:

  • 初始数组:[3a, 3b, 2]
  • 从索引 0 开始,寻找数组中最小的元素。
  • 比较 3a、3b 和 2,发现最小元素是 2,位于索引 2。
  • 将 2 与 3a 交换位置。
  • 结果数组:[2, 3b, 3a]
    (2)第二轮:
  • 数组状态:[2, 3b, 3a]
  • 从索引 1 开始,寻找子数组 [3b, 3a] 中的最小元素。 比较 3b 和3a,它们的值相同,因此最小元素可以认为是任意一个。 由于 3b 在索引 1,而 3a 在索引 2,但它们的值相同,所以不需要进行交换。
  • 结果数组:[2, 3b, 3a]
    (3)第三轮:
  • 数组状态:[2, 3b, 3a]
  • 从索引 2 开始,子数组只剩下 [3a],已经有序,无需操作。
  • 最终数组:[2, 3b, 3a]

可以发现:排序后的数组是 [2, 3b, 3a]。虽然数组已经按值正确排序,但原来的 3a 和 3b 的相对顺序发生了变化。
so,不稳定!

插入排序

介绍

插入排序(Insertion Sort)工作原理是:每次从未排序部分选取第一个元素,将其与已排序部分的元素进行比较,并插入到已排序部分的合适位置,直到整个数组排序完成。

步骤(以升序排序为例)

1.从数组的第 1 个元素开始,将其与前面已排序部分的元素进行比较。
2. 如果当前元素小于已排序部分的最后一个元素,则将已排序部分的元素依次向后移动,为当前元素腾出插入位置。
3. 将当前元素插入到合适的位置
4. 重复步骤 1 - 3,直到整个数组有序。

算法实现

void insertSort(vector<int> &arr){
	int n=arr.size();
	for(int i=0;i<n-1;i++){
		int cur=arr[i];//当前要插入的元素
		int j=i-1;
		while(arr[j]>arr[i]&&j>=0){
			arr[j+1]=arr[j];
			j--;
		}
		arr[j+1]=cur;//插入
	}
}

复杂度分析

时间复杂度

(1)最好情况:当输入数组已经是有序的时候,每次插入元素时无需移动已排序部分的元素,时间复杂度为 O(n)。
(2)最坏情况:当输入数组完全倒序时,每次插入元素都需要与已排序部分的所有元素进行比较并移动,时间复杂度为 O(n²)。
(3)平均情况:对于一个随机排列的数组,需要进行多次比较和交换操作,时间复杂度为 O(n²)。

空间复杂度

插入排序是一种原地排序算法,它只需要一个额外的临时变量用于交换元素,不需要额外的空间。因此,其空间复杂度为 O(1)。

是否为稳定排序:是

插入排序是稳定排序算法。在插入排序中,当比较和移动元素时,只有当前元素小于已排序部分的元素时才会进行移动操作。如果两个元素相等,它们的相对顺序保持不变。

希尔排序

介绍

希尔排序(Shell Sort)是插入排序的一种高效改进版本。它的工作原理是:先将整个待排序的记录序列分割成若干子序列分别进行插入排序,然后依次缩减间隔(步长),直至步长为 1 时进行最后一次插入排序,使得整个序列有序。

步骤(以升序排序为例)

1.确定初始步长 :选择一个增量序列,例如初始步长可以取数组长度的一半,并依次减半,直到步长为 1。
2. 分组与排序 :按照步长将数组分成若干组,每组包含间隔为步长的元素。对每一组内的元素进行插入排序。eg:[5,1,2,34,53,2,1].我选择步长为3,那么分组是[5,34,1],[1,53],[2,2]
4. 缩减步长并重复 :减小步长,重复步骤 2 的分组和排序过程,直到步长缩减为 1。此时,整个数组经过多次局部有序的调整,最终通过一次完整的插入排序得到有序序列。

算法实现

void shellSort(vector<int> &arr){
	int n=arr.size();
	int gap=n/2;//初始步长
	while(gap>0){
	//对每个步长gap的分组进行插入排序
	for(int i=gap;i<n;i++){
		int temp=arr[i];
		int j=i-gap;//注意这里!间隔不是1是步长啊!
		while(arr[j]>temp&&j>=0){
			arr[j+gap]=arr[j];
			j-=gap;
			}
		arr[j+gap]=temp;
		gap/=2;//减少步长
		}
	}
}

跟插入排序蛮像的哈!插入排序步长是1

复杂度分析

时间复杂度

(1)最好情况:当输入数组已经是有序的时候,希尔排序的时间复杂度接近 O(n),因为每次插入元素时无需移动已排序部分的元素,此时步长缩减过程主要是进行少量的比较操作。
(2)最坏情况:希尔排序的最坏情况时间复杂度取决于所采用的步长序列。对于最简单的步长序列(如每次减半),最坏情况下的时间复杂度为 O(n²)。但有一些更好的步长序列(如 Sedgewick 提出的序列),可以将时间复杂度降低到 O(n^1.25) 或更优。
(3)平均情况:希尔排序的平均时间复杂度介于 O(n^1.25) 和 O(n²) 之间,具体取决于步长序列的选择。

空间复杂度

希尔排序是一种原地排序算法,它只需要一个额外的临时变量用于交换元素,不需要额外的空间。因此,其空间复杂度为 O(1)。

是否为稳定排序:否

希尔排序不是稳定排序算法。在希尔排序中,由于元素可能会在不同组之间进行移动,导致相同元素之间的相对顺序发生改变。

归并排序

介绍

归并排序(Merge Sort)是一种经典的分治算法,其基本思想是将数组分成两部分分别对这两部分进行排序,然后再将排序后的两部分合并成一个有序的整体。

步骤(以升序排序为例)

1.分解:将数组不断分成两半,直到每个子数组只有一个元素(此时该子数组自然是有序的)。
2.合并:将两个相邻的有序子数组合并成一个有序的数组。

Part 1 递归实现:

void merge(vector<int>&arr,int left,int mid,int right){
	int i=left,j=mid+1;
	vector<int>temp;// 临时数组,用于存放合并后的结果
	while(i<=mid&&j<=right){
		if(arr[i]<=arr[j]){
			temp.push_back(arr[i]);
			i++;
		}else{
			temp.push_back(arr[j]);
			j++
		}
	}
	// 将剩余的元素添加到临时数组中
	while(i<=mid){
		temp.push_back(arr[i]);
		i++
	}
	while(j<=right){
		temp.push_back(arr[j]);
		j--;
	}
	// 将临时数组中的元素复制回原数组
	for(int k=left;k<=right;k++){
		arr[k]=temp[k-left];
	}
}
void mergeSort(vector<int> &arr,int left,int right){
	if(left<right){
		int mid=(left+right)/2+left;
		mergeSort(arr,left,mid);// 对左半部分进行归并排序
		mergeSort(arr,mid+1,right);// 对右半部分进行归并排序
		merge(arr,left,mid,right);// 合并两个有序的子数组
	}
}

复杂度分析

时间复杂度

(1)最好情况 :每次分解都将数组均匀分成两半,并且合并操作的时间复杂度为 O(n),所以最好情况下的时间复杂度为 O(n log n)。
(2)最坏情况 :无论数组的初始状态如何,归并排序都需要进行 log n 层的分解和合并操作,每层操作的时间复杂度为 O(n),所以最坏情况下的时间复杂度为 O(n log n)。
(3)对于一个随机排列的数组,归并排序的时间复杂度为 O(n log n)。

空间复杂度

归并排序需要额外的存储空间来保存临时数组,空间复杂度为 O(n)。

是否为稳定排序:是

归并排序是稳定排序算法。在合并两个有序子数组时,如果两个元素相等,会优先将前面的子数组中的元素添加到临时数组中,从而保证了相同元素的相对顺序不变。

Part 2 非递归实现:

//这部分内容不变
void merge(vector<int>&arr,int left,int mid,int right){
	int i=left,j=mid+1;
	vector<int>temp;// 临时数组,用于存放合并后的结果
	while(i<=mid&&j<=right){
		if(arr[i]<=arr[j]){
			temp.push_back(arr[i]);
			i++;
		}else{
			temp.push_back(arr[j]);
			j++
		}
	}
	// 将剩余的元素添加到临时数组中
	while(i<=mid){
		temp.push_back(arr[i]);
		i++
	}
	while(j<=right){
		temp.push_back(arr[j]);
		j--;
	}
	// 将临时数组中的元素复制回原数组
	for(int k=left;k<=right;k++){
		arr[k]=temp[k-left];
	}
}
void mergeSort(vector<int> &arr,int left,int right){
	int n=arr.size();
	vector<int>temp(n);
	 // 子数组长度从1开始,每次翻倍
	for(int sublength=1;sublength<n;sublength<<1){
		// 遍历数组,合并相邻的两个子数组
		for(int left=0;left<n;left+=sublength*2){
		int mid=left+sublength-1;
		int right=min(left+sublength*2-1,n-1);
		merge(arr,left,mid,right);
		}
	}
}

复杂度分析

时间复杂度

O(n log n):非递归归并排序的时间复杂度与递归版本相同,均为 O(n log n),其中 n 是数组的长度。这是因为算法将数组分成 log n 层,每层处理大约 n 个元素。

空间复杂度

O(n):由于在合并过程中使用了一个临时数组来存储合并后的结果,所以空间复杂度为 O(n),其中 n 是数组的长度。

快速排序

介绍

快速排序(Quick Sort)是一种高效的分治排序算法(复习:归并排序是不是分治排序??是的!),其基本思想是通过选择一个基准元素,将数组分为两部分:一部分包含小于或等于基准的元素,另一部分包含大于基准的元素,然后递归地对这两部分进行快速排序。

步骤(以升序排序为例)

1.选择基准元素 :从数组中选择一个元素作为基准(pivot)。常见的选择方法包括选择第一个元素、最后一个元素、中间元素或随机元素。
2.分区操作 :将数组中的元素重新排列,使得所有小于或等于基准的元素都移到基准的左边,所有大于基准的元素都移到基准的右边。基准元素最终会位于其正确的位置。(其他元素不一定在正确位置哦!每次都是为了把基准元素排对位置~)
3.递归排序 :对基准左边和右边的两个子数组分别递归地进行快速排序,直到子数组的大小为 0 或 1,此时整个数组有序。

实现:

int partition(vector<int> &arr,int low,int high){
	int pivot=arr[high];//选择最后一个元素作为基准
	int i=low-1;//i是小于等于基准部分的最后一个元素的索引
	for(int j=low;j<high;j++){
		if(arr[j]<=pivot){
			i++;
			swap(arr[i],arr[j]);//把比基准元素大的数放在基准元素左边
		}
		//比基准元素大的数就不变动位置
		//这里不要想太多:我们只是需要把比基准元素小的数字放左边,大的数放右边,他们的位置对不对不重要,重要的是基准元素要放对位置!
	}
	//经过上面的for循环,我们已经把所有小于基准元素的数放在基准元素左边了,i+1就是正确位置
	swap(arr[i+1],arr[high]);// 将基准元素放到正确的位置
	return i+1;//返回基准元素的位置
}
void quickSort(vector<int> &arr,int low,int high){
	if(low<high){
		int pivotIndex=partiton(arr,low,high);//分区操作
		quickSort(arr,low,pivotIndex-1);//对左半部分进行快速排序
		quickSort(arr,pivotIndex+1,high);// 对右半部分进行快速排序
	}
}
int main()
{
	quickSort(arr,0,arr.size()-1);
}

复杂度分析

时间复杂度

(1)最好情况 :当每次分区操作都能将数组均匀分成两部分,此时递归树的深度为 log n,每层的时间复杂度为 O(n),所以最好情况下的时间复杂度为 O(n log n)。
(2)最坏情况 :当数组已经有序或逆序时,每次分区操作都只会将数组分成一个大小为 n - 1 和一个大小为 0 的子数组,此时递归树的深度为 n,时间复杂度为 O(n²)。
(3)平均情况:对于随机排列的数组,快速排序的平均时间复杂度为 O(n log n)。快速排序在实际应用中通常被认为是最快的通用排序算法之一。

空间复杂度

快速排序的空间复杂度主要取决于递归调用所需的栈空间。在最好情况下,递归树的深度为 log n,因此空间复杂度为 O(log n)。在最坏情况下,空间复杂度为 O(n)。

是否为稳定排序:否

快速排序不是稳定排序算法。在分区过程中,相同元素的相对顺序可能会因为交换操作而发生改变。

堆排序

介绍

堆排序(Heap Sort)是一种基于堆数据结构的排序算法。它的工作原理是将数组构造成一个堆,然后不断取出堆顶元素并重新调整堆,从而实现排序。堆是一种特殊的完全二叉树,其中父节点的值总是**大于或等于(大顶堆)小于或等于(小顶堆)**其子节点的值。堆排序利用了堆的性质来高效地找到数组中的最大或最小元素。

步骤(以升序排序为例)

  1. 构建大顶堆:将数组构造成一个大顶堆,此时堆顶元素是数组中的最大值
  2. 交换堆顶与末尾元素:将堆顶元素(最大值)与数组末尾元素交换,此时最大值位于数组的正确位置
  3. 重新调整堆:排除已排序的末尾元素,对剩余元素重新调整堆结构,使其再次成为大顶堆

重复步骤 2 和 3,直到所有元素都排序完成。

堆算法详细图解见大大link

实现:

void heapify(vector<int>&arr,int n,int i){
	//递归版本
	int largest=i;//初始化最大值为当前节点
	int left=2*i+1;//左子节点
	int right=2*i+2;//右子节点
	if(left<n&&arr[left]>arr[largest]){
		largest=left;
	}
	if(right<n&&arr[right]>arr[largest]){
		largest=right;
	}
	if(largest!=i){
		swap(arr[i],arr[largest]);
		heapify(arr,n,largest);
	}

	//非递归版本
	int temp=arr[i];//当前元素i看出成最大值
	for(int j=2*i+1;j<n;j=2*j+1){
		if(j+1<n&&arr[j]<arr[j+1]){
			如果左子结点小于右子结点,j指向右子结点
			j++;
		}
		if(arr[j]>temp){
			arr[i]=arr[j];
			i=j;
		}else{
			break;
		}
	}
	arr[i]=temp;
}
void heapSort(vector<int>& arr){
	int n=arr.size();
	//构造大顶堆
	//n/2-1代表最后一个非叶子节点
	//从最后一个非叶子结点开始调整
	for(int i=n/2-1;i>=0;i--){
		heapify(arr,n,i);
	}
	//逐个取出堆顶元素并调整堆
	for(int i=n-1;i>=0;i--){
	 	swap(arr[i],arr[0]);// 将堆顶元素(最大值)移到数组末尾
	 	heapify(arr,i,0);//调整剩余元素为大顶堆
	}
}

复杂度分析

时间复杂度

构建堆的时间复杂度为 O(n),每次调整堆的时间复杂度为 O(log n),需要进行 n 次调整,因此总时间复杂度为 O(n log n)。堆排序的时间复杂度在最好、最坏和平均情况下均为 O(n log n)。

空间复杂度

堆排序的空间复杂度为 O(1),因为它只使用了少量的额外空间

是否为稳定排序:否

堆排序不是稳定排序算法。在堆排序过程中,相同元素的相对顺序可能会因为交换操作而发生改变。

计数排序

介绍

计数排序(Counting Sort)是一种非比较排序算法,它的工作原理是统计数组中每个元素出现的次数,然后根据统计结果确定每个元素的正确位置。计数排序适用于整数排序,尤其是当输入数据范围较小时。

步骤(以升序排序为例)

1.找到数组中的最大值和最小值,确定数据范围。
2. 创建一个计数数组,用于统计每个元素出现的次数。
3. 计算每个元素的累计次数,确定元素的正确位置。
4. 根据累计次数将元素放入输出数组。。

实现:

void countingSort(vector<int>& arr){
	int min_val=max_val=arr[0];
	for (int i = 1; i < array.length; i++) {
	    if (array[i] > max_val) {
	        max_val = array[i];
	    }
	    if(array[i] < min_val) {
	        min_val = array[i];
	    }
    }
	int range=max_val-min_val+1;//数据范围
	vector<int>count(range,0);//计数数组
	vector<int>output(arr.size());//输出数组
	//统计每个元素出现的次数
	for(int num:arr){
		count[num-min_val]++;
	}
	//计算累计次数
	for(int i=1;i<range;i++){
		count[i]+=count[i-1];
	}
	//根据累计次数将元素放入输出数组
	for(int i=arr.size()-1;i>=0;i--){
		output[count[arr[i]]-min_val-1]=arr[i];
		count[arr[i]-min_val]--;//
	}
	return output;
}

复杂度分析

时间复杂度

计数排序的时间复杂度为 O(n + k),其中 n 是数组长度,k 是数据范围(最大值减最小值加 1)。它适用于数据范围较小的情况。

空间复杂度

计数排序的空间复杂度为 O(n + k),需要额外的计数数组和输出数组。

是否为稳定排序:是

计数排序是稳定排序算法。在计数排序过程中,相同元素的相对顺序得以保持。

桶排序

介绍

桶排序(Bucket Sort)是一种分布排序算法,其基本思想是将数组元素分散到有限数量的桶中,每个桶再单独排序,最后将各个桶中的元素按顺序合并。桶排序适用于均匀分布在某一范围内的实数。

步骤(以升序排序为例)

  1. 确定数据范围,将数据划分到若干个桶中。
  2. 将数组中的元素放入对应的桶。
  3. 分别对每个桶内的元素进行排序(可使用插入排序、快排等)。
  4. 按顺序将每个桶中的元素合并,构成最终的排序结果。

实现:

void bucketSort(vector<float>& arr){
	int n=arr.size();
	vector<vector<float>>buckets(n);
	int max_val=min_val=arr[0];
	for (int i = 1; i < n; i++) {
	    if (array[i] > max_val) {
	        max_val = array[i];
	    }
	    if(array[i] < min_val) {
	        min_val = array[i];
	    }
    }
    int range = max_val - min_val + 1;
    int bucket_size = max(1, range/n + 1); // 每个桶的大小
    // 初始化桶
    vector<vector<int>> buckets(bucket_count);
    // 将元素分配到桶中
    for (int num:arr) {
        int idx = (num-min_val) / bucket_size;
        buckets[idx].push_back(num);
    }
    // 对每个桶排序并合并结果
    arr.clear();
    for (auto& bucket : buckets) {
        sort(bucket.begin(), bucket.end());
        for (int num:bucket) {
            arr.push_back(num);
        }
    }
    
}

复杂度分析

时间复杂度

平均情况:O(n + k),k为桶数。
最坏情况(所有数据集中一个桶):O(n²)。

空间复杂度

O(n + k),需要额外空间存储桶。

是否为稳定排序:取决于桶内排序方式

若桶内使用稳定排序算法(如插入排序),则整体为稳定排序。

基数排序

介绍

基数排序(Radix Sort)是一种非比较型整数排序算法,按照数字的每一位(从最低位到最高位或反过来)依次排序。通常用于整数或字符串等可分解为位的离散值类型。适合排序长度一致的整数或字符串。

步骤(以升序排序为例,最低位优先)

  1. 找出最大元素,确定最大位数。
  2. 从最低位到最高位,对每一位执行一次稳定排序(如计数排序)。
  3. 多轮排序完成后,整体有序。

实现:

//找最大值
int getMax(const vector<int>& arr){
	int mx=arr[0];
	for(int i=1;i<arr.size();i++){
		if(arr[i]>mx){
			mx=arr[i];
		}
	}
	return mx;
}

void countingSortByDigit(vector<int>& arr, int exp) {
	int n=arr.size();
	vector<int>output(n);
	vector<int>count(10,0);
	
	//统计当前位数的频率
	for(int i=0;i<n;i++){
		count[(arr[i]/exp)%10]++;
	}
	
	//计算累计频率
	for(int i=1;i<10;i++){
		count[i]+=count[i-1];
	}
		
	//构建输出数组(从后往前保证稳定性)
	for(int i=n-1;i>=0;i--){
		int digit=(arr[i]/exp)%10;
		output[count[digit]-1]=arr[i];
		count[digit]--;
	}
	
	//拷贝回原数组
	for(int i=0;i<n;i++){
		arr[i]=output[i];
	}
}

void radixSort(vector<int>& arr){
		int max_val=getMax(arr);
		for(int exp=1;max_val/exp>0;exp*=10){
			countingSortByDigit(arr,exp);
		}
	}
	

复杂度分析

时间复杂度

O(d × (n + k)),其中 d 是最大数的位数,n 是元素数量,k 是每位上的可能数值(通常为10)。

空间复杂度

O(n + k),使用额外计数数组和输出数组。

是否为稳定排序:是

基数排序在每个位上使用稳定排序,因此整体是稳定排序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值