Leetcode-148. Sort List-python

Leetcode-148. Sort List-python

问题描述:

Sort a linked list in O(n log n) time using constant space complexity.
将一个链表排序,限制了时间复杂度和空间复杂度

Example:

Example 1:

Input: 4->2->1->3
Output: 1->2->3->4
Example 2:

Input: -1->5->3->4->0
Output: -1->0->3->4->5

算法(归并排序):

由于限制了时间复杂度为O(nlogn),所以我们归并排序进行求解,将链表分成两部分,每一部分单独进行排序,然后合并起来,将链表平分的方式我们用到快慢指针的方式,快指针走到末尾时,慢指针才到中间。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        if head is None or head.next is None:
            return head
        slow,faster,pre = head,head,head
        while faster and faster.next:
            pre = slow
            slow = slow.next
            faster = faster.next.next
        pre.next = None
        return self.merge(self.sortList(head),self.sortList(slow))
    def merge(self,l1,l2):
        if l1 is None:
            return l2
        if l2 is None:
            return l1
        if l1.val < l2.val:
            l1.next = self.merge(l1.next,l2)
            return l1
        else:
            l2.next = self.merge(l1,l2.next)
            return l2

不过似乎递归并不是静态空间。。。

<think> 我们被要求详细讲解Pythonlist.sort()方法。根据用户提供的引用,我们可以总结出以下关键点: 1. list.sort()是列表的一个方法,用于原地排序(会改变原列表),而内置函数sorted()则返回一个新的排序列表,不改变原列表[^1]。 2. list.sort()方法有两个可选参数:key和reverse[^2][^3][^4]。 - key参数:指定一个函数,该函数用于从每个列表元素中提取比较键。排序将根据这个键进行。 - reverse参数:布尔值,默认为False(升序)。如果设置为True,则降序排序。 3.Python3中,取消了cmp参数,而是通过key参数来实现自定义排序。如果需要比较两个元素,可以使用functools.cmp_to_key将比较函数转换成key函数[^5]。 下面将详细讲解list.sort()方法。 ### 1. 基本用法 ```python list.sort(key=None, reverse=False) ``` - **原地排序**:该方法会对列表进行原地排序,返回None(因此不要赋值给变量)。 - **默认行为**:默认按元素从小到大的升序排列(对于数字就是数值大小,对于字符串是字典序)。 #### 示例1:基本排序 ```python numbers = [3, 1, 4, 1, 5, 9, 2] numbers.sort() print(numbers) # 输出:[1, 1, 2, 3, 4, 5, 9] words = ['banana', 'apple', 'cherry'] words.sort() print(words) # 输出:['apple', 'banana', 'cherry'] ``` ### 2. key参数的使用 key参数用于指定一个函数,该函数将作用于列表的每一个元素,并根据函数的返回值进行排序。 #### 示例2:按字符串长度排序 ```python fruits = ['apple', 'banana', 'cherry', 'date'] fruits.sort(key=len) print(fruits) # 输出:['date', 'apple', 'banana', 'cherry'] # 注意:如果长度相同,则保持原有顺序(稳定排序) ``` #### 示例3:按元素的某个属性排序 ```python # 按元组的第二个元素排序 pairs = [(1, 9), (2, 1), (7, 3), (8, 6)] pairs.sort(key=lambda x: x[1]) print(pairs) # 输出:[(2, 1), (7, 3), (8, 6), (1, 9)][^4] ``` ### 3. reverse参数 reverse参数控制排序顺序,默认False为升序,True为降序。 #### 示例4:降序排序 ```python numbers = [3, 1, 4, 1, 5, 9, 2] numbers.sort(reverse=True) print(numbers) # 输出:[9, 5, 4, 3, 2, 1, 1] ``` ### 4. 复杂排序:使用多个键 有时需要根据多个条件排序,可以在key函数中返回一个元组。元组会按顺序比较(即先比较第一个,相等再比较第二个,以此类推)。 #### 示例5:先按长度,再按字母顺序 ```python fruits = ['apple', 'banana', 'cherry', 'date', 'fig'] fruits.sort(key=lambda x: (len(x), x)) print(fruits) # 输出:['fig', 'date', 'apple', 'banana', 'cherry'] ``` ### 5. 稳定排序 list.sort()是稳定排序,即当两个元素比较相等时,它们在排序结果中的顺序与原始顺序相同。这允许我们通过多次排序来实现多级排序(先按次要条件排,再按主要条件排)。 #### 示例6:稳定排序的多级排序 ```python # 先按成绩降序,再按名字升序 students = [('Alice', 90), ('Bob', 85), ('Charlie', 90), ('Dave', 80)] # 先按次要条件(名字)升序排 students.sort(key=lambda x: x[0]) # 再按主要条件(成绩)降序排(注意:这里降序,所以reverse=True) students.sort(key=lambda x: x[1], reverse=True) print(students) # 输出:[('Alice', 90), ('Charlie', 90), ('Bob', 85), ('Dave', 80)] # 注意:两个90分的,Alice在Charlie之前是因为第一次排序时Alice在Charlie前面(稳定排序保留了第一次排序的相对顺序) ``` ### 6. 比较函数的替代(Python3) 在Python3中,list.sort()不再支持cmp参数。若需要比较两个元素的复杂逻辑,可以使用functools.cmp_to_key将比较函数转换为key函数。 比较函数接受两个参数,返回负数表示第一个参数小于第二个,正数表示大于,0表示相等。 #### 示例7:使用cmp_to_key实现自定义比较 ```python import functools # 重新实现示例3:按元组第二个元素升序 pairs = [(1,9), (2,1), (7,3), (8,6)] def compare(a, b): # 如果a[1] < b[1],返回负数,表示a应该排在b前面 return a[1] - b[1] pairs.sort(key=functools.cmp_to_key(compare)) print(pairs) # 输出:[(2,1), (7,3), (8,6), (1,9)] # 更复杂的比较:拼接成最大数(leetcode179) # 题目要求将非负整数数组重新排列,使之成为最大的数(字符串形式) # 思路:比较两个字符串a,b,看a+b和b+a哪个大 class Solution: def largestNumber(self, nums: List[int]) -> str: res = [str(x) for x in nums] # 自定义比较函数:如果a+b > b+a,则a应该排在b前面(这里要降序,所以返回-1?注意cmp_to_key的规则) # 注意:cmp_to_key要求一个比较函数,接受两个参数a,b,如果a应该排在b前面,则返回负数;如果b应该排在a前面,则返回正数;相等返回0。 # 我们想要的是:如果a+b>b+a,那么a应该排在b前面(即返回负数?因为cmp_to_key要求a<b返回负数,但这里我们定义的是a>b) # 所以可以:return int(b+a) - int(a+b) 这样当b+a>a+b时,返回正数,表示b应该排在a前面,即a排在b后面。而我们要的是a+b大的排在前面,所以这样就是降序。 # 或者:return 1 if a+b < b+a else -1 if a+b > b+a else 0 也可以。 res.sort(key=functools.cmp_to_key(lambda a, b: int(b+a)-int(a+b))) # 或者:res.sort(key=functools.cmp_to_key(lambda a, b: -1 if a+b>b+a else 1)) # 注意:这样排序后,我们得到的是从大到小(因为大的字符串应该放在前面) res = ''.join(res) if res[0]=='0': return '0' return res # 在示例代码中[^5],使用的是:res.sort(reverse=True, key=functools.cmp_to_key(lambda x,y : 1 if x+y > y+x else -1)) # 注意:这里cmp_to_key中的函数返回1表示x>y(即x应该排在y后面?因为cmp_to_key要求:当x>y时返回正数,则排序中x会排在y后面,但这里又设置了reverse=True,所以会反转,变成x排在y前面。所以逻辑正确。 ``` ### 7. 注意事项 - **原地修改**:list.sort()会改变原列表,而sorted()函数不会。 - **仅适用于列表**:list.sort()是列表的方法,而sorted()函数可以接受任何可迭代对象。 - **性能**:list.sort()的时间复杂度是$O(n \log n)$,空间复杂度为$O(n)$(最坏情况,平均$O(\log n)$)。它是Timsort算法,一种混合了归并排序和插入排序的算法。 - **稳定性**:稳定排序,相同键值的元素顺序保持不变。 ### 8. 总结 list.sort()Python中对列表进行原地排序的方法,通过key参数可以自定义排序依据,通过reverse参数可以控制升序或降序。在复杂排序场景中,可以利用稳定排序特性进行多级排序,或使用cmp_to_key实现复杂比较逻辑。 §§相关问题§§ 1. list.sort()sorted()函数有什么区别? 2. 如何实现多级排序(多个条件)? 3.Python中如何实现降序排序? 4. 什么是稳定排序?为什么它在多级排序中很重要? </think> ### Python `list.sort()` 方法详解 `list.sort()` 是 Python 列表的核心排序方法,用于**原地排序**(修改原列表,返回 `None`)。它通过高效的 Timsort 算法实现,支持自定义排序逻辑。以下是详细解析: --- #### 1. 基本语法 ```python list.sort(key=None, reverse=False) ``` - **`key`**(可选):函数类型,为每个元素生成排序依据的键值(默认为 `None`,按元素原始值排序)。 - **`reverse`**(可选):布尔类型,控制排序方向(`False`=升序,`True`=降序)。 --- #### 2. 核心功能与特性 | 特性 | 说明 | |---------------------|----------------------------------------------------------------------| | **原地排序** | 直接修改原列表,返回 `None`(与 `sorted()` 函数不同)[^1] | | **稳定性** | 相等元素的相对顺序保持不变(适用于多级排序)[^3] | | **时间复杂度** | $O(n \log n)$(平均/最坏情况) | | **自定义排序逻辑** | 通过 `key` 和 `reverse` 参数灵活控制排序规则[^2][^3] | --- #### 3. 参数详解 ##### (1) `key` 参数(核心用法) - **作用**:为每个元素生成用于比较的键值。 - **类型**:接受单参数函数(如 `lambda`、内置函数、自定义函数)。 - **原理**: 排序时实际比较的是 `key(elem)` 的返回值,而非元素本身。 ###### 示例 1:按元组第 2 个元素排序 ```python data = [(1, 9), (2, 1), (7, 3), (8, 6)] data.sort(key=lambda x: x[1]) print(data) # 输出:[(2, 1), (7, 3), (8, 6), (1, 9)][^4] ``` ###### 示例 2:按字符串长度排序 ```python words = ["apple", "kiwi", "banana"] words.sort(key=len) print(words) # 输出:['kiwi', 'apple', 'banana'] ``` ##### (2) `reverse` 参数 - `False`(默认):升序(从小到大) - `True`:降序(从大到小) ```python nums = [3, 1, 4, 2] nums.sort(reverse=True) print(nums) # 输出:[4, 3, 2, 1] ``` --- #### 4. 高级用法 ##### (1) 多级排序 利用稳定性实现多条件排序(先按次要条件排,再按主要条件排): ```python students = [("Alice", 90), ("Bob", 85), ("Charlie", 90)] # 先按成绩升序(次要条件) students.sort(key=lambda x: x[1]) # 再按姓名降序(主要条件) students.sort(key=lambda x: x[0], reverse=True) print(students) # 输出:[('Charlie', 90), ('Bob', 85), ('Alice', 90)] ``` ##### (2) 自定义比较函数(Python3) 通过 `functools.cmp_to_key` 将传统比较函数转换为 `key` 函数: ```python import functools def custom_compare(a, b): if a + b > b + a: # 拼接字符串比较(如最大数问题) return 1 return -1 nums = [3, 30, 34, 5, 9] nums.sort(key=functools.cmp_to_key(custom_compare), reverse=True) print("".join(map(str, nums))) # 输出:"9534330"[^5] ``` --- #### 5. 与 `sorted()` 的对比 | 特性 | `list.sort()` | `sorted()` | |--------------------|--------------------------------|--------------------------------| | **返回类型** | `None`(原地修改列表) | 新排序列表(原列表不变) | | **适用对象** | 仅列表 | 任意可迭代对象(列表、元组等) | | **空间复杂度** | $O(1)$ | $O(n)$ | | **性能** | 略快(无新建列表开销) | 略慢 | --- #### 6. 常见错误与注意事项 1. **误用返回值**: ```python # 错误:sort() 返回 None new_list = my_list.sort() # new_list 为 None # 正确:sorted() 返回新列表 new_list = sorted(my_list) ``` 2. **`key` 函数需返回可比较类型**: ```python # 错误:返回不可比较类型(如列表) data.sort(key=lambda x: [x[0], x[1]]) # 可能引发 TypeError # 正确:返回元组(可比较) data.sort(key=lambda x: (x[0], x[1])) ``` 3. **处理复杂对象**: ```python class Student: def __init__(self, name, grade): self.name = name self.grade = grade students = [Student("Alice", 90), Student("Bob", 85)] students.sort(key=lambda s: s.grade) # 按成绩排序 ``` --- #### 7. 实际应用场景 1. **数据清洗与预处理**: ```python # 按日期字符串排序 dates = ["2023-01-15", "2022-12-01", "2023-01-01"] dates.sort(key=lambda d: tuple(map(int, d.split("-")))) ``` 2. **分组统计**: ```python # 按类别分组后排序 products = [("apple", 2.5), ("orange", 1.8), ("apple", 3.0)] products.sort(key=lambda x: x[0]) # 按名称分组 ``` 3. **科学计算**: ```python # 按向量模长排序 vectors = [(1, 2), (3, 1), (2, 2)] vectors.sort(key=lambda v: v[0]**2 + v[1]**2) ``` --- #### 8. 性能优化建议 1. **避免复杂 `key` 函数**:简单函数可减少计算开销 2. **优先使用内置函数**:如 `operator.itemgetter` 比 `lambda` 更快 ```python from operator import itemgetter data.sort(key=itemgetter(1)) # 等效于 key=lambda x: x[1] ``` 3. **对预排序数据使用 `reverse`**:避免重复排序 --- ### 总结 `list.sort()` 是高效的原位排序工具,通过 `key` 和 `reverse` 参数提供强大的自定义能力。掌握其用法可显著提升数据处理效率,尤其适合大型列表排序场景。对于需要保留原列表的场景,应使用 `sorted()` 函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值