Leetcode-链表(一)

目录

206. 反转链表

92. 反转链表 II

83. 删除排序链表中的重复元素

82. 删除排序链表中的重复元素 II

86. 分隔链表

328. 奇偶链表

2. 两数相加

445. 两数相加 II

203. 移除链表元素

21. 合并两个有序链表


206. 反转链表

https://leetcode-cn.com/problems/reverse-linked-list/

反转一个单链表。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

题解

一:迭代,定义了三个指针,通过挪动三个指针来完成题目。

class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        pre_node, cur_node = None, head
        while cur_node:
            next_node = cur_node.next
            cur_node.next = pre_node
            pre_node = cur_node
            cur_node = next_node
        return pre_node

二:迭代,copy官方题解,https://leetcode-cn.com/problems/reverse-linked-list/solution/fan-zhuan-lian-biao-by-leetcode/

递归版本稍微复杂一些,其关键在于反向工作。假设列表的其余部分已经被反转,现在我该如何反转它前面的部分?

假设列表为:

n_1 \rightarrow \cdots \rightarrow n_{k-1} \rightarrow n_k \rightarrow n_{k+1} \rightarrow \cdots \rightarrow n_m \rightarrow \oslash

若从节点n_{k+1}n_m已经被反转,而我们正处于n_k

n_1 \rightarrow \cdots \rightarrow n_{k-1} \rightarrow n_k \rightarrow n_{k+1} \leftarrow \cdots \leftarrow n_m

我们希望n_{k+1}的下一个节点指向n_k。所以next\_node.next = n_k,也即n_k.next.next = n_k
要小心的是n_1的下一个必须指向 Ø 。如果你忽略了这一点,你的链表中可能会产生循环。如果使用大小为 2 的链表测试代码,则可能会捕获此错误。

函数reverseList返回的是翻转后的链表的头节点,其中head.next=None,是必须的,因为翻转后,原头节点的next是空。

class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        next_node = head.next
        p = self.reverseList(head.next)
        next_node.next = head
        head.next = None
        return p   

92. 反转链表 II

https://leetcode-cn.com/problems/reverse-linked-list-ii/

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。

说明:1 ≤ m ≤ n ≤ 链表长度。

示例:输入: 1->2->3->4->5->NULL, m = 2, n = 4,输出: 1->4->3->2->5->NULL。

题解

一:借鉴206反转链表的思路,其中reverse函数是翻转m到n之间的链表,并返回翻转之后的头节点pre(4)以及原链表的下一个节点cur(5,即无需翻转的第一个节点),主体结构的cur(2)是第一个要翻转的节点(翻转之后是新链表的尾节点),pre(1)是最后一个无需翻转的节点。

class Solution(object):
    def reverseBetween(self, head, m, n):
        """
        :type head: ListNode
        :type m: int
        :type n: int
        :rtype: ListNode
        """
        def reverse(node):
            num = n - m + 1
            cnt = 1
            pre, cur = None, node
            while cnt <= num:
                next = cur.next
                cur.next = pre
                pre = cur
                cur = next
                cnt += 1
            return pre, cur

        before_head = ListNode(0)
        before_head.next = head
        pre, cur = before_head, head
        cnt = 1
        while cnt < m:
            pre = cur
            cur = cur.next     
            cnt += 1

        before, next = reverse(cur)
        pre.next, cur.next = before, next
        return before_head.next
class Solution(object):
    def reverseBetween(self, head, m, n):
        before_head = ListNode(0)
        before_head.next, pre = head, before_head

        i, cur = 1, head
        while i < m:
            pre, cur = cur, cur.next
            i += 1
        start = cur 

        l_pre, next = None, None
        while i <= n:
            next = cur.next 
            cur.next = l_pre 
            l_pre, cur = cur, next 
            i += 1

        start.next = cur
        pre.next = l_pre
        return before_head.next

83. 删除排序链表中的重复元素

https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例 1:输入: 1->1->2,输出: 1->2
示例 2:输入: 1->1->2->3->3,输出: 1->2->3

题解

一:下一个元素与当前重复的元素,让该指针指向下一个元素的下一个(即跳掉下一个元素),若不重复,比较后续元素。因为每个元素只出现一次,头节点就依然会是头节点,不会被删除。最后一个节点单独处理,其next为None。

