在做这道题之前,先来看一个 206.翻转链表 的题做下铺垫。

解析:

使用迭代法来遍历链表。下图展示了整个链表翻转的详细过程。基本思想就是:在遍历链表时,将当前节点 curr 的 next 指针改为指向前一个节点。由于节点没有引用其前一个节点,因此必须提前存储其前一个节点,又因为首节点前没有节点,所以要设置虚拟头节点 dummy 。在更改引用之前,还需要存储后一个节点 nextNode 。最后返回新的头节点 dummy 即可。

简单来讲四步:

步骤1:保存 curr 的下一个节点,即 nextNode := curr.Next

步骤2:curr 的下一个节点指向 dummy 虚拟头节点,即 curr.Next = dummy

步骤3:dummy 指向下一个节点,也就是当前 curr 的位置,即 dummy = curr

步骤4:curr 指向下一个节点,也就是步骤 1 中保存的节点,即 curr = nextNode

代码:

type ListNode struct {
    Val int
    Next *ListNode
}

func reverseList(head *ListNode) *ListNode {
    var dummy *ListNode
    curr := head
    for curr != nil {
        nextNode := curr.Next
        curr.Next = dummy
        dummy = curr
        curr = nextNode
    }
    return dummy
}

复杂度分析:

时间复杂度:O(n),其中 n 是链表的长度。

空间复杂度:O(1)。

解决了翻转整个链表,接下来再来看翻转 K 个一组链表。

解析:

将链表节点按照 k 个一组进行分组,所以可以使用一个 head 依次指向每组的头节点。这个指针每次向前移动 k 步,直至链表结尾。对于每个分组,判断它的长度是否大于等于 k 。若是,就翻转这部分子链表,否则bu’x将链表节点按照 k 个一组进行分组,所以可以使用一个 head 依次指向每组的头节点。这个指针每次向前移动 k 步,直至链表结尾。对于每个分组,判断它的长度是否大于等于 k 。若是,就翻转这部分子链表,否则不需要翻转。

翻转一个子链表的问题就回到了上面的力扣 206.反转链表。但是不同的是,在 206.反转链表中输入和返回的都是链表的头节点,这里做子链表翻转不仅需要传入链表头节点,还要传入链表尾节点,返回同样也包括头节点和尾节点。

将翻转后的子链表的头节点与上一个子链表尾节点链接,以及子链表的尾节点与下一个子链表连接。

type ListNode struct {
    Val int
    Next *ListNode
}

func reverseKGroup(head *ListNode, k int) *ListNode {
    dummyNode := &ListNode{Next: head}
    dummy := dummyNode
    for head != nil {
        tail := dummy
        for i := 0; i < k; i++ {
            tail = tail.Next
            if tail == nil {
		return dummyNode.Next
	    }
	}
        // 保存当前子链表的尾节点的Next
	nextNode := tail.Next
        // 翻转子链表
	head, tail = reverse(head, tail)
        // 连接翻转后的子链表,虚拟头节点的Next为翻转后的head,tail的Next为 nextNode
	dummy.Next = head
	tail.Next = nextNode
        // 下一个子链表
	dummy = tail       //下一个子链表的虚拟头节点是上一个子链表的尾节点
	head = tail.Next   //下一个子链表的头节点是上一个子链表的尾节点的Next
    }
    return dummyNode.Next
}

// 翻转子链表
func reverse(head, tail *ListNode) (*ListNode, *ListNode) {
    prev := tail.Next
    curr := head
    for prev != tail {
        next := curr.Next
	curr.Next = prev
	prev = curr
	curr = next
    }
    return tail, head
}

复杂度分析:

时间复杂度:O(n),其中 n 是链表的长度。

空间复杂度:O(1)。

Categories:

Tags:

No responses yet

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注