人工智能3.5 -- python算法篇(五)排序和查找

python,大数据,机器学习,深度学习,计算机视觉

三、python算法篇(五)排序和查找

前言 ---- 排序算法的稳定性

一个例子说明白!
比如,对这几个元组(4, 1) (3, 1) (3, 7) (5, 6),按照第一个元素的大小对他们进行排序,由于(3, 1)和(3, 7)的第一个元素是相等的,所以有下面两种排序结果:
(1)(3, 1) (3, 7) (4, 1) (5, 6) (维持原有次序)----- 稳定
(2)(3, 7) (3, 1) (4, 1) (5, 6) (原有次序被改变) ----- 不稳定
我们称第(1)种维持原有次序的排序算法是稳定的,而第(2)种改变了原有次序的排序算法是不稳定的。

同理:若原次序为 (4, 1) (3, 7) (3, 1) (5, 6),对其排序,则排序结果:
(1)(3, 7) (3, 1) (4, 1) (5, 6) (维持原有次序)----- 稳定
(2)(3, 1) (3, 7) (4, 1) (5, 6) (原有次序被改变) ----- 不稳定

1. 冒泡排序

自己画了个图,便于彻底理解!不必死记用背
请添加图片描述

(1)基本写法。下面这种写法太简单!不多说

09_bubble_sort.py代码:

def bubble_sort(alist):
	"""冒泡排序"""
	n = len(alist)
	"""j控制循环次数。共n-1次"""
	for j in range(1, n): # 表1 ~ n-1,总共冒泡n-1次。 ||或写 range(0, n-1):即ragne(n-1):但下面要改成for i in range(n-1-j):即for i in range(0, n-1-j):
		"""i控制下标/游标。从0开始,第一次一直移动到第n-1个元素(倒数第二个元素)即下标n-1-1即可,因为自然会取到第n个元素(最后一个元素)下标n-1"""
		for i in range(n-j): # 即range(0, n-j):表0 ~ n-j-1
			if alist[i] > alist[i+1]:
				alist[i], alist[i+1] = alist[i+1], alist[i] #python专有的交换语法

#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(li)
	bubble_sort(li)
	print(li)

思考:
想想若本来就是有序的序列[1, 2, 3, 4, 5, 6, 7],还要再都依次比较吗?
再想想若除了前两个元素其他都是有序的序列[2, 1, 3, 4, 5, 6, 7],还要这么写吗?

(2)改进的冒泡排序。----- 可处理一开始就是有序 或者 排序过程中的某次就已经是有序的

写法一:

def bubble_sort(alist):
	"""冒泡排序"""
	n = len(alist)
	"""j控制循环次数。共n-1次"""
	for j in range(n-1): #每次外层for循环开始,标记号count都重置为0
		count = 0
		"""i控制下标/游标。从0开始,第一次一直游标到倒数第二个元素(第n-1个元素)即下标n-1-1即可,因为自然会取到最后一个元素(第n个元素)下标n-1"""
		for i in range(0, n-1-j): #若内层for循环有过交换,则count+1
		# 即:for i in range(n-1-j): 
			if alist[i] > alist[i+1]:
				alist[i], alist[i+1] = alist[i+1], alist[i] #python专有的交换语法
				count += 1 # python不能写count++
		if 0 == count: #若没有过交换,即顺序是排好了的,则不需再遍历了。
			return


#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(li)
	bubble_sort(li)
	print(li)

写法二:

def bubble_sort(alist):
	"""冒泡排序"""
	n = len(alist)
	"""j控制循环次数。共n-1次"""
	for j in range(n-1): #每次外层for循环开始,标记号count都重置为0
		swap = False
		"""i控制下标/游标。从0开始,第一次一直游标到倒数第二个元素(第n-1个元素)即下标n-1-1即可,因为自然会取到最后一个元素(第n个元素)下标n-1"""
		for i in range(0, n-1-j): #若内层for循环有过交换,则count+1
		# 即:for i in range(n-1-j): 
			if alist[i] > alist[i+1]:
				alist[i], alist[i+1] = alist[i+1], alist[i] #python专有的交换语法
				swap = True # 交换过
		if swap == False: #若没有过交换,即顺序是排好了的,则不需再遍历了。
			return


