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

 

 203. Remove Linked List Elements 

 # 初步思路 - 分类讨论不同删除情况:

1.简单题不简单!一开始我没有使用虚拟头节点,所以删除链表元素就需要考虑以下几种情况:

A:删除的元素是链表的开头,那么就需要不断的遍历head,直到 head.val != val 

B:删除的元素在链表的结尾,cur 指针就要停在倒数第二个元素,写成:while cur.next != None

C: 删除的元素在链表的中间位置,cur指针要遍历到删除元素的前一位:所以还得多弄个prev指针

# 深入思考 - 使用虚拟头节点统一删除:

后来我想了想,为什么非得这么麻烦呢?如果我加个 dummy head,这三种情况不都变成一种了吗

while cur.next != None 让 cur 指针停在被删除节点的前一位,无论是删头,删中,删尾是都一样的

class Solution(object):
    def removeElements(self, head, val):
        if not head: return head
        dummy = ListNode(-1)
        dummy.next = head 
        cur = dummy
        while cur.next: # 这样可以保证能够删除掉最后一个元素!
            if cur.next.val == val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return dummy.next

        # wrong: [7,7,7,7] - None type object has no attribute val

 # 什么时候写 while cur 什么时候写 while cur.next?

A. 如果想要删除的是最后一个元素,说明我们的指针要遍历到倒数第二位,即 cur.next != None,所以:删除最后一个元素的话,需要写 while cur.next

B.如果是反转链表这种题目,cur指针走到空指针就结束的情况下,就写 while cur != None

707 设计链表

# 易错点总结:

get index:

1. 首先对index进行判断,如果 <0 或者 >= self.count 说明已经越界,直接返回 -1

2. 其次是遍历到index当前所在的位置。因为有虚拟头节点,所以设立cur指针在 self.dummyHead, for loop 从(0,index+1 )

3. cur 指针停止的地方,就是当前index所在的位置

add at Index:

1. 先对index进行判断,如果 index <0, 重置为0,如果index >= self.count,说明越界,返回-1

2. 在当前index的前面插入一个数,说明要遍历到当前index前一位的数字:

3. 创建for loop (0,index) - 指针设置为 pre,pre 停下来的位置就是插入index的前一位

4. 插入新节点的操作:1.创建new node 2. new_node.next = pre.next 3. pre.next = new_node

5. 记得要对 self.size += 1 !!!

class Node():
    def __init__(self,val):
        self.val = val
        self.next = None 

class MyLinkedList(object):
    def __init__(self):
        self.dummy = Node(0) # create a dummy head 
        self.size = 0

    def get(self, index):
        if index >= self.size or index < 0: return -1 # consider the scenario when index <0
        cur = self.dummy
        for _ in range(index+1):
            cur = cur.next
        return cur.val
        
    def addAtHead(self, val):
        return self.addAtIndex(0,val) # miss another parameter 

    def addAtTail(self, val):
        return self.addAtIndex(self.size,val) ## add at tail: should be self.size not self.size -1

    def addAtIndex(self, index, val):
        if index > self.size:
            return -1
        if index < 0: 
            index = 0
        cur = self.dummy
        for _ in range(index):
            cur = cur.next 
        new_node = Node(val)
        new_node.next = cur.next
        cur.next = new_node
        # (0) 1,2,3,4,5 -- add at index 2:
        self.size += 1

    def deleteAtIndex(self, index):
        """
        :type index: int
        :rtype: None
        """
        if index >= self.size or index < 0: return -1

        cur = self.dummy
        for _ in range(index):
            cur = cur.next
        cur.next = cur.next.next 
        self.size -= 1

 

206. 反转链表

代码随想录:

递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。

关键是初始化的地方,可能有的同学会不理解, 可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。

具体可以看代码(已经详细注释),双指针法写出来之后,理解如下递归写法就不难了,代码逻辑都是一样的。

# 进步:第一次搞懂递归法怎么写!

1. 递归参数和返回值:需要一个 pre 和 一个 cur 指针,返回下一层递归的头节点

2. 递归终止条件:当 cur 走到空的时候,返回pre 指针

class Solution(object):
    def reverseList(self, head):
        if not head or not head.next: return head # 这段不是必须
        def reverse(pre,cur):
            if not cur:
                return pre
            temp = cur.next 
            cur.next = pre
            return reverse(cur, temp) # 这里不写return语句会报错

        return reverse(None, head)

反转链表递归法易错点:

1.不需要写 if not head or not head.next: return head 这句话,因为 reverse函数可以涵盖这种情况

2.调用递归语句的时候,记得要写return,因为最终的函数是要返回 pre 这个节点

3.递归函数调用的一开始,让 pre = None,cur = head

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值