class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head:
            return head
        pre, cur = head, head.next

        while cur:
            if pre.val == cur.val:
                cur = cur.next 
            else:
                pre.next = cur 
                pre = cur 
        pre.next = None 
        return head

82. 删除排序链表中的重复元素 II

https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。

示例 1:输入: 1->2->3->3->4->4->5,输出: 1->2->5
示例 2:输入: 1->1->1->2->3,输出: 2->3

题解

一:这边与上一题的区别,头节点可能会被删掉,故添加一个虚拟节点,符合要求的链表的最后一个节点是pre,考虑当前节点,他若和前一个节点或者后一个节点相等,都要跳掉,若不相等,则将pre指向该节点,要注意每时每刻符合要求的最后一个节点都是pre,故遍历完毕,要让pre.next=None。

class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head 
        
        before_head = ListNode(head.val - 1)
        before_head.next, pre, cur, l_pre = head, before_head, head, before_head 

        while cur:
            next = cur.next
            if l_pre.val != cur.val and (not next or cur.val != next.val):
                pre.next = cur 
                pre = cur
            l_pre = cur  
            cur = next
        pre.next = None 
        return before_head.next

86. 分隔链表

https://leetcode-cn.com/problems/partition-list/

给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。你应当保留两个分区中每个节点的初始相对位置。

示例:输入: head = 1->4->3->2->5->2, x = 3,输出: 1->2->2->4->3->5

题解

一:创建两个链表(小于是一个,大于等于是一个,在把这俩链表合并成一个),小trick:初始化为两个哑 ListNode,这样可以避免判断是否是第一个节点(小于、大于等于的),注意事项:要注意大于等于x的那个链表的尾节点的next要初始化为空,不然他有可能会指向别的节点,从而形成环。

class Solution(object):
    def partition(self, head, x):
        """
        :type head: ListNode
        :type x: int
        :rtype: ListNode
        """
        less_head, great_head = ListNode(x), ListNode(x)
        cur, cur_less, cur_great = head, less_head, great_head
        while cur:
            next = cur.next
            if cur.val < x:
                cur_less.next = cur
                cur_less = cur
            else:
                cur_great.next = cur
                cur_great = cur
            cur = next
        cur_great.next = None
        cur_less.next = great_head.next
        return less_head.next

328. 奇偶链表

https://leetcode-cn.com/problems/odd-even-linked-list/

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:输入: 1->2->3->4->5->NULL,输出: 1->3->5->2->4->NULL
示例 2:输入: 2->1->3->5->6->4->7->NULL ,输出: 2->3->6->7->1->5->4->NULL
说明:应当保持奇数节点和偶数节点的相对顺序。链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

题解

一:还是两个链表,第一个奇数节点,第二个偶数节点,做这类题目注意把握好循环进行下去的条件,即用那个指针进行判断,可以用例子来看看是否有问题,例如[1,2,3,4]和[1,2,3,4,5]。

这边要注意,循环体中的判断第一处if even_cur.next是为了确保even_cur.next.next这句话的正确性,第二处if odd_cur.next:是为了确保odd_cur不为None,保证odd_cur.next = even_head的正确性。

class Solution(object):
    def oddEvenList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        odd_head, even_head = head, head.next
        odd_cur, even_cur = odd_head, even_head

        while even_cur:
            odd_cur.next = even_cur.next
            if even_cur.next:
                even_cur.next = even_cur.next.next
            if odd_cur.next:
                odd_cur = odd_cur.next
            even_cur = even_cur.next
        odd_cur.next = even_head
        return odd_head

精简一点,在循环的时候一起判断,不再循环体中单独判断。

class Solution(object):
    def oddEvenList(self, head):
        if not head or not head.next:
            return head
        odd_head, even_head = head, head.next
        odd_cur, even_cur = odd_head, even_head

        while even_cur and even_cur.next:
            odd_cur.next = even_cur.next
            even_cur.next = even_cur.next.next
            odd_cur = odd_cur.next
            even_cur = even_cur.next
        odd_cur.next = even_head
        return odd_head

2. 两数相加

https://leetcode-cn.com/problems/add-two-numbers/

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例:输入:(2 -> 4 -> 3) + (5 -> 6 -> 4),输出:7 -> 0 -> 8,原因:342 + 465 = 807

题解

