排序链表
- https://leetcode.cn/problems/sort-list/
描述
- 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
示例 1
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3
输入:head = []
输出:[]
提示
- 链表中节点的数目在范围 [0, 5 * 10410^4104] 内
- -10510^5105 <= Node.val <= 10510^5105
进阶
- 你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
Typescript 版算法实现
1 )方案 1
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function sortList(head: ListNode | null): ListNode | null {
const map = new Map()
while(head) {
map.set(head.val, head) // 存储键值对
const next = head.next
if (!next) break
head = next // 当前指向next
}
if (!map.size) return head
// 基于map来存储
const sortList:number[] = []
map.forEach((v, k)=>{
sortList.push(k)
})
// 对sortList进行排序 默认升序
sortList.sort()
// 对数组进行处理
let first:ListNode | null = new ListNode()
for(let i = 0, len = sortList.length; i < len; i ++) {
const v = sortList[i]
const current:ListNode | null = map.get(v) || null
if (!i) first = current
if (!current || !sortList.length) break;
current.next = map.get(sortList[i + 1]) || null;
}
return first
};
- 解题思路
- 使用map和数组的结构来存储
- 将链表的val作为map的键,当前节点作为值
- 将map的所有val存入数组,对数组进行排序
- 循环读取排序后的数组元素,将元素作为map的key来读取对应节点
- 逐个将当前节点的next指向到下一个节点
- 关于时间复杂度
- 此算法最耗时的应该是 Array.prototype.sort() 这个api了
- 这个内部实现都是基于浏览器来决定的,一般是 O(nlogn)
- 所以,这个算法的时间复杂度是 O(nlogn)
- 这种适应场景有限,针对示例上的用例是可以过的
- 如果遇到重复的,使用map的数据结构,就会无法处理
- 所以,此种方案仅适用于开阔下思路,因此不推荐使用
- 这是反面教材
2 )方案 2
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function sortList(head: ListNode | null): ListNode | null {
let arr: ListNode[] = [];
let current: ListNode = head;
while (current) {
arr.push(current);
current = current.next;
}
arr = arr.sort((a, b) => a.val - b.val);
if (!arr.length) return head
head = arr[0];
let c: ListNode = head;
for (let i = 1; i < arr.length; i++) {
c.next = arr[i];
c = arr[i];
}
arr[arr.length - 1].next = null;
return head;
};
- 这个示例程序是官方提供的,我这边稍微进行了一下改动优化
- 这个程序明显比方案1简洁不少,相比方案1而言,方案1处理显得冗余并且出错了
- 直接使用数组来存储节点,对节点的排序基于val属性进行排序
- 之后再对排好序的节点进行遍历来寻找后继
- 此方案推荐,时间复杂度和方案一一致
Python3 版算法实现
1 )方案1
# 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: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head
# 使用字典来存储节点值作为键,节点对象作为值
node_map = {}
current = head
while current:
node_map[current.val] = current
current = current.next
# 从字典的键中获取一个列表,并对其进行排序
sorted_vals = sorted(node_map.keys())
# 创建一个哑节点作为排序后链表的头部
dummy = ListNode(0)
prev_node = dummy # 用来跟踪当前正在处理的节点的前一个节点
# 根据排序后的值数组来重建链表
for val in sorted_vals:
prev_node.next = node_map[val]
prev_node = prev_node.next
prev_node.next = None # 将当前节点的next指针设置为None,防止循环引用
# 返回排序后链表的头部(跳过哑节点)
return dummy.next
- 同ts版本是反面教材
- 处理不了重复的场景
- 仅供参考
2 )方案2
# 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: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head
# 将链表元素转换为列表
arr = []
current = head
while current:
arr.append(current)
current = current.next
# 对列表进行排序
arr.sort(key=lambda x: x.val)
# 将排序后的列表重新构建为链表
if not arr:
return head
head = arr[0]
c = head
for i in range(1, len(arr)):
c.next = arr[i]
c = arr[i]
# 将最后一个节点的next设为None
arr[-1].next = None
return head
Golang 版算法实现
1 )方案1
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func sortList(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
// Use a map to store the values as keys and node pointers as values.
nodeMap := make(map[int]*ListNode)
current := head
for current != nil {
nodeMap[current.Val] = current
current = current.Next
}
// Get a slice of the keys and sort them.
sortedVals := make([]int, 0, len(nodeMap))
for val := range nodeMap {
sortedVals = append(sortedVals, val)
}
sort.Ints(sortedVals)
// Create a dummy node to be the head of the sorted list.
dummy := &ListNode{}
prevNode := dummy
// Rebuild the list based on the sorted values.
for _, val := range sortedVals {
prevNode.Next = nodeMap[val]
prevNode = prevNode.Next
prevNode.Next = nil // Set the next pointer to nil to avoid circular references.
}
// Return the head of the sorted list (skipping the dummy node).
return dummy.Next
}
- 同ts版本是反面教材
- 处理不了重复的场景
- 仅供参考
2 )方案2
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func sortList(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
// 链表转换为切片
nodes := make([]*ListNode, 0)
current := head
for current != nil {
nodes = append(nodes, current)
current = current.Next
}
// 对切片进行排序 这里,leetcode 上不用 import
sort.Slice(nodes, func(i, j int) bool {
return nodes[i].Val < nodes[j].Val
})
// 重新构建链表
if len(nodes) == 0 {
return nil
}
head = nodes[0]
current = head
for i := 1; i < len(nodes); i++ {
current.Next = nodes[i]
current = current.Next
}
current.Next = nil // 设置最后一个节点的 Next 为 nil
return head
}
3 )方案3
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func sortList(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}
// 使用切片来存储节点值,并对其进行排序
var vals []int
current := head
for current != nil {
vals = append(vals, current.Val)
current = current.Next
}
// 对切片进行排序
sort.Ints(vals)
// 创建一个哑节点作为排序后链表的头部
dummy := &ListNode{}
prevNode := dummy
// 根据排序后的值切片来重建链表
for _, val := range vals {
prevNode.Next = &ListNode{Val: val}
prevNode = prevNode.Next
}
// 返回排序后链表的头部(跳过哑节点)
return dummy.Next
}
- 这个是方案2 的优化版本
7万+



被折叠的 条评论
为什么被折叠?



