定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
定义节点类
public class ListNode {
int val;
ListNode next;// 下一个链表对象
ListNode(int x) { val = x; } //赋值链表的值
}
第一种利用外部空间,申请一个动态扩容的数组或者容器,比如 ArrayList ,栈,都可以,遍历两次
public ListNode reverseList(ListNode head) {
if(head==null||head.next==null){
return head;
}
List<ListNode> list=new ArrayList<ListNode>();
while(head!=null){
list.add(head);//迭代链表,把node赋值给list
head=head.next;//替换当前节点为下一个节点
}
int index=list.size()-1;
ListNode next=null;
ListNode node=list.get(index);//给当前节点赋值
ListNode newHead=node;//给链表节点赋值
for(int i=index-1;i>=0;i--){
next=list.get(i);//给下一个节点赋值
node.next=next;//给当前节点的内的下一个节点赋值
node=node.next;//替换当前节点为下一个节点
}
node.next=null;//最后一个结点就是反转前的头结点,一定要让他的next等于空,否则会构成环
return newHead;
}
执行用时:1 ms, 在所有 Java 提交中击败了8.32%的用户
内存消耗:38.3 MB, 在所有 Java 提交中击败了94.09%的用户
第二种利用双链表迭代方式,
public ListNode reverseList(ListNode head) {
ListNode newHead = null, next = null;//新链表
while(head != null) {
next = head.next;//下一个节点
head.next = newHead;//每次访问的原链表节点都会成为新链表的头结点
newHead = head;//更新新链表
head = next;//重新赋值,继续访问
}
return newHead;
}
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.5 MB, 在所有 Java 提交中击败了75.06%的用户
第三种递归调用是要从当前节点的下一个结点开始递归。逻辑处理这块是要把当前节点挂到递归之后的链表的末尾
public ListNode reverseList3(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode next = head.next; //保存当前节点的下一个结点
ListNode reverse = reverseList(next); //从当前节点的下一个结点开始递归调用
next.next = head; //reverse是反转之后的链表,head挂到next节点的后面就完成了链表的反转。
head.next = null;//这里head相当于变成了尾结点,尾结点都是为空的,否则会构成环
return reverse;
}
执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
内存消耗:38.8 MB, 在所有 Java 提交中击败了34.76%的用户