一:没啥注意的,依旧是关注指针是否为None的问题(即我们是否用了None的next,也即合法性)。另外,所有的数加完之后,要判断是否有进位,若有还要创建一个节点以对应该进位。

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        before_head = ListNode(0)
        cur, cur_1, cur_2, carry = before_head, l1, l2, 0

        while cur_1 or cur_2:
            val = carry
            if cur_1:
                val += cur_1.val
                cur_1 = cur_1.next
            if cur_2:
                val += cur_2.val
                cur_2 = cur_2.next
            carry = val // 10
            val = val % 10
            cur.next = ListNode(val)
            cur = cur.next
        if carry:
            cur.next = ListNode(carry)
        return before_head.next

445. 两数相加 II

https://leetcode-cn.com/problems/add-two-numbers-ii/

给你两个 非空 链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。你可以假设除了数字 0 之外,这两个数字都不会以零开头。

进阶:如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。

示例:输入:(7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4),输出:7 -> 8 -> 0 -> 7

题解

一:反转链表,再用题2的方法,得到结果之后继续反转

二:借助数据结构,将链表中的数据存储下来。这边用的列表。

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        rec1, rec2, rec = [], [], []
        self._abstract_num(l1, rec1)
        self._abstract_num(l2, rec2)
        self._sum(rec1, rec2, rec)
        before_head = ListNode(0)
        cur = before_head
        for i in range(len(rec)-1, -1, -1):
            val = rec[i]
            cur.next = ListNode(val)
            cur = cur.next
        return before_head.next

    def _abstract_num(self, l, rec):
        cur = l
        while cur:
            rec.append(cur.val)
            cur = cur.next
    
    def _sum(self, rec1, rec2, rec):
        i, j, carry = len(rec1)-1, len(rec2)-1, 0
        while i >= 0 or j >= 0:
            val = carry
            if i >= 0:
                val += rec1[i]
                i -= 1
            if j >= 0:
                val += rec2[j]
                j -= 1
            carry = val // 10
            val = val % 10
            rec.append(val)
        if carry:
            rec.append(carry)

三:copy官方题解,https://leetcode-cn.com/problems/add-two-numbers-ii/,借用栈的结构后进先出,list的append和pop可做到,然后最后倒着把链表连起来

class Solution(object):
    def addTwoNumbers(self, l1, l2):
        rec1, rec2 = [], []
        self._abstract_num(l1, rec1)
        self._abstract_num(l2, rec2)

        ans, carry = None, 0

        while rec1 or rec2 and carry != 0:
            x = rec1.pop() if rec1 else 0
            y = rec2.pop() if rec2 else 0
            val = carry + x + y
            carry = val // 10
            val = val % 10
            cur = ListNode(val)
            cur.next = ans
            ans = cur
        return ans
        
    def _abstract_num(self, l, rec):
        while l:
            rec.append(l.val)
            l = l.next

203. 移除链表元素

https://leetcode-cn.com/problems/remove-linked-list-elements/

删除链表中等于给定值 val 的所有节点。

示例:输入: 1->2->6->3->4->5->6, val = 6, 输出: 1->2->3->4->5

题解

一:跳过就👌啦,要注意这句话pre.next = None,否则若最后一个元素应该被删除,缺少这句话删不掉,虚拟头节点一直就是链表题目的小trick。

class Solution(object):
    def removeElements(self, head, val):
        """
        :type head: ListNode
        :type val: int
        :rtype: ListNode
        """
        before_head = ListNode(0)
        pre, cur = before_head, head

        while cur:
            if cur.val != val:
                pre.next = cur
                pre = cur
            cur = cur.next
        pre.next = None
        return before_head.next

21. 合并两个有序链表

将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例:输入:1->2->4, 1->3->4,输出:1->1->2->3->4->4

题解

一:不改变原先两链表的结构

class Solution(object):
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        before_head = ListNode(0)
        pre = before_head

        while l1 or l2:
            if not l1:
                pre.next = ListNode(l2.val)
                l2 = l2.next
            elif not l2:
                pre.next = ListNode(l1.val)
                l1 = l1.next
            elif l1.val < l2.val:
                pre.next = ListNode(l1.val)
                l1 = l1.next
            else:
                pre.next = ListNode(l2.val)
                l2 = l2.next
            pre = pre.next
        return before_head.next

二:可以改变原先链表结构

class Solution(object):
    def mergeTwoLists(self, l1, l2):
        
        before_head = ListNode(0)
        pre = before_head

        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
        pre.next = l1 if l1 else l2
        return before_head.next

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值