Leetcode刷题之链表篇(三)

链表篇

2. 两数相加

  • 思路1:采取双指针,一一对应相加,过程中记录进位以及考虑双指针是否为空
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        ret,cin = ListNode(0),0
        pre = ret
        while l1 or l2:
            if l1 and l2:
                val = (l1.val + l2.val + cin) % 10
                cin = (l1.val + l2.val + cin) // 10
            elif l1:
                val = (l1.val + cin) % 10
                cin = (l1.val + cin) // 10
            elif l2:
                val = (l2.val + cin) % 10
                cin = (l2.val + cin) // 10
            tmp = ListNode(val)
            pre.next = tmp
            pre = tmp
            if l1: l1 = l1.next
            if l2: l2 = l2.next
        if cin:
            pre.next = ListNode(cin) # 默认新建节点next 为None 符合链表尾节点定义
        return ret.next

总结:头结点不确定时,可引入哨兵节点

445. 两数相加 II

  • 思路1:将链表进行逆序,采取逆序的方式去保存每位数字,然后一一对应相加,过程中记录进位以及考虑双指针是否为空
  • 思路2:在l1和l2中的短链表前面填充节点0,直到两个链表长度一致 一一对应相加即可,会多耗费空间
# 思路1
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        l1 = self.reverseList(l1)
        l2 = self.reverseList(l2)
        ret,cin = ListNode(0),0
        pre = ret
        while l1 or l2:
            if l1 and l2:
                val = (l1.val + l2.val + cin) % 10
                cin = (l1.val + l2.val + cin) // 10
            elif l1:
                val = (l1.val + cin) % 10
                cin = (l1.val + cin) // 10
            elif l2:
                val = (l2.val + cin) % 10
                cin = (l2.val + cin) // 10
            tmp = ListNode(val)
            pre.next = tmp
            pre = tmp
            if l1: l1 = l1.next
            if l2: l2 = l2.next
        if cin:
            pre.next = ListNode(cin) # 默认新建节点next 为None 符合链表尾节点定义
        ret = self.reverseList(ret.next)
        return ret
        
    def reverseList(self,head):
        pre,cur = None,head
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre
# 思路2
class Solution:
    def __init__(self):
        self.cin = 0

    def addTwoNumbers(self,l1,l2):
        ret = ListNode(0)
        if not l1: return l2
        if not l2: return l2
        cur1,cur2 = l1,l2
        while cur1 or cur2: # 在短的链表前面 填充节点为0的节点
            if cur1 and not cur2:
                tmp = ListNode(0)
                tmp.next = l2
                l2 = tmp
            if cur2 and not cur1:
                tmp = ListNode(0)
                tmp.next = l1
                l1 = tmp
            if cur1: cur1 = cur1.next
            if cur2: cur2 = cur2.next
        self.dfs(l1,l2,ret)
        if self.cin: # 存在进位 在最前面添加节点,值为1
            cur = ListNode(1)
            tmp = ret.next
            ret.next = cur
            cur.next = tmp
        return ret.next

    def dfs(self,l1,l2,ret):
        if not l1 and not l2: return
        self.dfs(l1.next,l2.next,ret) # 后序
        cur = ListNode((l1.val+l2.val+self.cin)%10)
        self.cin = (l1.val+l2.val+self.cin) // 10
        tmp = ret.next
        ret.next = cur
        cur.next = tmp

总结:链表存储非负整数,每位数字一般采取 逆序方式!

143. 重排链表

  • 思路1:链表涉及到前半部分、后半部分概念时,可采取快慢指针进行链表二分,对后半部分链表反转,然后一一比较
class Solution(object):
    def reorderList(self, head): 
        # 链表分成两半  用快慢指针
        pre,cur = head,head
        while cur and cur.next:
            pre = pre.next
            cur = cur.next.next
        tmp = pre.next
        pre.next = None
        pre,cur = None,tmp # 链表反转
        while cur:
            tmp = cur.next 
            cur.next = pre
            pre = cur
            cur = tmp
        cur = head
        while pre: # 一一重排
            tmp = cur.next
            pre_next = pre.next
            cur.next = pre
            pre.next = tmp
            cur = tmp
            pre = pre_next
        return head  

总结:链表二分,用快慢指针

21. 合并两个有序链表(面试高频)

  • 思路1:引入哨兵节点,一一比较两个有序链表元素,小的接到哨兵节点后面
class Solution(object):
    def mergeTwoLists(self, l1, l2):
        head = ListNode() #辅助头节点
        cur = head
        while(l1 and l2):
            if(l1.val <= l2.val):
                cur.next = l1
                l1 = l1.next
            else:
                cur.next = l2
                l2 = l2.next
            cur = cur.next
        cur.next = l1 if l1 else l2
        return head.next