#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(li)
	bubble_sort(li)
	print(li)

最优时间复杂度:O(n) ------ 遍历一次发现没有任何可以交换的元素,排序结束
最坏时间复杂度:O(n2)
算法稳定性:稳定 ----- 前面讲的能维持原有次序

2. 选择排序

根本思路:不断地找出相对最小的数,放到开头。
实现过程:
li = [54, 23, 32, 324, 34, 324, 3]
首先,默认第一个元素li[0] = 54是最小的数,记录下标min_index = 0(实际代码记录下标,列表/数组就是玩下标的)
然后,其他的元素都和最小数比较,谁更小就重定谁是最小数:
比到第23时,最小数成了23,记录其下标min_index = 1
再往后走,324…和最小数23比较…,一直到3出现,最小数成了3,记录其下标min_index = 6
所以将最小数放到最左边开头,即交换 li[6] 和 li[0]
此为一轮。
接着,不管li[0],再将li[1]看出最小的数,重复上面操作,进行几轮操作。如下:

一轮:li = [3,                    23, 32, 324, 34, 324, 54]
二轮:li = [3, 23,                32, 324, 34, 324, 54]
三轮:li = [3, 23, 32             324, 34, 324, 54]
四轮:li = [3, 23, 32, 34         324, 324, 54]
五轮:li = [3, 23, 32, 34, 54    324, 324]
六轮:li = [3, 23, 32, 34, 324, 324]

代码思路:
(1)初步代码设计:

def select_sort(alist):
	n = len(alist)
	min_index = 0
	for i in range(1,n):# j: 1 ~ n-1
		if alist[min_index]>alist[i]:
			min_index = i
	alist[min_index], alist[i] = alist[i], alist[min_index]

其实也可以按下面这样设计,但不如上面的效率高,因为alist[min_index], alist[i] = alist[i], alist[min_index]交换是执行两步(其他语言temp那种交换就是三步),前面已说过,列表(如同其他数组)就是玩下标的。
参考:

def select_sort(alist):
	n = len(alist)
	min_index = 0
	for i in range(1,n):# j: 1 ~ n-1
		if alist[min_index]>alist[i]:
			alist[min_index], alist[i] = alist[i], alist[min_index]

(2)进一步地:

def select_sort(alist):
	n = len(alist)
	for j in range(n-1):
		min_index = j
		for i in range(j+1, n):
			if alist[min_index] > alist[i]:
				min_index = i
		alist[j], alist[min_index] = alist[min_index], alist[j]

完整代码如下:
10_select_sort.py代码:

def select_sort(alist):
	"""选择排序"""
	n = len(alist)
	for j in range(n-1): # 即range(0, n-1) 故j: 0 ~ n-2
		min_index = j
		for i in range(j+1, n):
			if alist[min_index] > alist[i]:
				min_index = i
		alist[j], alist[min_index] = alist[min_index], alist[j]

#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(li)
	select_sort(li)
	print(li)

最优时间复杂度:O(n2) ------ 即使是排序好的有序序列也是O(n2)
最坏时间复杂度:O(n2)
算法稳定性:不稳定 ----- 有重复值时,考虑升序每次选择最大的情况

3. 插入排序

插入排序和选择排序一样都是分成左右两部分:左边(下标较小的)是排好序的,右边(下标较大的))是无序的。
不同的是:
上面选择排序是从右边选出最小值放到左边。
而插入排序是从右边随便拿一个,实际操作也就是一个个依次拿,和左边的去比较,排序插入到左边。即插入排序名字由此而来!

(1)基本写法。

代码思路:
(1)初步代码设计:

def insert_sort(alist):
	j = 1 # i = [1, 2, 3, ..., n-1]
	# 执行从右边的无序序列中取出第一个元素,即i位置的元素,然后将其插入到前面的正确位置中
	# 从第i个元素开始向前比较,如果小于前一个元素,交换
	for i in range(j, 0, -1): # j:从i ~ 1,递减。如range(5, 0, -1)是[5,4,3,2,1],最后位是1不是0,最后位 = 0-步长 = 0-(-1) = 1
		if alist[i] < alist[i-1]:
			alist[i], alist[i-1] = alist[i-1], alist[i]

