[Go版]算法通关村第二关黄金——K个一组反转链表

目录

  • 题目:K个一组反转链表
    • 方法一:穿针引线法
      • 思路分析
      • 复杂度:时间复杂度: O ( n ) O(n) O(n)、空间复杂度: O ( 1 ) O(1) O(1)
      • Go代码
    • 方法一:头插法
      • 思路分析
      • 复杂度:时间复杂度: O ( n ) O(n) O(n)、空间复杂度: O ( 1 ) O(1) O(1)
      • Go代码

题目:K个一组反转链表

题目链接:LeetCode-25. K 个一组翻转链表
[Go版]算法通关村第二关黄金——K个一组反转链表_第1张图片

方法一:穿针引线法

思路分析

  1. 先写一个专门反转的函数
  2. 算出当前链表长度,再算出需要反转几组:length/k
  3. 设置一个虚拟头结点指向该链表head
  4. 始终找到每段要反转的pre、next,把每段反转完之后连上pre、next即可,所以每轮反转要变动的就是pre
  5. 解释下pre、next、tmp的关系:tmp是要反转链表的头节点,pre.Next=tmp,要反转链表的尾节点.Next=next
  6. 反转方式说明:使用递归的方法,在每个循环中,将子链表的首尾节点通过递归进行反转。

复杂度:时间复杂度: O ( n ) O(n) O(n)、空间复杂度: O ( 1 ) O(1) O(1)

  • 时间复杂度: O ( n ) O(n) O(n)

首先,该函数中使用了一个循环来计算链表的长度,遍历一次链表,时间复杂度是 O ( n ) O(n) O(n),其中 n 是链表的长度。
然后,根据 k 值计算需要反转的次数 times,计算时间复杂度是 O ( 1 ) O(1) O(1)
在循环中,每次反转长度为 k 的一段链表。在最坏情况下,需要遍历整个链表,每次反转 k 个节点。对于长度为 k 的反转操作,时间复杂度是 O ( k ) O(k) O(k)。因为 k 是一个常量,所以整体的时间复杂度是 O ( n ) O(n) O(n),其中 n 是链表的长度。
综上所述,reverseKGroup 函数的总时间复杂度是 O ( n ) O(n) O(n)

  • 空间复杂度: O ( 1 ) O(1) O(1)

该函数中使用了常量级别的额外空间来存储变量和常数,所以空间复杂度是 O ( 1 ) O(1) O(1)

Go代码

type ListNode struct {
	Val int
	Next *ListNode
}
func reverseList(head *ListNode) *ListNode {
    if head == nil || head.Next == nil {
        return head
    }
    tmp:=head
    newList := reverseList(tmp.Next)
    tmp.Next.Next = tmp
    tmp.Next = nil
    return newList
}
func reverseKGroup(head *ListNode, k int) *ListNode {
    if head == nil || head.Next == nil {
        return head
    }
    length := 0
    tmp := head
    // 得到链表的长度
    for tmp != nil {
        length++
        tmp = tmp.Next
    }
    dummyHead := &ListNode{}
    dummyHead.Next = head
    pre := dummyHead
    tmp = head
    // 算出要反转的次数
    times := length/k
    for i:=0; i<times; i++ {
        // tmp走到k的位置(反转末尾)
        for j:=1;j<k;j++ {
            tmp = tmp.Next
        }
        // 保存下一个节点(下一次反转的开头)
        next := tmp.Next
        tmp.Next = nil
        beforeNext := pre.Next
        pre.Next = reverseList(beforeNext)
        beforeNext.Next = next

        pre=beforeNext
        tmp=next
    }
    return dummyHead.Next
}

方法一:头插法

思路分析

  1. 用虚拟头结点指向head
  2. 算出链表长度,再算出有多少个要反转的组:length/k
  3. tmp=head,从表头开始,做k-1次的下一个元素移动到比表头的反转。然后将tmp指向下一段的“表头”,重复该步骤length/k 次
  4. 解释下pre、tmp的关系:tmp是要反转链表的头节点,pre.Next=tmp
  5. 反转方式说明:使用迭代的方法,在每个循环中,将后续的 k-1 个节点一个个地从原位置取出,然后将其插入到 pre 节点之后,从而实现链表的反转

复杂度:时间复杂度: O ( n ) O(n) O(n)、空间复杂度: O ( 1 ) O(1) O(1)

Go代码

type ListNode struct {
	Val int
	Next *ListNode
}
func reverseKGroup(head *ListNode, k int) *ListNode {
    if head == nil || head.Next == nil {
        return head
    }
    dummyHead := &ListNode{}
    dummyHead.Next = head
    pre := dummyHead
    tmp := head
    length := 0
    count := 0
    for tmp != nil {
        length++
        tmp = tmp.Next
    }
    times := length/k
    tmp = head
    for i:=1;i<=times;i++ {
        for count < k-1 {
            next:= tmp.Next
            tmp.Next = tmp.Next.Next
            next.Next = pre.Next
            pre.Next = next
            count++
        }
        count = 0
        pre = tmp
        tmp = tmp.Next
    }
    return dummyHead.Next
}

你可能感兴趣的:(算法与数据结构,golang,算法,链表)