总结:头结点不确定,引入哨兵节点

148. 排序链表

  • 思路1:链表排序,采取归并排序 无需额外数组;归并排序先 递归二分链表,然后对 两个有序子链表采取合并
  • 思路2:借助数组,把链表节点放入数组中,对数组自定义排序,根据节点val排序,然后把数组中排序后的节点连接起来
# 链表归并排序
class Solution(object):
    def sortList(self, head):
        # 链表为了节约 空间,可采取归并排序
        if not head or not head.next: return head
        cur1,cur2 = head,self.mid(head)
        cur1 = self.sortList(cur1)
        cur2 = self.sortList(cur2)
        return self.merge(cur1,cur2)

    def mid(self,head): # 链表二分
        if not head or not head.next: return head
        tmp = ListNode(0,next = head) # 头结点可能变化  因此需要引入哨兵节点
        pre,cur = tmp,tmp
        while cur and cur.next:
            pre = pre.next
            cur = cur.next.next
        p = pre.next
        pre.next = None # 中间断掉链表
        return p

    def merge(self,cur1,cur2):
        if not cur1: return cur2
        if not cur2: return cur1
        if cur1.val < cur2.val:
            cur1.next = self.merge(cur1.next,cur2)
            return cur1
        else:
            cur2.next = self.merge(cur1,cur2.next)
            return cur2
# 借助数组
class Solution(object):
    def sortList(self, head):
        if not head: return None
        nums = []
        while head:
            nums.append(head)
            head = head.next
        nums.sort(key=lambda x:x.val)
        for i in range(len(nums)-1):
            nums[i].next = nums[i+1]
        nums[-1].next = None
        return nums[0]

总结:链表排序采取归并排序,链表最后一个元素指向None

23. 合并k个升序链表(hard)

  • 思路1:两两有序链表合并,合并k-1次,时间复杂度较高
  • 思路2:采取归并排序的思想,递归完成两个有序子链表的排序
# 思路1
class Solution(object):
    def mergeKLists(self, lists):
        if not lists: return None
        head = lists[0]
        for i in range(1,len(lists)):
            head = self.mergeTwoLists(head,lists[i])
        return head

    def mergeTwoLists(self,l1,l2):
        auxi = ListNode(0)
        pre = auxi
        while l1 and l2:
            if l1.val <= l2.val:
                pre.next = l1
                l1 = l1.next
            else:
                pre.next = l2
                l2 = l2.next
            pre = pre.next
        if l1: pre.next = l1
        if l2: pre.next = l2
        return auxi.next
# 思路2
class Solution(object):
    def mergeKLists(self, lists):
        if not lists: return None
        i,j = 0,len(lists)-1
        return self.dfs(lists,i,j)
        
    def dfs(self,lists,i,j):
        if i>=j: return lists[i]
        mid = (i+j) // 2
        cur1 = self.dfs(lists,i,mid)
        cur2 = self.dfs(lists,mid+1,j)
        return self.mergeTwoLists(cur1,cur2)

    def mergeTwoLists(self,l1,l2):
        auxi = ListNode(0)
        pre = auxi
        while l1 and l2:
            if l1.val <= l2.val:
                pre.next = l1
                l1 = l1.next
            else:
                pre.next = l2
                l2 = l2.next
            pre = pre.next
        if l1: pre.next = l1
        if l2: pre.next = l2
        return auxi.next

总结:合并k个有序链表,可以采取 归并排序二分的思想,然后对有序子链表排序

25. k个一组翻转链表(hard)

  • 思路1:引入哨兵节点 遍历链表,依次反转节点 ,记录每k个节点的起始节点 当计数为k时。更新链表连接指向,并更新起始节点,如果发现 最终起始节点不为空,说明最后 一组节点没有k个(但是还是在遍历过程中被反转了),因此需要再反转回来
class Solution(object):
    def reverseKGroup(self, head, k):
        if not head or not head.next: return head
        cnt,ret = 0,ListNode(0,next=head)
        pre,cur = ret,head
        preNode,start,end = None,head,None
        while cur:
            cnt += 1
            tmp = cur.next
            if not tmp: end = cur
            cur.next =  preNode
            preNode = cur
            if cnt == k:
                pre.next = cur
                pre = start
                start = tmp
                cnt = 0
                preNode = None
            cur = tmp
        preNode = None
        if start: # 
            while end: # 最后 一组节点没有k个(但是还是在遍历过程中被反转了),因此需要再反转回来
                tmp = end.next
                end.next = preNode
                preNode = end
                end = tmp
        pre.next = start
        return ret.next

总结:头结点不确定,引入哨兵节点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值