前言
工作之后每天都是CRUD,CRUD多了脑袋也跟着生锈,为了拯救一下自个贫瘠的脑瓜子,也为了以后的大厂梦,决定每日从牛客网上找个题目来练练手,刚开始先挑个简单的来提升一下自信心。
正文
反转链表是牛客网中上周最热且比较简单题目,就它了,开搞。
题目描述
反转链表:传入一个链表的表头,反转链表后返回新链表的表头。
链表节点结构如下:
class ListNode{
Object value;
ListNode next;
public ListNode(Object value){
this.value = value;
}
}
输入样例
{1,2,3}
输出样例
{3,2,1}
分析
题目很简单,用我们大脑思考就是遍历每一个节点将当前节点的next指向它的上一个节点即可。
用代码处理的话我们需要注意的是防止把当前节点的next指向它前一个后会丢失对它原next引用的问题。
此时我们就需要引入一些辅助变量帮我们记录前一个节点、当前节点、下一个节点。伪代码如下:
// head是出入的链表头
// 初始用头节点做上一个节点
ListNode preNode = head;
// 头节点的下一个节点为当前节点
ListNode currentNode = preNode.next;
// 当前节点的下一个节点做下一个节点
ListNode nextNode = currentNode.next;
// 初始时候直接将当前节点的下一个指向它的前一个节点,接下来遍历链表从next节点开始
currentNode.next = preNode;
// 一定要把头节点的下一个指针指向null,因为原本head.next指向currentNode,上一步又相当于把currentNode.next = head。如果不把head.next置为null会出现head和currentNode的循环指向了。
head.next = null;
接下来我们分析遍历时我们需要做什么事情:
1、将currenNode和nextNode的链接关系反转
2、将nextNode赋值给currentNode,将nextNode.next赋值给nextNode
代码实现如下:
while (nextNode!=null){
// 辅助变量,防止nextNode.next的引用丢失
ListNode newNext = nextNode.next;
// 反转currentNode和nextNode的链接关系
nextNode.next = currentNode;
// 重置currentNode
currentNode = nextNode;
// 重置nextNode
nextNode = newNext;
}
至此核心代码已经完成,但是还需要注意一点就是如果head的长度为0和1时需要做以下特殊处理,不然容易出现空指针异常。
完整代码如下:
public static ListNode reverseList(ListNode head){
// 当传入的链表为空就返回null
if(head==null){
return null;
}
ListNode preNode = head;
ListNode currentNode = preNode.next;
// 如果链表只有一个元素,怎么反转都还是这个元素,直接返回即可
if(currentNode==null){
return head;
}
ListNode nextNode = currentNode.next;
// 初始时候直接将当前节点的下一个指向它的前一个节点,接下来遍历链表从next节点开始
currentNode.next = preNode;
// 一定要把头节点的下一个指针指向null,因为原本head.next指向currentNode,上一步又相当于把currentNode.next = head。如果不把head.next置为null会出现head和currentNode的循环指向了。
head.next = null;
while (nextNode!=null){
// 辅助变量,防止nextNode.next的引用丢失
ListNode newNext = nextNode.next;
// 反转currentNode和nextNode的链接关系
nextNode.next = currentNode;
// 重置currentNode
currentNode = nextNode;
// 重置nextNode
nextNode = newNext;
}
return currentNode;
}