字节面试手撕题:版本号排序
题目
给定版本号:version = ["1.5.1", "1.45.0", "1.99.99", "3.3.3.3", "1.5", "6"]
写一个函数对版本号从小到大排序。
解答
为了对版本号进行排序,我们需要将每个版本号字符串转换为整数元组,然后根据这些元组进行排序。这样可以确保每个部分按数值大小正确比较,并处理不同长度的版本号:
-
分割和转换:将每个版本号字符串按点号分割成多个部分,并将每个部分转换为整数。
-
元组比较:利用Python元组的自然排序机制,逐个比较每个部分的值。较短版本号在比较时,缺失的部分视为0。
-
排序:使用Python的内置排序函数,根据转换后的元组进行排序。
def sort_versions(versions):return sorted(versions, key=lambda v: tuple(map(int, v.split('.'))))# 示例测试
version = ["1.5.1", "1.45.0", "1.99.99", "3.3.3.3", "1.5", "6"]
sorted_versions = sort_versions(version)
print(sorted_versions)
# ['1.5', '1.5.1', '1.45.0', '1.99.99', '3.3.3.3', '6']
附1:key=lambda v: tuple(map(int, v.split('.')))的解释
1.v.split('.')
- 作用:将版本号字符串按点号
.
分割成多个部分 - 结果:生成字符串列表(每个部分仍是字符串)
"1.5.1".split('.') # 返回: ['1', '5', '1']
"3.3.3.3".split('.') # 返回: ['3', '3', '3', '3']
"6".split('.') # 返回: ['6']
2.map(int, ...)
-
作用:将每个字符串部分转换为整数
-
为什么需要:避免字符串比较(如 "10" < "2" 的错误情况)
map(int, ['1', '5', '1']) # 转换为: [1, 5, 1]
map(int, ['3', '3', '3', '3']) # 转换为: [3, 3, 3, 3]
map(int, ['6']) # 转换为: [6]
3.tuple(...)
-
作用:将整数列表转换为元组
-
为什么需要:元组支持按元素顺序比较(这是版本号排序的关键)
tuple([1, 5, 1]) # 转换为: (1, 5, 1)
tuple([3, 3, 3, 3]) # 转换为: (3, 3, 3, 3)
tuple([6]) # 转换为: (6,)
4.lambda v: ...
-
作用:创建一个临时函数,接受版本号字符串
v
,返回转换后的元组
# 定义一个匿名函数
lambda v: tuple(map(int, v.split('.')))
相当于:
def key_function(v):parts = v.split('.')int_parts = [int(part) for part in parts]return tuple(int_parts)
附2:快速排序的代码实现(递归算法)
快速排序是一种高效的排序算法,采用分治策略。其基本思想是选择一个基准元素,将数组分为两部分:小于基准的部分和大于基准的部分,然后递归地对这两部分进行排序。
-
基准选择:
-
选择数组中间元素作为基准(
pivot = arr[len(arr) // 2]
) -
也可以选择第一个、最后一个或随机元素作为基准
-
-
分区操作:
-
left
:存储所有小于基准的元素 -
middle
:存储所有等于基准的元素(处理重复值) -
right
:存储所有大于基准的元素
-
-
递归排序:
-
对左右分区递归调用快速排序
-
将排序后的左分区、中间元素、右分区合并
-
-
时间复杂度:
-
平均情况:O(n log n)
-
最坏情况(已排序数组):O(n²) - 可通过随机选择基准避免
-
空间复杂度:O(log n)(递归调用栈)
-
def quick_sort(arr):"""快速排序函数:param arr: 待排序列表:return: 排序后的列表"""# 递归终止条件:当数组长度为0或1时,直接返回if len(arr) <= 1:return arr# 选择基准元素(这里选择中间元素)pivot = arr[len(arr) // 2]# 创建三个分区left = [x for x in arr if x < pivot] # 小于基准的元素middle = [x for x in arr if x == pivot] # 等于基准的元素right = [x for x in arr if x > pivot] # 大于基准的元素# 递归排序左右分区,并合并结果return quick_sort(left) + middle + quick_sort(right)# 测试示例
if __name__ == "__main__":test_arr = [3, 6, 8, 10, 1, 2, 1]print("原始数组:", test_arr)sorted_arr = quick_sort(test_arr)print("排序结果:", sorted_arr)
附3:快速排序的代码实现(非递归算法)
快速排序的非递归实现使用栈来模拟递归过程,避免了递归调用的系统栈开销。下面是完整的实现:
def quick_sort_non_recursive(arr):"""快速排序的非递归实现:param arr: 待排序列表:return: 排序后的列表(原地排序)"""if len(arr) <= 1:return arr# 使用栈存储待处理的子数组范围stack = []# 初始范围:整个数组stack.append((0, len(arr) - 1))while stack:# 获取当前处理的子数组范围low, high = stack.pop()# 如果子数组长度小于等于1,跳过if low >= high:continue# 分区操作pivot_index = partition(arr, low, high)# 将左右子数组范围压入栈中# 先压入较大的子数组,后压入较小的子数组(优化栈深度)if (pivot_index - low) > (high - pivot_index):stack.append((low, pivot_index - 1))stack.append((pivot_index + 1, high))else:stack.append((pivot_index + 1, high))stack.append((low, pivot_index - 1))return arrdef partition(arr, low, high):"""分区函数:选择基准元素并将数组分为两部分:param arr: 待分区数组:param low: 子数组起始索引:param high: 子数组结束索引:return: 基准元素的最终位置"""# 选择基准元素(这里使用三数取中法优化)mid = low + (high - low) // 2# 对左、中、右三个元素进行排序if arr[low] > arr[mid]:arr[low], arr[mid] = arr[mid], arr[low]if arr[low] > arr[high]:arr[low], arr[high] = arr[high], arr[low]if arr[mid] > arr[high]:arr[mid], arr[high] = arr[high], arr[mid]# 选择中位数作为基准(放在high-1位置)pivot = arr[mid]arr[mid], arr[high] = arr[high], arr[mid]# 分区指针i = low - 1# 遍历子数组for j in range(low, high):if arr[j] <= pivot:i += 1arr[i], arr[j] = arr[j], arr[i]# 将基准元素放到正确位置arr[i + 1], arr[high] = arr[high], arr[i + 1]return i + 1# 测试代码
if __name__ == "__main__":# 测试用例test_cases = [[3, 6, 8, 10, 1, 2, 1],[10, 7, 8, 9, 1, 5],[],[1],[5, 4, 3, 2, 1],[1, 2, 3, 4, 5],[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]]for arr in test_cases:print(f"原始数组: {arr}")sorted_arr = quick_sort_non_recursive(arr.copy())print(f"排序结果: {sorted_arr}")print()'''
原始数组: [3, 6, 8, 10, 1, 2, 1]
排序结果: [1, 1, 2, 3, 6, 8, 10]原始数组: [10, 7, 8, 9, 1, 5]
排序结果: [1, 5, 7, 8, 9, 10]原始数组: []
排序结果: []原始数组: [1]
排序结果: [1]原始数组: [5, 4, 3, 2, 1]
排序结果: [1, 2, 3, 4, 5]原始数组: [1, 2, 3, 4, 5]
排序结果: [1, 2, 3, 4, 5]原始数组: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
排序结果: [1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9]
'''