(2)进一步地:

def insert_sort(alist):
	n = len(alist)
	for j in range(1, n):# j = [1, 2, 3, ..., n-1]
		# 执行从右边的无序序列中取出第一个元素,即i位置的元素,然后将其插入到前面的正确位置中
		# 从第i个元素开始向前比较,如果小于前一个元素,交换
		for i in range(j, 0, -1): # j:从i ~ 1,递减。如range(5, 0, -1)是[5,4,3,2,1],最后位是1不是0,最后位 = 0-步长 = 0-(-1) = 1
			if alist[i] < alist[i-1]:
				alist[i], alist[i-1] = alist[i-1], alist[i]

完整代码如下:
11_insert_sort.py代码:

def insert_sort(alist):
	""""插入排序"""
	n = len(alist)
	for j in range(1, n):# j = [1, 2, 3, ..., n-1]
		# 执行从右边的无序序列中取出第一个元素,即i位置的元素,然后将其插入到前面的正确位置中
		for i in range(j, 0, -1): # j:从i ~ 1,递减。
			if alist[i] < alist[i-1]:
				alist[i], alist[i-1] = alist[i-1], alist[i]

#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(li)
	insert_sort(li)
	print(li)
(2)改进的插入排序。----- 可处理一开始就是有序 或者 排序过程中的某次就已经是有序的

代码思路:
(1)初步代码设计:

def insert_sort(alist):
	"""插入排序"""
	i = 1 # i = [1, 2, 3, ..., n-1]
	while i > 0:
		if alist[i] < alist[i-1]:
			alist[i],alist[i-1] = alist[i-1], alist[i]
			i -= 1
		else:
			break

(2)进一步地:

def insert_sort(alist):
	n = len(alist)
	for j in range(1, n): # j = [1, 2, 3, ..., n-1]
		i = j # i 代表内存循环起始值
		# 执行从右边的无序序列中取出第一个元素,即i位置的元素,然后将其插入到前面的正确位置中
		while i > 0:
			if alist[i] < alist[i-1]:
				alist[i], alist[i-1] = alist[i-1], alist[i]
				i -= 1
			else:#如果a[i]比左边a[i-1]大,则退出本次while循环,想想[1,2,3,4,5]的情况。
				break

完整代码如下:
11_insert_sort.py代码:

def insert_sort(alist):
	"""插入排序"""
	n = len(alist)
	for j in range(1, n): # j = [1, 2, 3, ..., n-1]
		i = j # i 代表内存循环起始值
		# 执行从右边的无序序列中取出第一个元素,即i位置的元素,然后将其插入到前面的正确位置中
		while i > 0:
			if alist[i] < alist[i-1]:
				alist[i], alist[i-1] = alist[i-1], alist[i]
				i -= 1
			else:
				break

#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(li)
	insert_sort(li)
	print(li)

最优时间复杂度:O(n)----- 升序排列,序列已经处于升序状态
最坏时间复杂度:O(n2)
稳定性:稳定

4. 希尔排序

希尔排序和插入排序差不多,唯一的区别是希尔排序有步长。
首先步长gap设计为4,
第一组:下标为0,4, 8的拿出来分成一组(步长gap=4,所以0,4,8)
第二组:下标为1,5, 的拿出来分成一组
第三组:下标为2,6, 的拿出来分成一组

然后每组组内用插入排序算法比较。
在这里插入图片描述在这里插入图片描述在这里插入图片描述
接下来将步长gap设计为2,再重复步骤,同上(我们暂时用折半的方法取步长值)
在这里插入图片描述
在这里插入图片描述在这里插入图片描述最后,直到gap=1时,再用插入排序法,结束。
在这里插入图片描述看似麻烦,实则若gap设计好(实际中怎么给gap最优设计需要通过数学计算得到),效率很高。

代码思路:
(1)首先考虑核心代码,开始步长gap=1时,

