Table of Contents
25-09-19 反转链表、两数之和 25-09-20 两两交换链表中的节点 昨天和今天在准备速写带画教学内容,学习进度放缓… 相关链接:代码随想录 |> 206.反转链表|24. 两两交换链表中的节点|1. 两数之和
206.反转链表
简单
给你单链表的头节点
head,请你反转链表,并返回反转后的链表。示例 1:
![]()
输入:head = [1,2,3,4,5]输出:[5,4,3,2,1]示例 2:
![]()
输入:head = [1,2]输出:[2,1]示例 3:
输入:head = []输出:[]提示:
链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000**进阶:**链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
双指针法
写的时候犯了个小错误,由于基础不牢,不知道怎么直接给 prev nil,然后直接写了 prev := &ListNode{} 再赋值成 nil ,然后这个节点被丢弃掉,等待 GC 回收。多了一次无意义的分配。
应该是: var prev *ListNode
含义:声明了一个指针,初始状态是「空指针」,不指向任何元素。
这证明我对结构体的传递还不熟悉。
大致过程:
prev = nil
cur = head
tmp = cur.Next // tmp 存储下一个节点,防止指针反向后丢失
cur.Next = prev // 指针反向
以上就是一次反向的过程,遍历的条件是
for cur != nil {
}如下图所示:
多次操作后…到达最后一次
当 cur == tail 时是最后一次迭代,接着 cur = nil ,不进循环,tmp 也是 nil。此时 return prev 就是反转后的链表
代码
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */func reverseList(head *ListNode) *ListNode { // prev := &ListNode{} // prev = nil var prev *ListNode cur := head
for cur != nil { tmp := cur.Next // 存储下一个节点/nil cur.Next = prev // 反转指向 // 向后移动 prev = cur cur = tmp } return prev}24. 两两交换链表中的节点
中等
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
![]()
输入:head = [1,2,3,4]输出:[2,1,4,3]示例 2:
输入:head = []输出:[]示例 3:
输入:head = [1]输出:[1]提示:
- 链表中节点的数目在范围
[0, 100]内0 <= Node.val <= 100
虚拟头结点
一定要画图
设一个虚拟头结点指向 head ,然后按照上图的步骤操作。注意这里需要设一个 tmp 存一下节点1。
同时需要注意循环条件。
当链表节点数为偶数时,cur.Next != nil (空链表时也满足);
当链表节点数为奇数时,cur.Next.Next != nil ;
写循环条件时,cur.Next != nil 应该写在 cur.Next.Next != nil 前面,否则可能会操作空指针。
for cur.Next != nil && cur.Next.Next != nil {}完整代码
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */func swapPairs(head *ListNode) *ListNode { DummyHead := &ListNode{Next: head} cur := DummyHead
for cur.Next != nil && cur.Next.Next != nil { tmp := cur.Next cur.Next = tmp.Next tmp.Next = cur.Next.Next cur.Next.Next = tmp
// 移动 cur cur = cur.Next.Next } return DummyHead.Next}