青铜挑战——手写链表反转
LeetCode206 给你单链表的头节点 head,请你反转链表,并返回反转后的链表。
示例1:
输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
方法一:直接操作链表实现反转
public ListNode reverseList(ListNode head) {
ListNode prev = null; // prev指针初始化为null
ListNode curr = head; // curr指针初始化为链表的头节点
// 遍历链表
while (curr != null) {
ListNode next = curr.next; // 临时变量next存储当前节点的下一个节点
curr.next = prev; // 将当前节点的next指向前一个节点,实现反转
prev = curr; // prev指针向前移动
curr = next; // curr指针向前移动
}
// 循环完成后,prev将指向反转后的链表头节点
return prev;
}
方法二:建立虚拟头结点辅助反转
首先理解什么是虚拟头节点,这里我们以删除节点为例。
虚拟头结点的作用,可以使原链表的所有节点就都可以按照统一的方式进行移除了。
这样移除了一个头结点,是不是发现,在单链表中移除头结点 和 移除其他节点的操作方式是不一样,其实在写代码的时候也会发现,需要单独写一段逻辑来处理移除头结点的情况。
来看看如何设置一个虚拟头。依然还是在这个链表中,移除元素1。
这里来给链表添加一个虚拟头结点为新的头结点,此时要移除这个旧头结点元素1。
这样是不是就可以使用和移除链表其他节点的方式统一了呢?直接使用Head=Head.next。
现在我们已经理解了虚拟节点的作用,那么对应的反转链表的代码如下:
// 方法1:虚拟结点法
public static ListNode reverseList(ListNode head) {
ListNode dumpyHead = new ListNode(-1); //创建虚拟节点
ListNode cur = head; //指定头节点
while (cur != null) { //遍历
ListNode next = cur.next; //存储下一个节点的连接,防止遍历找不到下一个节点
cur.next = dumpyHead.next; //将下一个节点的连接指向头节点(开始进行反转)
dumpyHead.next = cur; //将虚拟节点的下一个节点指向为头节点,让其成为新的头节点
cur = next; // 将这个节点连接到下一个节点的连接上
}
return dumpyHead.next;
}