链表 LC.19/83/92/61/143/21/160/141/147/138/142

LC.19 Remove Nth Node Form End of List

Description

Given a linked list, remove the n-th node from the end of list and return its head.

Example:

Given linked list: 1->2->3->4->5, and n = 2.

After removing the second node from the end, the linked list becomes 1->2->3->5.

Note:

Given n will always be valid.

Follow up:

Could you do this in one pass?

Solution

  • one-pass (trivial) 实际上有两个指针,所以是2-pass
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        count = 1
        target = head
        temp = head
        while count < n:
            temp = temp.next
            count += 1
        if temp.next == None:
            return target.next
        else:
            temp = temp.next
        while temp.next != None:
            target = target.next
            temp = temp.next
        target_d = target.next
        target.next = target_d.next
        
        return head
        
  • recursive

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
            rec = self.helper(head, n)
            if rec == n:
                return head.next
            return head
        
        def helper(self, head: ListNode, n: int) -> int:
            if head.next == None:
                return 1
            rec = self.helper(head.next, n)
            if rec == n:
                head.next = head.next.next
            return rec + 1
    

    递归做法,实际上这道题本质上必须遍历整个链表直到最后一个node,所以用递归的方法查看之后还剩多少个元素,如果正好是n的话,那么当前的结点(倒数第n+1个)的下一个结点(倒数第n个)就需要被删除。和另外一个方法比起来并不会增大memory的占用。runtime还更低(我猜是因为少了一个移动的指针)


LC.83 Remove Duplicates from Sorted List

Description

Given a sorted linked list, delete all duplicates such that each element appear only once.

Example 1:

Input: 1->1->2
Output: 1->2

Example 2:

Input: 1->1->2->3->3
Output: 1->2->3

Solution

  • straight solution (两个指针)

  • # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def deleteDuplicates(self, head: ListNode) -> ListNode:
            node_a = head
            node_b = head
            if head == None:
                return head
            while node_b.next != None:
                if node_b.val != node_b.next.val:
                    node_a.next = node_b.next
                    node_a = node_a.next
                node_b = node_b.next
            if not node_a == node_b:
                node_a.next = node_b.next
            return head
    

    或者一个指针:

    class Solution:
        def deleteDuplicates(self, head: ListNode) -> ListNode:
            temp = head
            while temp != None and temp.next != None:
                if temp.val == temp.next.val:
                    temp.next = temp.next.next
                else:
                    temp = temp.next
            return head
    
  • 递归做法

    class Solution:
        def deleteDuplicates(self, head: ListNode) -> ListNode:
            if head == None or head.next == None:
                return head
            if head.val == head.next.val:
                return self.deleteDuplicates(head.next)
            else:
                head.next = self.deleteDuplicates(head.next)
                return head
    

LC. 92 Reversed Linked List

Reverse a linked list from position m to n. Do it in one-pass.

Note: 1 ≤ mn ≤ length of list.

Example:

Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL

Solution

  • 直接从前往后走,只要还在reverse的范围内,看见一个拎出来一个,添加到旁边的翻转新链表的表头。所有需要翻转的都翻转完之后,把新的链表插在原来的链表里面

    class Solution(object):
        def reverseBetween(self, head, m, n):
            """
            :type head: ListNode
            :type m: int
            :type n: int
            :rtype: ListNode
            """
            holder = ListNode(-1)
            holder.next = head
            head = holder
            count = 1
            while count < m:
                head = head.next
                count += 1
            new = None
            while count < n+1:
                temp = head.next.next
                head.next.next = new
                new = head.next
                if count == m:
                    tail = new
                head.next = temp
                count += 1
            temp = head.next
            head.next = new
            tail.next = temp
            return holder.next
    
    

    在表的最前面加一个holder可以方便计数,并且corner case少了很多!!第17-20行是翻转表头的操作

  • 递归做法

    class Solution(object):
        def reverseBetween(self, head, m, n):
            """
            :type head: ListNode
            :type m: int
            :type n: int
            :rtype: ListNode
            """
            self.successor = None
            if m == 1:
                return self.reverseHelper(head, n-m+1)
            head.next = self.reverseBetween(head.next, m-1, n-1)
            return head
                
        def reverseHelper(self, head, m):
            if m == 1:
                self.successor = head.next
                return head
            new = self.reverseHelper(head.next, m-1)
            head.next.next = head
            head.next = self.successor
            return new
    

    是LC.206的变形,递归的时候加入一个变量k,reverse当前链表的前k个元素。递归现在还写得乱七八糟的!!