#第一步 gap = 1
if alist[i] < alist[i-1]:
	alist[i], alist[i-1] = alist[i-1], alist[i]
else:
	break

(2)进一步地,gap = 2,4,8等。
完整代码如下:
12_shell_sort.py代码:

def shell_sort(alist):
	"""希尔排序"""
	n = len(alist)
	# gap具体怎么取会影响效率,最优取法要通过数学运算来算出,这里不研究,下面暂时用折半的方法(如第一次取4,下一次取2,再下一次取1)取gap值
	gap = n//2 # 除法运算。python3 n/2得到小数,n//2得到整数。而老版本的python2可以写n/2得到整数
	
	# gap变化到0之前,插入算法执行的次数
	while gap > 0:
		for j in range(gap, n): # 希尔排序,与普通的插入算法的区别就是gap步长
			# j = [gap, gap+1, gap+2, gap+3,..., n-1]
			i = j
			while i > 0:
				if alist[i] < alist[i-gap]:
					alist[i], alist[i-gap] = alist[i-gap], alist[i]
					i -= gap
				else:
					break
		# 缩短gap步长
		gap //= 2


#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(li)
	shell_sort(li)
	print(li)

注:可以对比一下插入排序的代码,对比理解和记忆。
最优时间复杂度:O(n1.3) ;根据步长(上面的gap)序列的不同而不同
最坏时间复杂度:O(n2) ------- gap直接取1的时候,就是插入排序
稳定性:不稳定 ------ 假设排序序列中有两个相同又相邻的数77和77,因为分成多组,第一个77被分到的那组有可能在组里面是最大值或相对较大的排序到后面,而第二个77分到的组如果其在组里是最小值或相对比较小的被排序到了前面,这样一来最终结局就是原来的第一个77跑到了第二个77后面,所以不稳定

5. 快速排序(重点,必须掌握)

快排一句话:序列中任意取一个元素作为目标(中间值mid_value),其余元素比他小的放到他左面,比他大的放到右面。然后左右两面重复上面操作,再取一个中间值…
【分析】:
第一步:

def quick_sort(alist, first, last): # ([54, 23, 32, 324, 34, 324, 3], 0, 6)

    mid_value = alist[first]
    left = first
    right = last

# 代码核心思想:
    # 比中间值(mid_value)小的放在左边(left),比中间值大的放在右边(right)。
    while left < right:
        alist[left] = alist[right]
        alist[right] = alist[left]

    # 从上面循环退出时,left == right
    alist[left] = mid_value

# 递归:
    # 对left左边的列表执行快速排序
    quick_sort(alist, first, left-1)
    # 对left右边的列表进行快速排序
    quick_sort(alist, left+1, last)

第二步:

def quick_sort(alist, first, last): # ([54, 23, 32, 324, 34, 324, 3], 0, 6)
    """快速排序"""

    if first >= last:
        return

    mid_value = alist[first] # 54
    left = first # 0
    right = last # 6
    
    # 比中间值(mid_value)小的放在左边(left),比中间值大的放在右边(right)。
    while left < right: # 0 < 6
        # 只要右边的比中间值大,right就一直左移:因为要从右向左找比中间值小的放到左边left里。
        while left < right and alist[right] >= mid_value:
            right -= 1
        alist[left] = alist[right]

        # 只要左边的比中间值小,left就一直右移:因为要从左向右找比中间值大的放到右边right里。
        while left < right and alist[left] < mid_value:
            left += 1
        alist[right] = alist[left]


    # 从上面循环退出时,left == right
    alist[left] = mid_value

    # 对left左边的列表执行快速排序
    quick_sort(alist, first, left-1) # 递归思想

    # 对left右边的列表进行快速排序
    quick_sort(alist, left+1, last)


#test
if __name__ == "__main__":
    li = [54, 23, 32, 324, 34, 324, 3]
    print(li)
    quick_sort(li, 0, len(li)-1)
    print(li)

完整代码如下,也可将left写成low低位、right写成high高位:
13_quick_sort.py代码:

