Leetcode刷题第二周--链表

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:给定的 n 保证是有效的。
进阶:你能尝试使用一趟扫描实现吗?

解题说明:
注意,这个题有可能删除头结点,所以首先创建一个虚拟节点,虚拟节点的好处就是头结点可能被删掉,而虚拟节点不会被删掉。

方法一:先得到整个列表的长度,注意考虑一些极端情况的出现,比如删除元素位于链表的开头或者结尾,亦或是不存在的情况。然后开始第二轮遍历,遍历到length-n的位置的时候调过下一个目标,去到下下一个目标。

只扫描一次的情况
方法二:双指针算法

  1. 创建虚拟指针,
  2. 采用两个指针,一个先走n步,
  3. 然后第二个和第一个一起走,当第一个走完的时候,第二个刚好走到倒数第n的位置,
  4. 然后慢指针跳过下一个位置。
# method 1
class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        # get the length of list
        length = 0
        tmp = head
        while tmp:
            tmp = tmp.next
            length += 1

        # exceptions
        if length == n:
            return head.next
        if length == 0:
            return 
        if length - n < 0:
            return head

        i = 1
        cur_node = head
        while cur_node:
            if i == length - n:             
                cur_node.next = cur_node.next.next  
            else:
                cur_node = cur_node.next            
            i += 1

        return head 

# method 2
class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        # 采用悬挂指针的方式
        prehead = ListNode(0)  
        prehead.next = head
        fast_cur = slow_cur = prehead

        i = 0
        #注意在这里控制极端情况的发生
        while i <=n and fast_cur:
            fast_cur = fast_cur.next
            i += 1

        while fast_cur:
            fast_cur = fast_cur.next
            slow_cur = slow_cur.next

        slow_cur.next = slow_cur.next.next
        return prehead.next

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 -- head = [4,5,1,9],它可以表示为:


图片.png

输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

解题思路:
由于删除的点不是尾结点,所以可以伪装成下一个点,然后删除下一个点

# 解法一
class Solution(object):
    def deleteNode(self, node):
        """
        :type node: ListNode
        :rtype: void Do not return anything, modify node in-place instead.
        """
        node.val = node.next.val
        node.next = node.next.next

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例 1:
输入: 1->1->2
输出: 1->2

解题思路:注意是排序链表,分为两种情况:如果下一个点和当前点相似,则删掉下一个点;否则指针移动到下一个点。因此只需要扫描一遍。

class Solution(object):
    def deleteDuplicates(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        cur = head
        while cur:
            if cur.next and cur.val == cur.next.val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return head  

Leetcode 61. 旋转链表

给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL

解题说明:

  1. 先让k对n取模;
  2. 可以采用双指针的做法,得到最后一个点和倒数第n+1个点的位置(注意不需要创建虚拟头结点了);
  3. 改变头结点和尾结点为位置。
class Solution(object):
    def rotateRight(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        # exception
        if head == None:
            return 
        
        # get the length of list
        n = 0
        cur = head
        while cur:
            cur = cur.next
            n += 1
        k = k%n
        
        # fast and slow cur
        fast = slow = head
        i = 1
        while i<=k:
            fast = fast.next
            i += 1
        while fast.next:
            fast = fast.next
            slow = slow.next
            
        # change the head and tail
        fast.next = head
        head = slow.next
        slow.next = None
        
        return head

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.

解题思路:
p为虚拟节点, 第一步p指向b,第二步a指向3,第三步b指向a,第四步p移动到a。这样就完成了一个循环。

图片.png
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head == None:
            return 
        p = ListNode(0)
        p.next = head
        cur = p
        
        while p.next and p.next.next:
            a = p.next
            b = a.next
            p.next = b
            a.next = b.next
            b.next = a
            p = a
        return cur.next

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

解题思路:


图片.png
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head == None:
            return 
        
        a = head
        b = a.next
        
        while b:
            c = b.next
            b.next = a
            a = b
            b = c
        head.next = None
        
        return a

反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。
说明:
1 ≤ m ≤ n ≤ 链表长度。
示例:
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

解题思路:


图片.png
class Solution(object):
    def reverseBetween(self, head, m, n):
        """
        :type head: ListNode
        :type m: int
        :type n: int
        :rtype: ListNode
        """
        if head == None or head.next == None or m >= n or m < 0 or n < 0:
            return head

        # virtual node
        prehead = ListNode(0)
        prehead.next = head
        
        # get the position before m and n
        t1 = prehead
        t2 = prehead
        i = 0
        j = 0
        while i < m-1:
            t1 = t1.next
            i += 1
        while j < n:
            t2 = t2.next
            j += 1
            
        # reverse
        a = t1.next
        b = t2.next
        
        p = a
        q = a.next

        while q != b:
            o = q.next
            q.next = p
            p = q
            q = o
            
        # connect the reversed chain 
        t1.next = p
        a.next = b
        
        return head

Leetcode 92. 相交链表

编写一个程序,找到两个单链表相交的起始节点。
如下面的两个链表
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。在节点 c1 开始相交。

解题思路:


图片.png
class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        p = headA
        q = headB
        
        while(p!=q):
            if p:
                p = p.next
            else:
                p = headB
            if q:
                q = q.next
            else:
                q = headA
        return p

Leetcode 142. 环形链表

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。

解题思路:
(链表,快慢指针扫描) O(n)
本题的做法比较巧妙。用两个指针 first,second分别从起点开始走,first 每次走一步,second 每次走两步。如果过程中 second 走到null,则说明不存在环。否则当 first 和 second 相遇后,让 first 返回起点,second待在原地不动,然后两个指针每次分别走一步,当相遇时,相遇点就是环的入口。


图片.png

证明:如上图所示,a
是起点,b 是环的入口,c 是两个指针的第一次相遇点,ab 之间的距离是 x,bc 之间的距离是 y。则当 first 走到 b 时,由于 second 比 first 多走一倍的路,所以 second 已经从 b 开始在环上走了 x 步,可能多余1圈,距离 b 还差 y 步(这是因为第一次相遇点在 b 之后 y 步,我们让 first 退回 b 点,则 second 会退 2y 步,也就是距离 b 点还差 y 步);所以 second 从 b 点走 x+y 步即可回到 b 点,所以 second 从 c 点开始走,走 x 步即可恰好走到 b 点,同时让 first 从头开始走,走 x 步也恰好可以走到 b 点。所以第二次相遇点就是 b 点。

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

推荐阅读更多精彩内容