LC. 61 Rotate List

Given a linked list, rotate the list to the right by k places, where k is non-negative.

Example 1:

Input: 1->2->3->4->5->NULL, k = 2
Output: 4->5->1->2->3->NULL
Explanation:
rotate 1 steps to the right: 5->1->2->3->4->NULL
rotate 2 steps to the right: 4->5->1->2->3->NULL

Example 2:

Input: 0->1->2->NULL, k = 4
Output: 2->0->1->NULL
Explanation:
rotate 1 steps to the right: 2->0->1->NULL
rotate 2 steps to the right: 1->2->0->NULL
rotate 3 steps to the right: 0->1->2->NULL
rotate 4 steps to the right: 2->0->1->NULL

Solution

  • 直接解:

    先数一下一共有多少个元素,再用总数减去模k的值求left rotate多少个。找到新的头元素,把tail和原来的头元素串起来就好了

    class Solution(object):
        def rotateRight(self, head, k):
            """
            :type head: ListNode
            :type k: int
            :rtype: ListNode
            """
            if not head:
                return head
            count = 1
            key = head
            while key.next:
                count += 1
                key = key.next
            key.next = head
            k = count - k % count
            
            while k > 1:
                head = head.next
                k -= 1
            new = head.next
            head.next = None
            return new
    
  • 还可以用间隔k的两个指针,一旦走到头就重新回到head的方法,不需要显式地求list的长度。但这样复杂度显然变高了,模掉的那堆都得计算一遍


LC. 143 Reorder List

Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→LnL1→Ln-1→L2→Ln-2→…

You may not modify the values in the list's nodes, only nodes itself may be changed.

Example 1:

Given 1->2->3->4, reorder it to 1->4->2->3.

Example 2:

Given 1->2->3->4->5, reorder it to 1->5->2->4->3.

