牛客刷题-go-链表反转、回文

160 阅读1分钟

T1. 反转链表

func ReverseList(pHead *ListNode) *ListNode {
    var pre, cur, next *ListNode
    cur = pHead
    if pHead == nil || pHead.Next == nil {
        return pHead
    }
    for cur != nil {
        next = cur.Next
        cur.Next = pre
        pre = cur
        cur = next
    }
    return pre //返回pre而不是cur

}

T2. 链表内指定区间反转

func reverseBetween( head *ListNode ,  m int ,  n int ) *ListNode {  
    if head == nil || head.Next == nil {  //do not forget!!!
        return head
    }
    var cur,pre,next,left,right,newHead *ListNode
    newHead = &ListNode{-1,head}  //设置newHead,防止从head就开始反转,反转后链表头节点就不为head
    //pre = &ListNode{-1,head}  //pre.Next = head报错?pre都没给,哪来的pre.Next
    pre = newHead  
    for i := 1; i < m; i++ {
        pre = pre.Next
    }
    left = pre
    cur = pre.Next
    for i := m; i <= n; i++ {  //go中没有++i
        next = cur.Next
        cur.Next = pre
        pre = cur
        cur = next
    }
    right = cur
    left.Next.Next = right  //反转部分重新连接
    left.Next = pre
    return newHead.Next  //newHead.Next才是反转后的头节点
}

复习一下指针,p *p &p

T3. 链表中节点每k个一组反转

时间复杂度O(2k+n) 空间复杂度O(1) 思路: 1. 先找反转后头节点 2. 递归反转每个区间并连接 3. 递归结束,返回头节点

func reverseKGroup(head *ListNode, k int) *ListNode {
    if head == nil {
        return head
    }
    newHead := &ListNode{-1, head}
    for count := 1; count < k; count++ { //先找新链表头节点
        head = head.Next
        if head == nil { //不能反转则返回head
            return newHead.Next
        }
    }
    reverse(newHead, k)
    return head
}
func reverse(head *ListNode, k int) int {
    if head == nil || head.Next == nil { //反转终止
        return 0
    }
    var newHead, pre, cur, next *ListNode
    pre = nil
    cur = head.Next
    for count := 1; count <= k; count++ {
        next = cur.Next
        cur.Next = pre
        pre = cur
        cur = next
        if cur == nil && count != k { //节点不足k个,再次反转回来
            cur = pre //不要总把pre cur的位置搞错!!!!
            pre = nil
            for ; count > 0; count-- {
                next = cur.Next
                cur.Next = pre
                pre = cur
                cur = next
            }
            return 0 //反转终止,输出反转后链表
        }
    }
    newHead = head.Next
    head.Next = pre     //前一个区间连到当前区间
    newHead.Next = cur  //当前指向下一个区间
    reverse(newHead, k) //递归
    return 0

}

注意:

1. 每次反转时注意pre cur的位置

2. 递归别忘了给返回值做终止条件

T4. 判断是否回文

链表经常用双指针来找mid。

func isPail(head *ListNode) bool {
    if head == nil || head.Next == nil {
        return true
    }
    fast := &ListNode{-1, head}
    slow := fast
    for fast != nil && fast.Next != nil {
        fast = fast.Next.Next
        slow = slow.Next
    }
    mid := reverse(slow.Next)
    for head != nil && mid != nil {
        if head.Val != mid.Val {
            return false
        }
        head = head.Next
        mid = mid.Next
    }
    return true
}
func reverse(head *ListNode) *ListNode {
    var pre, cur, next *ListNode
    pre = nil
    cur = head
    for cur != nil {
        next = cur.Next
        cur.Next = pre
        pre = cur
        cur = next
    }
    return pre
}