题目描述
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
解题思路
方法1:暴力法
方法2:双指针法
方法3:递归法
暴力法参考代码
/**
* 暴力法
*
* 申请一个动态扩容的数组或者容器,比如 ArrayList 这样的。
* 然后不断遍历链表,将链表中的元素添加到这个容器中。
* 再利用容器自身的 API,反转整个容器,这样就达到反转的效果了。
* 最后同时遍历容器和链表,将链表中的值改为容器中的值。
* @param head
* @return
*/
public static ListNode reverseListByViolent(ListNode head) {
ListNode res = head;
List<Integer> list = new ArrayList<>();
while (head != null) {
list.add(head.val);
head = head.next;
}
Collections.reverse(list);
// 从第一个开始
ListNode tmp = res;
for (Integer integer : list) {
tmp.val = integer;
tmp = tmp.next;
}
return res;
}
双指针法参考代码
/**
* 迭代双指针法
*
* 申请两个指针,第一个指针叫 cur,最初是指向 null 的。
* 第二个指针 pre 指向 head,然后不断遍历 pre。
* 每次迭代到 pre,都将 pre 的 next 指向 cur,然后 pre 和 cur 前进一位。
* 都迭代完了(pre 变成 null 了),cur 就是最后一个节点了。
* @param head
* @return
*/
public static ListNode reverseList(ListNode head) {
// 虚节点,模拟反转后的链表的最后一个元素的next
ListNode cur = null;
// 头元素
ListNode pre = head;
while (pre != null) {
// 存pre的下一个节点
ListNode tmp = pre.next;
// pre的下一个节点反转
pre.next = cur;
// cur和pre各自往前走一步
cur = pre;
pre = tmp;
}
return cur;
}
递归法参考代码
/**
* 递归法
* @param head
* @return
*/
public static ListNode reverseListByRecur(ListNode head) {
// 递归结束条件
// head = null : 链表里没有元素
// head.next = null :走到了尽头
if (head == null || head.next == null) {
return head;
}
// 递归结束时,cur=5,head=4.
ListNode cur = reverseListByRecur(head.next);
// 原来:head.next.next=null
// 现在:head.next.next = head等价于4.next.next=4等价于5.next=4
// 实现两个元素指向反转,相当于一个反向的指针
head.next.next = head;
// 防止链表循环:因为cur=5,5的next已经反向指向4了,实现了反转,这里head.next就不需要了
head.next = null;
return cur;
}