剑指 Offer II 024. 反转链表(206. 反转链表)
题目:
思路:
【1】使用辅助空间是我们最容易的想到的处理方式,先遍历一遍存起来,然后反转连起来(但明显不是最优的)。
【2】循环中不使用辅助空间的情况
需要定义两个指针,一个是tem临时存储,一个是pre头部节点的存储,加上本身的head(给予的树头节点) 如树为【5,4,3,2,1】 那么第一次循环head先为5 此时先记录下一个节点tmp = head.next; ,即将将4赋予了tem 此时5被单独了出来,对接上新链条的pre, head.next = pre; pre = head; //此时新链条为【5】 然后head = tmp; 完美承接到下一个节点,可以进行第二次遍历 第二次循环head先为4 此时先记录下一个节点tmp = head.next; ,即将将3赋予了tem 此时4被单独了出来,对接上新链条的pre, head.next = pre; pre = head; //此时新链条为【4,5】,而pre也指向4这个首节点 然后head = tmp; 完美承接到下一个节点,可以进行第二次遍历 ....
【3】递归的方式
代码展示:
递归的方式:
//时间0 ms击败100% //内存41.4 MB击败39.14% //时间复杂度:O(n),其中 n 是链表的长度。需要对链表的每个节点进行反转操作。 //空间复杂度:O(n),其中 n 是链表的长度。空间复杂度主要取决于递归调用的栈空间,最多为 n 层。 class Solution { public ListNode reverseList(ListNode head) { if (head == null || head.next == null) { return head; } ListNode newHead = reverseList(head.next); head.next.next = head; head.next = null; return newHead; } }
使用辅助空间的方式:
//时间1 ms击败4.34% //内存41.2 MB击败68.75% class Solution { public ListNode reverseList(ListNode head) { LinkedList<ListNode> queue = new LinkedList<ListNode>(); ListNode res = new ListNode(-1); while (head != null){ queue.add(head); head = head.next; } ListNode tem = res; while (!queue.isEmpty()){ tem.next = queue.pollLast(); tem = tem.next; //这一步是为了防止形成环,因为如果是链表【5,4,3,2,1】 //在没有清除的时候,4和5的下一个指针相互指向对方会形成环 tem.next = null; } return res.next; } }
循环中不使用辅助空间的情况:
//时间0 ms击败100% //内存41.5 MB击败27.75% /** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode() {} * ListNode(int val) { this.val = val; } * ListNode(int val, ListNode next) { this.val = val; this.next = next; } * } */ class Solution { public ListNode reverseList(ListNode head) { ListNode tmp = null, pre = null; while(head != null) { // 暂存后继节点 cur.next tmp = head.next; // 修改 next 引用指向 head.next = pre; // pre 暂存 cur pre = head; // cur 访问下一节点 head = tmp; } return pre; } }