def quick_sort(alist, first, last):
	"""快速排序"""

	if first >= last:
		return

	mid_value = alist[first]
	low = first
	high = last
	while low < high:
		# high左移
		while low < high and alist[high] >= mid_value:
			high -= 1
		alist[low] = alist[high]

		# low右移
		while low < high and alist[low] < mid_value:
			low += 1
		alist[high] = alist[low]
	# 从循环退出时,low == high
	alist[low] = mid_value

	# 对low左边的列表执行快速排序
	quick_sort(alist, first, low-1)

	# 对low右边的列表进行快速排序
	quick_sort(alist, low+1, last)


#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(li)
	quick_sort(li, 0, len(li)-1)
	print(li)

最优时间复杂度:O(nlogn) ------ 第一次分成左右两组,左右总共执行n次;第二次再分成22=4组,共执行n次;第三次分成22*2=8组,共执行n次…,直到不可再分割时即每组只有一个元素时。可见总共分割了log2n次(简记作logn),每次执行了n次,所以最优时间复杂度O(nlogn)
最坏时间复杂度:O(n2)
稳定性:不稳定

6. 归并排序

归并排序是采用分治法的一个非常典型的应用。归并排序的思想就是先递归分解数组,再合并数组。
将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁最小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。
在这里插入图片描述
代码思路:
(1)初步代码设计:递归实现拆分!

def merge_sort(alist):
	n = len(alist)
	mid = n//2
	left_li = merge_sort(alist[:mid])
	right_li = merge_sort(alist[mid:])

(2)写递归一定注意写终止条件,避免死循环。这里不能无限拆分,拆到列表长度 为1时就不拆了!

def merge_sort(alist):
	n = len(alist)
	if n <= 1:
		return

	mid = n//2
	min = merge_sort(alist[:mid])

完整代码如下:
14_merge_sort.py代码:

def merge_sort(alist):
	"""归并排序"""
	n = len(alist)
	if n <= 1:
		return alist

	mid = n//2

	# 左部分列表: 采用归并排序后形成的有序的新的列表
	left_li = merge_sort(alist[:mid])# alist[:mid]表截取从开头到mid即下标0~mid的部分列表

	# 右部分: 采用归并排序后形成的有序的新的列表
	right_li = merge_sort(alist[mid:])# alist[mid:]表截取从mid到结尾即下标mid~len-1的部分列表

	# 将左右两个有序的子序列合并为一个新的整体
	left_pointer, right_pointer = 0, 0 # 指针,记录下标
	result = [] # 存放排序后的列表

	while left_pointer < len(left_li) and right_pointer < len(right_li):
		if left_li[left_pointer] <= right_li[right_pointer]:#等号保证了此算法(归并排序算法)的稳定-----见时间复杂度那里总结。若不加等号则变不稳定
			result.append(left_li[left_pointer])
			left_pointer += 1
		else:
			result.append(right_li[right_pointer])
			right_pointer += 1

	result += left_li[left_pointer:]
	result += right_li[right_pointer:]
	return result

#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(li)
#重点:
	merge_sort(li)#归并排序不改变原列表顺序,因为此法是新建一个result存放新的列表,从原列表alist往result里面放值
	print(li)
	print(merge_sort(li))

最优时间复杂度:O(nlogn) ------ 看上面开始的图,第一步(合1)需要执行n次,第二步(合2)需要执行n次
最坏时间复杂度:O(nlogn)
稳定性:稳定
只有归并排序算法需要开辟一块新的空间,虽然时间上它是好的效率高的,但是空间上它是大的。

排序算法总结对比

在这里插入图片描述

总结:

需要掌握3、4种排序算法不要求全部掌握。

但是!快排必须掌握,因为快排的时间复杂度最低效率最高(看最坏情况,见上表)应用是最广泛的!
虽然归并排序时间复杂度和快排一样好,但归并排序需要另开辟一额外的空间存放新列表占用空间大,所以快排是目前最优的排序算法!
虽然快排不稳定,但在实际应用中我们一般不需要保序(值相等的时候保持原次序),如果需要保序那就不用快排了。

7. 二分查找(折半查找)

