4.4 反转链表
...大约 5 分钟
4.4.1 问题24: 反转链表
给定单链表的头节点
head,请反转链表,并返回反转后的链表的头节点。示例 1:
img 输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2:
img 输入:head = [1,2] 输出:[2,1]示例 3:
输入:head = [] 输出:[]提示:
- 链表中节点的数目范围是
 [0, 5000]-5000 <= Node.val <= 5000**进阶:**链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
4.4.1.1 分析
反转一个节点, 需要三个指针:
- 当前节点
 - 前一个节点
 - 后一个节点
 
4.4.1.2 题解
func reverseList(head *ListNode) *ListNode {
	var prev *ListNode
	cur := head
	for cur != nil {
		next := cur.Next
		// 反转
		cur.Next = prev
		// 更新
		prev = cur
		cur = next
	}
	return prev
}
4.4.2 问题25: 链表中的数字相加
给定两个 非空链表
l1和l2来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。可以假设除了数字 0 之外,这两个数字都不会以零开头。
示例1:
img 输入:l1 = [7,2,4,3], l2 = [5,6,4] 输出:[7,8,0,7]示例2:
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[8,0,7]示例3:
输入:l1 = [0], l2 = [0] 输出:[0]提示:
- 链表的长度范围为
 [1, 100]0 <= node.val <= 9- 输入数据保证链表代表的数字无前导 0
 
4.4.2.1 分析
如果直接将链表数字转换成整型, 那么可能会溢出, 此时无法计算.
按照十进制的计算规则, 数位对齐后从个位开始计算. 那么需要先将链表反转, 然后从首位开始计算.
4.4.2.2 题解
func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode {
	// 反转链表
	rl1 := reverseList25(l1)
	rl2 := reverseList25(l2)
	// 按位计算
	res := addList(rl1, rl2)
	return reverseList25(res)
}
func reverseList25(head *ListNode) *ListNode {
	var prev *ListNode
	cur := head
	for cur != nil {
		next := cur.Next
		cur.Next = prev
		prev = cur
		cur = next
	}
	return prev
}
func addList(l1, l2 *ListNode) *ListNode {
	dummy := &ListNode{}
	carry := 0 // 进位
	node := dummy
	for l1 != nil || l2 != nil {
		sum := 0
		sum += getVal(l1) + getVal(l2) + carry
		if sum >= 10 {
			carry = 1
		} else {
			carry = 0
		}
		// 记录结果
		v := sum % 10
		node.Next = &ListNode{Val: v}
		node = node.Next
		if l1 != nil {
			l1 = l1.Next
		}
		if l2 != nil {
			l2 = l2.Next
		}
	}
	if carry == 1 {
		node.Next = &ListNode{Val: 1}
	}
	return dummy.Next
}
func getVal(node *ListNode) int {
	if node == nil {
		return 0
	}
	return node.Val
}
4.4.3 问题26: 重排链表
给定一个单链表
L的头节点head,单链表L表示为:
L0 → L1 → … → Ln-1 → Ln请将其重新排列后变为:L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
img 输入: head = [1,2,3,4] 输出: [1,4,2,3]示例 2:
img 输入: head = [1,2,3,4,5] 输出: [1,5,2,4,3]提示:
- 链表的长度范围为
 [1, 5 * 104]1 <= node.val <= 1000
4.4.3.1 分析
问题实际上是将链表分为前后两半, 和 ;
链表长度为:
- 偶数时, 长度相同
 - 奇数时, 比 多一个元素
 
然后将 反转后插入 中.
将链表拆分成两半, 使用快慢指针来寻找中间节点:
- 快指针每次移动两个节点
 - 慢指针每次移动一个节点
 
当快指针到达尾节点时, 慢指针在链表的中间节点.
4.4.3.2 题解
func reorderList(head *ListNode) {
	// 快慢指针, 寻找中间节点
	slow, fast := head, head
	for fast != nil && fast.Next != nil {
		slow = slow.Next
		fast = fast.Next
		if fast.Next != nil {
			fast = fast.Next
		}
	}
	// 分离前后半链表
	tmp := slow.Next
	slow.Next = nil
	link(head, reverseList26(tmp))
}
func reverseList26(head *ListNode) *ListNode {
	var prev *ListNode
	cur := head
	for cur != nil {
		next := cur.Next
		cur.Next = prev
		prev = cur
		cur = next
	}
	return prev
}
func link(node1, node2 *ListNode) {
	dummy := &ListNode{}
	
	node := dummy
	for node1 != nil && node2 != nil {
		tmp := node1.Next
		node.Next = node1
		node1.Next = node2
		node = node2
		node1 = tmp
		node2 = node2.Next
	}
	if node1 != nil {
		node.Next = node1
	}
}
4.4.4 问题27: 回文链表
给定一个链表的 头节点
head**,**请判断其是否为回文链表。如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
示例 1:
输入: head = [1,2,3,3,2,1] 输出: true示例 2:
输入: head = [1,2] 输出: false提示:
- 链表 L 的长度范围为
 [1, 105]0 <= node.val <= 9
4.4.4.1 分析
对于回文链表来说, 若将其分为前后两半链表 :
- 链表长度为偶数: 和反转后的 是相同的
 - 链表长度为奇数: 不包含中间节点(去除最后一个节点) 和 的反转是相同的
 
时间复杂度: O(n)
空间复杂度: O(1)
4.4.4.2 题解
func isPalindrome(head *ListNode) bool {
	// 边界条件
	if head == nil || head.Next == nil {
		return true
	}
	dummy := &ListNode{Next: head}
	// 快慢双指针, 寻找中间节点
	slow, fast := dummy, dummy.Next
	for fast != nil && fast.Next != nil {
		slow = slow.Next
		fast = fast.Next.Next
	}
	// 前半部分
	secondHalf := &ListNode{}
	if fast == nil {
		secondHalf = slow.Next
	} else if fast.Next == nil { // 链表长为奇数
		secondHalf = slow.Next.Next
	}
	// 前后分离
	slow.Next = nil
	// 反转后半
	secondHalf = reverseList27(secondHalf)
	// 比较
	return listEqual(head, secondHalf)
}
func reverseList27(head *ListNode) *ListNode {
	var prev *ListNode
	cur := head
	for cur != nil {
		next := cur.Next
		cur.Next = prev
		prev = cur
		cur = next
	}
	return prev
}
func listEqual(head1, head2 *ListNode) bool {
	for head1 != nil && head2 != nil {
		if head1.Val != head2.Val {
			return false
		}
		head1 = head1.Next
		head2 = head2.Next
	}
	return head1 == nil && head2 == nil
}
Reference
 Powered by  Waline  v2.15.2







