反转链表

L206 反转链表

题目描述

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例1:

img

示例2:

img

题解

方法一:迭代

假设链表为 1→2→3→∅,我们想要把它改成 ∅←1←2←3。

我们考虑遍历链表,将每个节点的next指针改为指向前一个节点。但是链表是单向的,当遍历到某个节点时,我们已经没有前一个节点的引用了,所以需要使用一个prev引用来保存当前节点的前一个节点。

然后做以下迭代步骤:

  • 保存curr的next引用
  • 设置当前节点的next指向prev
  • 将prev指向当前节点
  • 将curr指向next
class Solution {
    public ListNode reverseList(ListNode head) {
		ListNode curr = head;
        ListNode prev = null;
        
        while (curr != null) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        
        return prev;
    }
}

复杂度分析

时间复杂度:O(N),遍历一次。

空间复杂度:O(1)

方法二:递归

假设链表为:

n1→…→n**k−1→n**kn**k+1→…→n**m→∅

若从节点 n**k+1 到 n**m 已经被反转,而我们正处于 n**k

n1→…→n**k−1→n**kn**k+1←…←n**m

我们希望 n**k+1 的下一个节点指向 n**k

所以,n**k.next.next=n**k

需要注意的是:

  • next指针的修改
  • 反转后的链表的链尾节点的next应该为null
  • 在递归过程中应该要将反转后的链表头节点返回
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;
    }
}

复杂度分析

时间复杂度:O(N)

空间复杂度:O(N),因为递归占用栈空间

L92 反转链表 II

题目描述

给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表

示例1:

img

输入:head = [1,2,3,4,5], left = 2, right = 4
输出:[1,4,3,2,5]

示例2:

输入:head = [5], left = 1, right = 1
输出:[5]

题解

方法一:一遍扫描

将链表分成三段,反转中间的部分,然后将左中右重新相接。

下载

下载 (1)

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
    	ListNode dummy = new ListNode(0, head);
        
        // 0.整个链表分为左中右三段
        // 1.首先找到左链表的尾部
        ListNode node = dummy;
        for (int i = 1; i < left; i++) {
            node = node.next;
        }
        ListNode leftListTail = node;
        
        // 2.反转中间链表
        node = node.next;
        ListNode midListHead = node;
        ListNode prev = null;
        for (int i = left; i <= right; i++) {
			ListNode next = node.next;
            node.next = prev;
            prev = node;
            node = next;
        }
        
        // 3.重新相接
        leftListTail.next = prev;
        midListHead.next = node;
        
        return dummy.next;
    }
方法二:穿针引线

pre永远指向左链表的最后一个节点。

curr永远指向右链表的第一个节点。

每次迭代:

  • 先将 curr 的下一个节点记录为 next
  • 执行操作 ①:把 curr 的下一个节点指向 next 的下一个节点
  • 执行操作 ②:把 next 的下一个节点指向 pre 的下一个节点
  • 执行操作 ③:把 pre 的下一个节点指向 next

image.png

class Solution {
    public ListNode reverseBetween(ListNode head, int left, int right) {
        // 设置 dummyNode 是这一类问题的一般做法
        ListNode dummyNode = new ListNode(-1);
        dummyNode.next = head;
        ListNode pre = dummyNode;
        for (int i = 0; i < left - 1; i++) {
            pre = pre.next;
        }
        ListNode cur = pre.next;
        ListNode next;
        for (int i = 0; i < right - left; i++) {
            next = cur.next;
            cur.next = next.next;
            next.next = pre.next;
            pre.next = next;
        }
        return dummyNode.next;
    }
}

L25 K个一组反转链表

题目描述

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例1

img

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

示例2

img

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]

题解

方法一:模拟

思路就是先向后遍历k个节点,如果剩余元素个数少于k个,则直接返回;如果大于等于k个,就进行翻转。

反转完成之后,需要重新将它接回原链表。

class Solution {
    public ListNode reverseKGroup(ListNode list, int k) {
    	ListNode dummy = new ListNode(0, list);
        ListNode tail = dummy;
        
        while (true) {
            ListNode curr = tail;
            for (int i = 0; i < k; i++) {
                curr = curr.next;
                if (curr == null) {
					return dummy.next;
                }
            }
            
            ListNode nextKGroupHead = curr.next;
            ListNode currKGroupHead = tail.next;
            ListNode prev = nextKGroupHead;
            curr = tail.next;
          	while (curr != nextKGroupHead) {
                ListNode nxt = curr.next;
                curr.next = prev;
                prev = curr;
                curr = nxt;
            }
            tail.next = prev;
            tail = currKGroupHead;
        }
    }
}
posted @ 2024-07-08 23:19  zhaoqi94  阅读(28)  评论(0)    收藏  举报