Solutions

  • 这题还蛮容易错的,主要是reverse list的时候不能反转原链表,这样正序的链表就没了;首先找到链表中点,然后反转后一半的链表,前一半的链表a和后一半的反转链表b交替插在一块儿就好了

    class Solution(object):
        def reorderList(self, head):
            """
            :type head: ListNode
            :rtype: None Do not return anything, modify head in-place instead.
            """
            if not head or not head.next:
                return
            a = b = head
            move_a = False
            while b.next:
                b = b.next
                if move_a == True:
                    a = a.next
                    move_a = False
                else:
                    move_a = True
            list_b = self.reverseList(a.next)
            a.next = None
            list_a = head
            while list_b:
                a_temp = list_a.next
                b_temp = list_b.next
                list_a.next = list_b
                list_b.next = a_temp
                list_a = a_temp
                list_b = b_temp
            return
        
        def reverseList(self, head):
            if not head.next:
                return head
            new = self.reverseList(head.next)
            head.next.next = head
            head.next = None
            return new
    

    优化:

    第7-17行可以优化成如下,复杂度降了好多,我也不确定为什么,大概是更改变量的次数变少了。。

     while b.next.next:
                b = b.next.next
                a = a.next
                if not b.next:
                    break
    
  • 感觉这道没必要用递归,因为每次都得找最尾端的元素,性价比很低 (?


LC. 21. Merge Two Sorted Lists

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

Example:

Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4、

Solutions

  • 直接解(超级丑)

  • class Solution(object):
        def mergeTwoLists(self, l1, l2):
            """
            :type l1: ListNode
            :type l2: ListNode
            :rtype: ListNode
            """
            if not l1:
                return l2
            if not l2:
                return l1
            if l1.val <= l2.val:
                head = l1
                l1 = l1.next
            else:
                head = l2
                l2 = l2.next
            key = head
            while l1 and l2:
                if l1.val <=l2.val:
                    key.next = l1
                    key = key.next
                    l1 = l1.next
                else:
                    key.next = l2
                    key = key.next
                    l2 = l2.next
            if l1 or l2:
                key.next = l1 if l1 else l2
            return head
    
  • 递归(似乎叫动态规划了这里)

    class Solution(object):
        def mergeTwoLists(self, l1, l2):
            """
            :type l1: ListNode
            :type l2: ListNode
            :rtype: ListNode
            """
            if not l1:
                return l2
            if not l2:
                return l1
            if l1.val <= l2.val:
                l1.next = self.mergeTwoLists(l1.next, l2)
                return l1
            else:
                l2.next = self.mergeTwoLists(l1, l2.next)
                return l2
    

LC. 160. Intersection of Two Linked Lists

Write a program to find the node at which the intersection of two singly linked lists begins.

Notes:

If the two linked lists have no intersection at all, return null.
The linked lists must retain their original structure after the function returns.
You may assume there are no cycles anywhere in the entire linked structure.
Your code should preferably run in O(n) time and use only O(1) memory.

Solutions

  • 一个超简洁的解法:

    class Solution(object):
        def getIntersectionNode(self, headA, headB):
            """
            :type head1, head1: ListNode
            :rtype: ListNode
            """
            if not headA or not headB:
                return None
            
            a = headA
            b = headB
            while a != b:
                a = headB if a == None else a.next
                b = headA if b == None else b.next
            return a
    
    • 思路是a+b = b+a,如果遍历两遍,他们会同时到达终点,自动对齐

    • 第12行很重要,这和两个链表intersect的方式有关,如果只是一个node的val相同,这个语句是false的。必须后面是同一个链才是true

    • 第12行到14行的另外一种错误写法:

      if a.next == None:
          a.next = headB
      if b.next == None:
          b.next = headA
      a = a.next
      b = b.next
      

      原因是第2/4行会导致链表的终端不指向None,会形成一个环形链表,这样后到达的指针就出不来了!


LC. 141. Linked List Cycle

Given a linked list, determine if it has a cycle in it.

To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Example 1:

Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the second node.

Solutions

  • 一个作弊解法:(which 我觉得肯定有毛病)

    class Solution(object):
        def hasCycle(self, head):
            """
            :type head: ListNode
            :rtype: bool
            """
            marker = ListNode(-1)
            if not head:
                return False
            while head.next and not head.next == marker:
                temp = head.next
                head.next = marker
                head = temp
            if not head.next:
                return False
            return True
    

    走过的点就标记为走过,通过把它指向一个marker点。但这样链表就被损坏了

  • 龟兔赛跑的解法:一个指针以步长1移动,另一个以步长2移动。如果有环的话,fast指针一定会追上另外一个

    class Solution(object):
        def hasCycle(self, head):
            """
            :type head: ListNode
            :rtype: bool
            """
            try:
                slow = head
                fast = head.next
                while not slow == fast:
                    slow = slow.next
                    fast = fast.next.next
                return True
            except:
                return False
    

    这里用try/except的写法写会更快,不必每次显式地检查是否有指针到达终点

class Solution(object):
def insertionSortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head:
return head
helper = ListNode(0)
pre = helper

    while head:
        temp = head.next
        if pre.next and head.val < pre.next.val:
            pre = helper
        while pre.next and head.val >= pre.next.val:
            pre = pre.next
        head.next = pre.next
        pre.next = head
        head = temp
        
    return helper.next

LC. 138 Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.

Solution

  • 交替索引

    class Solution(object):
        def copyRandomList(self, head):
            """
            :type head: Node
            :rtype: Node
            """
            if not head:
                return None
            helper = Node(0, head, None)
            while head.next:
                new = Node(head.val, head.next, head.random)
                head.next = new
                head = head.next.next
            new = Node(head.val, None, head.random)
            head.next = new
            
            new_head = helper.next.next
            while new_head.next:
                new_head.random = None if not new_head.random else new_head.random.next
                new_head = new_head.next.next
            new_head.random = None if not new_head.random else new_head.random.next
                
            head = helper.next
            helper.random = head.next
            new = Node(0, None, None)
            while head.next.next:
                new.next = head.next
                head.next = head.next.next
                new = new.next
                head = head.next
            new.next = head.next
            head.next = None
    
            return helper.random
    
  • keep an hash table for each node in the list: 原链表的每一个node索引到它的copy上,然后再次从头到位遍历原来的链表,写入新结点们的next和random

    class Solution(object):
        def copyRandomList(self, head):
            """
            :type head: Node
            :rtype: Node
            """
            if not head:
                return None
            copy = dict()
            m = n = head
            while m:
                copy[m] = Node(m.val, m.next, m.random)
                m = m.next
            while n:
                copy[n].next = copy.get(n.next)
                copy[n].random = copy.get(n.random)
                n = n.next
            return copy[head]
    

    需要注意的是,在第15/16行都用的是dict.get(key)而不是直接dict[key], 这是为了当key等于None的时候,返回default value None而不是报错。如果事先定义copy[None]=None的话,这两处也可以直接用dict[key]

    这种方法还有一个很trick的只遍历一次的写法,使用collections.defaultdict来访问(及创建)存在(或不存在)的结点

    class Solution(object):
        def copyRandomList(self, head):
            """
            :type head: Node
            :rtype: Node
            """
            copy = collections.defaultdict(lambda: Node(0, None, None))
            m = head
            copy[None] = None
            while m:
                copy[m].val = m.val
                copy[m].next = copy[m.next]
                copy[m].random = copy[m.random]
                m = m.next
            return copy(head)
    

    注意这里的12/13行是直接调用的方式,且在第9行定义了key=None的情况。这是因为现在的default是RandomNode(0)而不是None了


LC. 142 Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Solution

  • hash table that records the visited nodes

    class Solution(object):
        def detectCycle(self, head):
            """
            :type head: ListNode
            :rtype: ListNode
            """
            info = dict()
            m = head
            while m:
                if not info.get(m):
                    info[m] = True
                else:
                    return m
                m = m.next
            return None
    
  • hare-tortoise method

    class Solution(object):
        def detectCycle(self, head):
            """
            :type head: ListNode
            :rtype: ListNode
            """
            fast = slow = helper = head
            try:
                fast = fast.next.next
                slow = slow.next
                while not fast == slow:
                    fast = fast.next.next
                    slow = slow.next
                while not helper == slow:
                    helper = helper.next
                    slow = slow.next
                return helper
            except:
                return None
    

    这里最重要的就是fast步长=2,slow=1。。。这样保证了fast恰好超slow一圈

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 什么是数组? 数组简单来说就是将所有的数据排成一排存放在系统分配的一个内存块上,通过使用特定元素的索引作为数组的下...
    启明_b56f阅读 879评论 0 0
  • <center>#1 Two Sum</center> link Description:Given an arr...
    铛铛铛clark阅读 2,135评论 0 3
  • Python语言特性 1 Python的函数参数传递 看两个如下例子,分析运行结果: 代码一: a = 1 def...
    伊森H阅读 3,043评论 0 15
  • 说来很是惭愧,这半辈子好像都没有坚持很久的事情,每一件都是雄心壮志的开始,最后都是不自信或懒惰而半途而废,想想真是...
    kitty2017阅读 150评论 0 0
  • 如果可以,我愿是你树上的叶,在有生命的岁月里,和你紧相依,把我的色彩写满你的枝,我所有的色彩只为你而亮。 如果可以...
    宁蕤阅读 300评论 0 17