代码随想录算法训练营第三天| 203.移除链表元素、707.设计链表、206.反转链表

93 阅读4分钟

203.移除链表元素

题目链接

leetcode.cn/problems/re…

文章链接

programmercarl.com/0203.%E7%A7…

视频链接

www.bilibili.com/video/BV18B…

看到题目的第一想法

这道题我的第一想法有一个疑问,如果删除的是头结点怎么办,这个我不知道怎么解。

看完代码随想录之后的想法

看完卡哥的视频我发现可以在链表前面加一个虚拟头结点,这样就完美地解决了“如果删除的是头结点”这样一个问题,到时候直接返回虚拟头结点的下一个节点就可以了,完美地解决了我的问题。下面附上我的go语言代码。

func removeElements(head *ListNode, val int) *ListNode {
    dummyHead := new(ListNode)
    cursor := dummyHead
    cursor.Next = head
    for cursor.Next != nil {
        if cursor.Next.Val == val {
            cursor.Next = cursor.Next.Next
        } else {
            cursor = cursor.Next
        }
    }
    return dummyHead.Next
}

实现过程中遇到的困难

这道题不算难,但是写的时候也有一些细节问题,比如我搞忘了go语言怎么定义链表了,还专门去百度了一下。另外,定义的虚拟头结点dummyHead不能直接拿来进行后面的操作,必须写一句cursor := dummyHead来进行一个转换,不然就将整个链表全改了,我最开始直接用dummyHead来进行操作,最后结果始终为空。一定要记住最后返回的是dummyHead.Next,因为头结点可能被删了,所以返回head不完全对。

今日收获

今天学到了虚拟头结点的方式来解决链表问题,对于处理头结点的问题很关键。

707.设计链表

题目链接

leetcode.cn/problems/de…

文章链接

programmercarl.com/0707.%E8%AE…

视频链接

www.bilibili.com/video/BV1FU…

看到题目的第一想法

这道题看到的时候比较头疼,再加上我也在实习,时间比较紧,所以等到周末再来做这道题。

看完代码随想录之后的想法

卡哥在视频里也运用了虚拟头结点的方式来解题,还讲到了一系列细节问题,这道题周末做了再来好好总结。下面附上官方代码,官网的代码还有单向链表和双向链表的版本。 单向链表:

type MyLinkedList struct {
    head *ListNode
    size int
}

func Constructor() MyLinkedList {
    return MyLinkedList{&ListNode{}, 0}
}

func (l *MyLinkedList) Get(index int) int {
    if index < 0 || index >= l.size {
        return -1
    }
    cur := l.head
    for i := 0; i <= index; i++ {
        cur = cur.Next
    }
    return cur.Val
}

func (l *MyLinkedList) AddAtHead(val int) {
    l.AddAtIndex(0, val)
}

func (l *MyLinkedList) AddAtTail(val int) {
    l.AddAtIndex(l.size, val)
}

func (l *MyLinkedList) AddAtIndex(index, val int) {
    if index > l.size {
        return
    }
    index = max(index, 0)
    l.size++
    pred := l.head
    for i := 0; i < index; i++ {
        pred = pred.Next
    }
    toAdd := &ListNode{val, pred.Next}
    pred.Next = toAdd
}

func (l *MyLinkedList) DeleteAtIndex(index int) {
    if index < 0 || index >= l.size {
        return
    }
    l.size--
    pred := l.head
    for i := 0; i < index; i++ {
        pred = pred.Next
    }
    pred.Next = pred.Next.Next
}

func max(a, b int) int {
    if b > a {
        return b
    }
    return a
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/design-linked-list/solution/she-ji-lian-biao-by-leetcode-solution-abix/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

双向链表:

type node struct {
    val        int
    next, prev *node
}

type MyLinkedList struct {
    head, tail *node
    size       int
}

func Constructor() MyLinkedList {
    head := &node{}
    tail := &node{}
    head.next = tail
    tail.prev = head
    return MyLinkedList{head, tail, 0}
}

func (l *MyLinkedList) Get(index int) int {
    if index < 0 || index >= l.size {
        return -1
    }
    var curr *node
    if index+1 < l.size-index {
        curr = l.head
        for i := 0; i <= index; i++ {
            curr = curr.next
        }
    } else {
        curr = l.tail
        for i := 0; i < l.size-index; i++ {
            curr = curr.prev
        }
    }
    return curr.val
}

func (l *MyLinkedList) AddAtHead(val int) {
    l.AddAtIndex(0, val)
}

func (l *MyLinkedList) AddAtTail(val int) {
    l.AddAtIndex(l.size, val)
}

func (l *MyLinkedList) AddAtIndex(index, val int) {
    if index > l.size {
        return
    }
    index = max(0, index)
    var pred, succ *node
    if index < l.size-index {
        pred = l.head
        for i := 0; i < index; i++ {
            pred = pred.next
        }
        succ = pred.next
    } else {
        succ = l.tail
        for i := 0; i < l.size-index; i++ {
            succ = succ.prev
        }
        pred = succ.prev
    }
    l.size++
    toAdd := &node{val, succ, pred}
    pred.next = toAdd
    succ.prev = toAdd
}

func (l *MyLinkedList) DeleteAtIndex(index int) {
    if index < 0 || index >= l.size {
        return
    }
    var pred, succ *node
    if index < l.size-index {
        pred = l.head
        for i := 0; i < index; i++ {
            pred = pred.next
        }
        succ = pred.next.next
    } else {
        succ = l.tail
        for i := 0; i < l.size-index-1; i++ {
            succ = succ.prev
        }
        pred = succ.prev.prev
    }
    l.size--
    pred.next = succ
    succ.prev = pred
}

func max(a, b int) int {
    if b > a {
        return b
    }
    return a
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/design-linked-list/solution/she-ji-lian-biao-by-leetcode-solution-abix/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

实现过程中遇到的困难

做了再写吧!

今日收获

有点懵!

206.反转链表

题目链接

leetcode.cn/problems/re…

文章链接

programmercarl.com/0206.%E7%BF…

视频链接

www.bilibili.com/video/BV1nB…

看到题目的第一想法

这道题的第一想法就是有一个问题我不知道怎么解决。举个例子,假设链表1->2->3,反转链表则是1<-2<-3,当只改变了一个箭头的方向时,那么会变成1<-2->3,这是不允许的,2这个元素有两个next,这是不允许的,我就卡在了这个问题上。

看完代码随想录之后的想法

看完卡哥的视频后,我发现我多虑了,用双指针来解这道题,根本不存在这个问题,因为我第一想法的那个疑惑之处只是链表操作的其中一步,箭头会陆续反过来的,最重要的是返回的要是全部反转完的链表。这道题用双指针法恰到好处。两个指针,一个pre,一个cur,pre先定义为空结点,cur指向head,先把cur.Next给保存下来,接下来的一步很重要,cur.Next = pre,这样的话下一步才能将cur移动到cur.Next,于是pre = cur,最后再把保存的元素赋给cur。下面是我写的go语言代码:

func reverseList(head *ListNode) *ListNode {
    var pre *ListNode
    cur := head
    for cur != nil {
        temp := cur.Next
        cur.Next = pre
        pre = cur
        cur = temp
    }
    return pre
}

实现过程中遇到的困难

困难在上一个章节已经讲到了。

今日收获

再一次巩固了双指针法。