算法练习Day3 (Leetcode/Python-链表)

链表基础知识

1. 链表的查询需要时间复杂度为O(n), 插入删除复杂度为O(1)。与数组正好相反。

2. 用python定义链表的方式:

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

3. 链表类型

单链表中的指针域只能指向节点的下一个节点。

双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。既可以向前查询也可以向后查询。

循环链表: 就是链表首尾相连。

4. 删除节点的时候,直接将current节点的指针next指向current.next.next的节点即可。在python里,多余的被删除的节点(current.next)会被内存自动回收,不用手动释放。

5. 涉及链表增删,即元素位数变动的情况,总是加上一个虚拟表头会更加方便。  dummy_head = ListNode(next=head),这个虚拟表头指向真正的表头。如果不加的话,如果删/增的是链表里的第一个元素的话就需要额外写代码处理。

203. Remove Linked List Elements 移除等于Val的元素

Given the head of a linked list and an integer val, remove all the nodes of the linked list that has Node.val == val, and return the new head.

Example:

Input: head = [], val = 1
Output: []
Input: head = [7,7,7,7], val = 7
Output: []

思路:构造虚拟表头dummy_head,以防链表为空,即无ListNode时,不便统一处理。

注意!以下写法中,当current.next 为None,current就是表尾的最后一个元素,且这个元素的值是否等于val在上一个while循环里就已经被判断过了,直接跳出循环即可。while循环里,current从无实际意义的虚拟表头开始,每次判断的都是current.next,即下一个元素的值。

class Solution(object):
    def removeElements(self, head, val):
        """
        :type head: ListNode
        :type val: int
        :rtype: ListNode
        """
        dummy_head = ListNode(next=head) # 构造虚拟链表头,方便增删元素

        current = dummy_head # 当前链表所处元素
        while current.next:
            if current.next.val == val:
                current.next = current.next.next
            else:
                current = current.next
        return dummy_head.next

707. Design Linked List

Example:

Input
["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"]
[[], [1], [3], [1, 2], [1], [1], [1]]
Output
[null, null, null, null, 2, null, 3]

思路:

同样的,继续设置一个dummy_head为了方便处理增删元素的情况。同时,记录一个链表长度更加方便查询当前函数输入的index是否有意义,无意义就不用遍历整个链表了。虽然应该是并非必须。

注意!别忘了corner case,index超出了链表长度,即 if index >= self.size: return -1。index似乎默认>=0, 因为不写这个corner case,leetcode代码也能通过。

class MyLinkedList(object):

    def __init__(self):
        self.dummy_head = ListNode()
        self.size = 0 # self.size is useful, do not forget.


    def get(self, index):
        """
        :type index: int
        :rtype: int
        """
        if index >= self.size: # corner cases: out of scope 
            return -1 

        current = self.dummy_head.next
        for i in range(index):
            current = current.next
        return current.val 
        

    def addAtHead(self, val):
        """
        :type val: int
        :rtype: None
        """
        self.dummy_head.next = ListNode(val, self.dummy_head.next)
        self.size = self.size + 1 

        return self.dummy_head.next
        

    def addAtTail(self, val):
        """
        :type val: int
        :rtype: None
        """
        current = self.dummy_head 
        while current.next:
            current = current.next
        current.next = ListNode(val, None)
        self.size += 1 
            
        

    def addAtIndex(self, index, val):
        """
        :type index: int
        :type val: int
        :rtype: None
        """
        if index > self.size:
            return 
        current = self.dummy_head
        for i in range(index):
            current = current.next
        current.next = ListNode(val, current.next)
        self.size += 1



    def deleteAtIndex(self, index):
        """
        :type index: int
        :rtype: None
        """
        if index >= self.size:
            return 
        current = self.dummy_head
        for i in range(index):
            current = current.next
        current.next = current.next.next
        self.size -= 1    
        

206. Reverse Linked List 反转链表

Example:

Input: head = [1,2]
Output: [2,1]
Input: head = []
Output: []

Solution 双指针法:

思路:所谓双指针就是记录当前Node cur和上一个Node pre,用temp记录当前Node的原本的下一个Node,然后把pre赋给当前Node的next,实现reverse。

class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        pre = None
        cur = head
        while cur: #这个问题中不在乎是否有下一个链表Node,只看当前Node是否存在,只要当前的存在,一定有指向它的更前的Node。所以这里不用cur.next判断while跳出标志。
            temp = cur.next # ori next of cur  #如果cur已经是最后一个Node,cur.next = None罢了。
            cur.next = pre # update ori next to pre
            pre = cur # set pre to cur
            cur = temp # set ori next of cur to the new cur
        return pre

Solution 递归法

化上一解法中的while为递归的写法。 

class Solution(object):
    def reverseList(self, head):
        return self.recursiveReverse(head, None)
    def recursiveReverse(self, cur, pre):
        # 跳出递归的条件
        if not cur: 
            return pre #当前node不存在了,说明链表到尾了,return当前node的上一个为真正的链表尾巴
        # 当前递归的处理
        temp = cur.next
        cur.next = pre
        # 自调用,进入递归下一层
        return self.recursiveReverse(temp, cur)

############################################################################

2. Add Two Numbers

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
Explanation: 342 + 465 = 807.

Example 2:

Input: l1 = [0], l2 = [0]
Output: [0]

Example 3:

Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]

思路:按位相加,若超过10,则carry进1,carry被加到下一位中。

注意while循环里除了看两个列表是否被遍历到了最后一位,还要看carry != 0。因为可能有上一位相加遗留的进位。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        dummyhead = ListNode(0)
        curr = dummyhead
        carry = 0
        while l1 != None or l2 != None or carry != 0:
            l1val = l1.val if l1 else 0
            l2val = l2.val if l2 else 0
            columnSum = l1val + l2val + carry
            carry = columnSum // 10 
            newNode = ListNode(columnSum % 10)
            curr.next = newNode 
            curr = newNode 
            l1 = l1.next if l1 else None
            l2 = l2.next if l2 else None
        return dummyhead.next 

Reference: 

代码随想录

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值