链表系列入门指南:类型、操作及解题思路(一)

81 阅读2分钟

前言

链表分成多种,这里总结链表常见操作和链表的类型

单链表

最简单的链表,只有指向下一个链表的指针

结构

 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }

常见操作

遍历

    for node := head;node != nil;node=node.Next {
    }

插入(在第K个位置插入,k的范围是1~n)

func Insert(node *Node){
    cnt := 0
    knode := head
    for ;knode != nil && cnt != k-1;knode=knode.Next { // 取到地k-1个结点 然后插入到它后面
        cnt ++
    }
    node.Next := knode.Next
    knode.Next = node
}

链表题常见思路

快慢双指针遍历链表(判环)

题目:leetcode141 思路:通过快慢指针判断,如果一个快,一个慢,总是会相遇的 代码:

func hasCycle(head *ListNode) bool {
    if head == nil || head.Next == nil {
        return false
    }
    fastPtr := head.Next
    slowPtr := head
    for  {
        if slowPtr == fastPtr {
            return true
        }
        if slowPtr.Next == nil {
            break
        }else if fastPtr.Next == nil || fastPtr.Next.Next == nil {
            break
        }
        slowPtr = slowPtr.Next
        fastPtr = fastPtr.Next.Next
    }
    return false
}

随机链表的复制

题目:leetcode138 middle 思路:一开始思考Random可能会卡住。但其实我们不需要关心老链表的Random之间是怎么映射的。只需要维护新老链表节点的映射关系,就可以将老链表的数据关系无缝迁移了

func copyRandomList(head *Node) *Node {
    mOldNew := make(map[*Node]*Node)
    newHead := &Node{}
    newNode := newHead
    for node:=head;node!=nil;node=node.Next{
        now := &Node{
            Val: node.Val,
        }
        newNode.Next = now
        newNode = now

        mOldNew[node] = now
    }
    for node:=head;node!=nil;node=node.Next{
        mOldNew[node].Random = mOldNew[node.Random]
    }
    return newHead.Next
}

反转链表

题目:leetcode92 思路:既然是区间反转,首先可以拆分成两个步骤:

  1. 先把中间这段反转
  2. 反转后,处理首尾指针关系

中间反转的思路: 当前指针依次指向上一个指针.

先考虑左端点:我们需要关注left前一个节点,即为反转后的链表头,链表头最后一个节点的位置是left-1,由于题目头节点不是虚拟节点,所以我们创造一个虚拟节点,把链表挂载上 考虑右端点:我们需要关注right后一个节点的地址,为反转后的链表尾的第一个节点位置是right+1,就是right.Next,提前保存,然后拼接

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseBetween(head *ListNode, left int, right int) *ListNode {
    //首先l r >=1 
    if left == right{
        return head
    }

    // 逻辑上得到left-1 还有right节点
    // 修改Left - 1节点的指针
    // 修改right节点
    cnt := 0
    h := &ListNode{Next: head}
    leftBeforeNode := h
    rightNode := h
    for node := h; node != nil; node= node.Next{
        
        if cnt == left - 1{
            leftBeforeNode = node
        }
        if cnt == right{
            rightNode = node
            rightNodeNext := rightNode.Next
            leftNode := leftBeforeNode.Next
            reverse(leftBeforeNode.Next, rightNode)
            leftBeforeNode.Next = rightNode
            leftNode.Next = rightNodeNext
            break
        }
        cnt ++
    }
    return h.Next
}

func reverse(st,ed *ListNode){
    var lastNode *ListNode
    edNext := ed.Next
    for node:=st; node!=edNext ;{
        nxt := node.Next
        node.Next = lastNode
        lastNode = node
        node = nxt
    } 
}