联想实际查字典怎么查,让你查你的姓,你实际试试。比如“令狐”(Linghu),肯定是字典拿来中间随便翻开一页,如果你翻到的拼音在你的姓拼音之比如你翻到了拼音H位置(你要找的令狐拼音开头L在H后),那么就再往后面随便一翻;如果你翻到的拼音在你的姓拼音之比如你翻到了拼音O位置(你要找的令狐拼音开头L在O前),那么就再往面随便一翻…如此下去,直到找到为止。
在实际的查找案例中,若找不到,则说明没有我们可以返回False了。
在这里插入图片描述

注意:

使用二分查找(折半查找)的前提:被查的列表是有序列表,即升序或降序,如1, 3, 4, 7, 43,344。或者3223, 233, 23, 29, 6, 2这样的

法1(递归法):

15_binary_search.py代码:

def binary_search(alist, item):
	"""二分查找(递归法)"""
	n = len(alist)
	if n > 0:
		mid = n//2# 一定记住双斜线除号得到整数,单斜线除号得到小数
		if alist[mid] == item:
			return True
		elif item < alist[mid]:
			return binary_search(alist[:mid], item)#这里一定记得写return
		else:
			return binary_search(alist[mid+1:], item)#这里一定记得写return
	return False


#test
if __name__ == "__main__":
	li = [54, 23, 32, 324, 34, 324, 3]
	print(binary_search(li, 23))#23在li列表中,结果True
	print(binary_search(li, 100))#100不在li列表中,结果False

"""
运行结果:
True
False
"""
法2(first、last法):
def binary_search_2(alist, item):
	"""二分查找(非递归法)"""
	n = len(alist)
	first = 0#起始。这个叫first、last法,或者叫start、end法
	last = n-1#末尾
	while first <= last:
		mid = (first+last)//2
		if alist[mid] == item:
			return True
		elif item < alist[mid]:
			last = mid-1
		else:
			first = mid+1
	return False

最优时间复杂度:O(1) ------ 如li = [54, 23, 32, 324, 34, 324, 3],查找54。因为54在首元素,则执行一次即找到。
最坏时间复杂度:O(logn) ------ 同上面讲的算法,二分查找即折半查找,每次分成两部分,执行一次,共分了logn次(2的多少次幂),即1*logn = logn

8. 堆排序

def buildMaxHeap(arr):
    import math
    for i in range(math.floor(len(arr)/2),-1,-1):
        heapify(arr,i)
def heapify(arr, i):
    left = 2*i+1
    right = 2*i+2
    largest = i
    if left < arrLen and arr[left] > arr[largest]:
        largest = left
    if right < arrLen and arr[right] > arr[largest]:
        largest = right
    if largest != i:
        swap(arr, i, largest)
        heapify(arr, largest)
def swap(arr, i, j):
    arr[i], arr[j] = arr[j], arr[i]
def heapSort(arr):
    global arrLen
    arrLen = len(arr)
    buildMaxHeap(arr)
    for i in range(len(arr)-1,0,-1):
        swap(arr,0,i)
        arrLen -=1
        heapify(arr, 0)
    return arr

9. 计数排序

def countingSort(arr, maxValue):
    bucketLen = maxValue+1
    bucket = [0]*bucketLen
    sortedIndex =0
    arrLen = len(arr)
    for i in range(arrLen):
        if not bucket[arr[i]]:
            bucket[arr[i]]=0
        bucket[arr[i]]+=1
    for j in range(bucketLen):
        while bucket[j]>0:
            arr[sortedIndex] = j
            sortedIndex+=1
            bucket[j]-=1
    return arr

10. 基数排序

def radix(arr):
    digit = 0
    max_digit = 1
    max_value = max(arr)
    #找出列表中最大的位数
    while 10**max_digit < max_value:
        max_digit = max_digit + 1
    while digit < max_digit:
        temp = [[] for i in range(10)]
        for i in arr:
            #求出每一个元素的个、十、百位的值
            t = int((i/10**digit)%10)
            temp[t].append(i)
        coll = []
        for bucket in temp:
            for i in bucket:
                coll.append(i)
        arr = coll
        digit = digit + 1
    return arr
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值