leetcode-链表

链表

第一题

在这里插入图片描述
解法
[边界] - n的取值范围是1-链表长度,边界为n=1和n=链表长度
[思路] - 要求移除倒数第n个,考虑双指针:指针1先移动n+1步,指针2再移动(指针1指向None时,指针2刚好指向倒数第n+1个结点)
[改进] - 对于边界n=链表长度时,指针1移动n+1会报错。在开头定义一个dunmmy结点

解法1

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        p = head
        for _ in range(n+1):
            if not p:    # 边界-正数第一个结点
                return head.next
            p = p.next

        q = head
        while p:
            p = p.next
            q = q.next
        q.next = q.next.next

        return head

改进: 开头定义一个dummy结点

class Solution(object):
    def removeNthFromEnd(self, head, n):
        dummy = ListNode(-1)
        dummy.next = head

        p = dummy
        for _ in range(n+1):
            p = p.next

        q = dummy
        while p:
            p = p.next
            q = q.next
        q.next = q.next.next

        return dummy.next


第二题

在这里插入图片描述

解法 看到链表题,想到递归。 刚开始想用非递归写,发现有点绕。 [解法1] - 递归解法 [解法2] - 非递归,参照递归的思想

解法1 递归,截止条件-链表为空/只有一个元素。判断head和head.next是否相等,若相等,递归操作head.next;否则, 返回head

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

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

解法2 非递归,将递归改造成非递归。外面套一层while, 内部p = p.next. 为代码简洁起见,引入dummy指针pNode

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def deleteDuplicates(self, head):
        if not head or not head.next:
            return head
            
        pNode = ListNode(-1)
        pHead = pNode
        p = head
        while p:
            while p.next and p.val == p.next.val:
                p = p.next
            pNode.next = p
            pNode = pNode.next
            p = p.next
        return pHead.next

第三题

206. Reverse Linked List
在这里插入图片描述

解法1

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        node = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return node
解法2 非递归解法,定义两个指针

class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        pre = None
        cur = head
        while cur:
            temp = cur.next
            cur.next = pre
            pre, cur = cur, temp
        return pre

第四题

92. Reverse Linked List II

在这里插入图片描述

思路 开始写的时候发现很麻烦,好几个特殊用例(比如m=1)要考虑。所以考虑加一个dummy结点。
 把要翻转的一段先进行翻转,再把它和前后的链表接起来

解法

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def reverseBetween(self, head, m, n):
        """
        :type head: ListNode
        :type m: int
        :type n: int
        :rtype: ListNode
        """
        dummy = ListNode(-1)
        dummy.next = head
        
        node = dummy
        for _ in range(m-1):
            node = node.next
            
        pre = node.next
        cur = pre.next
        for _ in range(n-m):
            temp = cur.next
            cur.next = pre
            pre, cur = cur, temp
            
        # 先和后面串起来
        node.next.next = cur
        node.next = pre
        return dummy.next
我们可以看出来,总共需要n-m步即可,
第一步是将结点3放到结点1的后面,
第二步将结点4放到结点1的后面。这是很有规律的操作,那么我们就说一个就行了,比如刚开始,pre指向结点1,cur指向结点2,
然后我们建立一个临时的结点t,指向结点3(注意我们用临时变量保存某个结点就是为了首先断开该结点和前面结点之间的联系,
这可以当作一个规律记下来),然后我们断开结点2和结点3,将结点2next连到结点4上,也就是 cur->next = t->next,
再把结点3连到结点1的后面结点(即结点2)的前面,即 t->next = pre->next,最后再将原来的结点1和结点2的连接断开,
将结点1连到结点3,即 pre->next = t。这样我们就完成了将结点3取出,加入结点1的后方。
第二步将结点4取出,加入结点1的后方,也是同样的操作,这里就不多说了,请大家自己尝试下吧,参见代码如下:

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

class Solution(object):
    def reverseBetween(self, head, m, n):
        """
        :type head: ListNode
        :type m: int
        :type n: int
        :rtype: ListNode
        """
        if m == n or not head:
            return head
        dummy = ListNode(0)
        dummy.next = head
        prev = dummy
        for i in range(m - 1):
            prev = prev.next 
        #prev record the node before reverse substring
        st, then = prev.next, prev.next.next
        for i in range(n - m):
            st.next = then.next #
            then.next = prev.next 
            prev.next = then #this step will correctly reconnect substring
            then = st.next

        return dummy.next



第五题

61. Rotate List

在这里插入图片描述

解法

第一次遍历,记录链表长度size
有k%size个结点翻转到了前面
解法 记录长度,两次遍历 - (先把链表连成环)
① 第一次遍历时通过tail把链表变成了环 (尾节点指向头节点)
② 第二次遍历长度为size-k-1,遍历结束后p指向不需要反转部分的最后一个节点
③ 因为最后return 反转后链表的头节点(比如题目中的例子,就是返回头节点4开头的链表)    
----后三行代码
node=p.next    用来记录然后return
p.next=None(题目中的例子为例,反转后尾节点是3;如果没有这句话,节点3是指向4的)
return node(return 4# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def rotateRight(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        
        # Mark size and tail
        size = 1
        tail = head
        while tail.next:
            tail = tail.next
            size += 1
        tail.next = head
        
        # Rotate
        k = k % size
        p = head
        for _ in range(size-k-1):
            p = p.next
        node = p.next
        p.next = None
        return node    

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def rotateRight(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        if not head or k==0:
            return head
        
        size=0;
        tmp=ListNode(0)
        tmp.next=head
        cur=tmp
        while cur.next:
            size+=1
            cur=cur.next
        #此时cur指向最后一个结点,这里先和head接上,变成一个环
        cur.next=head
        #找到新的头结点的前一个结点,摘链
        for i in range(size-k%size):
            cur=cur.next
        #此时cur指向新的头结点的前一个结点
        new_head=cur.next
        #摘链
        cur.next=None
        return new_head

第六题

[143. Reorder List(https://leetcode.com/problems/reorder-list)
在这里插入图片描述
题目思路是把链表拆成两个长度相等的链表,然后将后面的链表翻转,重新连起来。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reorderList(self, head: ListNode) -> None:
        """
        Do not return anything, modify head in-place instead.
        """
        if not head or not head.next or not head.next.next:
            return 
        slow=fast=head
        while fast.next and fast.next.next:
            slow=slow.next
            fast=fast.next.next
        node1=head
        node2=slow.next
        slow.next=None
        
        dummy=ListNode(-1)
        dummy.next=node2
        p=node2.next
        node2.next=None
        while p:
            temp=p
            p=p.next
            temp.next=dummy.next
            dummy.next=temp
        node2=dummy.next
        
        p1=node1
        p2=node2
        while p2:
            temp1=p1.next
            temp2=p2.next
            p1.next=p2
            p2.next=temp1
            p1=temp1
            p2=temp2


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reorderList(self, head: ListNode) -> None:
        """
        Do not return anything, modify head in-place instead.
        """
        if not head or not head.next or not head.next.next:
            return 
        slow=fast=head
        while fast.next and fast.next.next:
            slow=slow.next
            fast=fast.next.next
        node1=head
        node2=slow.next
        slow.next=None
        
        node2=self.reverseList(node2)
        
        
        p1=node1
        p2=node2
        while p2:
            temp1=p1.next
            temp2=p2.next
            p1.next=p2
            p2.next=temp1
            p1=temp1
            p2=temp2
            
    def reverseList(self,head):
        pre=None
        cur=head
        while cur:
            temp=cur.next
            cur.next=pre
            pre,cur=cur,temp
        return pre
            

第七题

21. Merge Two Sorted Lists
在这里插入图片描述

解法 法1 - 非递归,逐次比较 法2 - 递归

解法1 非递归
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        dummy=ListNode(-1)
        p=dummy
        while l1 and l2:
            if l1.val<l2.val:
                p.next=l1
                l1=l1.next
            else:
                p.next=l2
                l2=l2.next
            #融合后链表的下一位,当前位置刚刚赋值
            p=p.next
        #把剩余的链表排在后面
        p.next=l1 or l2
        #返回融合后链表从第二个对象开始,第一个对象是自己创建的ListNode(-1)
        return dummy.next
解法2 递归

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

第八题

160. Intersection of Two Linked Lists

在这里插入图片描述

解法 1) 可以从尾部遍历链表就好了(当然不可能) 2) 知道两个链表的长度差,
长链表的先走几步就好了 我们可以用两个指针分别遍历两个链表,当其中一个为空时,
令其指向另一个链表的头部(类似长度差)
 		p= headA
        q = headB
        
        lenA=lenB=0
        while p:
            p= p.next
            lenA +=1
        while q:
            q= q.next
            lenB +=1
        
        p=headA
        q= headB
        if lenA>lenB:
            for i in range(lenA-lenB):
                p= p.next
          
        else:
            for i in range(lenB-lenA):
                q= q.next
        while p!=q:
            p=p.next
            q= q.next
            
        return p
            



假如长度不一致(比如例子),那短链表会先遍历完,然后会指向长链表的头。
而长的遍历完一次,继续向下则指向短链表的头。这时候,他们会同时到达相等的节点(如果没有就一起遍历到结束)。
也就是(长链表+短链表)的长度等于(短链表+长链表)的长度。所以有相同节点时候会遇到。很神奇!
 p和q是两个指针。跳出while循环有两种方式,一个是两个链表都遍历完了,另一个是找到共同节点。
解法

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        p1 = headA
        p2 = headB
        while p1 != p2:
            if p1:
                p1 = p1.next
            else:
                p1 = headB
            if p2:
                p2 = p2.next
            else:
                p2 = headA
        return p1

第九题

141. Linked List Cycle

在这里插入图片描述

创建两个节点,第一个慢节点单步走,第二个快节点两步走,如果没有环,则快节点会首先走到链表尾,退出循环,返回False。如果存在环,则快节点会再第二圈或者第n圈的地方追上慢节点,直到两者相等,则返回True
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

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

第十题

147. Insertion Sort List

在这里插入图片描述

解题思路:
设置一个dummy头结点,然后将原链表中的节点一个个拆下来,按升序拼接到新的链表中。
优化)可以根据尾节点进行优化,如果要插入的节点比尾节点还大的话,就不用从头开始找插入的位置了。
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def insertionSortList(self, head: ListNode) -> ListNode:
        
        dummy = ListNode(-1)
        tail = dummy
        while head:
            # First check the tail node, if tail.val > head.val ——> reset
            if tail and tail.val > head.val:
                tail = dummy
            while tail.next and tail.next.val < head.val:
                tail = tail.next
            # Insert
            tail.next, head.next, head = head, tail.next, head.next
        return dummy.next

        

第十一题

138. Copy List with Random Pointer
题目描述

给定一链表 - 每个结点包含一个额外的random指针,指向任何链表中的结点或None。 返回链表的深拷贝。

例子

思想 两种解法。难点在于如何定位random指针。 法1 - 首先复制next指针,将其复制到已知链表的next后面;这样待求链表的random指向的结点 = 已知链表的random指向的结点的next。 法2 - 建立已知链表和待求链表相应结点的一个hash。

"""
# Definition for a Node.
class Node:
    def __init__(self, val, next, random):
        self.val = val
        self.next = next
        self.random = random
"""
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if head is None:
            return None
        
        #add clones to the chain
        n = head
        while n:
            clone = Node(n.val,None,None)
            next_node = n.next
            clone.next = next_node
            n.next = clone
            n = clone.next
        
        #update random pointers
        n = head
        while n:
            clone = n.next
            if n.random:
                clone.random = n.random.next
            n = clone.next
        
        #extract clones & restore original chain
        n = head
        res = Node(0,None,None)
        clone_head = res
        while n:
            next_original_node = n.next.next
            
            #extract clones
            clone = n.next
            clone_head.next = clone
            
            #restore original chain
            n.next = next_original_node
            
            # move forward
            n = next_original_node
            clone_head = clone_head.next
            
        
        return res.next

第十二题

142. Linked List Cycle II
题目描述

给定单链表,返回链表中环的起始结点。如果没有环,返回None。

思路:快慢指针相遇点到环入口的距离 = 链表起始点到环入口的距离 
- 求环的长度 
先判断是否是环。假设环长为L,不是环的长度为M,在环中的N处相遇。
那么fast走了M+K1L+N,slow走了M+K2L+N。fast=2slow,M+K1L+N=2*(M+K2*L+N),N=(K1-K2)*L-M。
可以看到从N出发再走M就到了环的起始点。


# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return None
        slow=fast=head
        while fast and fast.next:
            slow=slow.next
            fast=fast.next.next
            if slow==fast:
                fast=head
                while slow!=fast:
                    slow=slow.next
                    fast=fast.next
                return slow
        return None
                    

第十三题

148. Sort List
题目描述

链表排序,要求时间复杂度O(nlogn),空间复杂度O(1)

例子 Example 1:

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

Example 2:

Input: -1->5->3->4->0 Output: -1->0->3->4->5

思想 联想几个时间复杂度O(nlogn)的排序:堆排序(麻烦),快排(要移位,还要交换),归并排序(找中点,可以用快慢指针找中点)
class Solution(object):
    def sortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head or not head.next:
            return head
        fast = slow = pre = head
        while fast and fast.next:    # Mark: pre
            pre = slow
            slow = slow.next
            fast = fast.next.next
        pre.next = None
        
        left = self.sortList(head)
        right = self.sortList(slow)
        return self.merge(left, right)
        
    def merge(self, left, right):
        dummy = ListNode(-1)
        p = dummy
        while left and right:
            if left.val < right.val:
                p.next = left
                left = left.next
            else:
                p.next = right
                right = right.next
            p = p.next
        if left:
            p.next = left
        else:
            p.next = right
        return dummy.next

第十四题

146. LRU Cache

题目描述

设计一种LRU的数据结构,支持下面两个操作:get和put。 get(key) - 如果key在缓存中,返回key对应的value(总是正数),否则返回-1 put(key, value) - 设置值;如果key不存在,插入值。当缓存达到容量时,它应该在插入新项前使最近最少使用的项无效。 最好O(1)的时间复杂度
如果一个数据长时间没有使用,且又有新的数据加入,那么应该将最长时间没有使用的数据去除

思想 首先,涉及查询,考虑用字典来存储。 难点 - 如何找到哪个节点最久没被使用? 定义一个双向链表,尾部的节点最久没被使用。每次访问某节点时,删除该节点,并把该节点放在头部。

注意双向链表的head和tail没有数据。

解法 双向链表的插入和删除

class LRUCache(object):
    class Node(object):
        def __init__(self, key, value):
            self.key = key
            self.value = value
            self.next, self.prev = None, None

    def __init__(self, capacity):
        """
        :type capacity: int
        """
        self.capacity = capacity
        self.size = 0
        self.dic = {}    # self.dic[key] = Node(key, value)
        self.head, self.tail = self.Node(-1,-1) , self.Node(-1,-1)
        self.head.next, self.tail.prev = self.tail, self.head
    
    def removeNode(self, node):
        node.prev.next = node.next
        node.next.prev = node.prev
        node.prev, node.next = None, None
        
    def insertNode(self, node):
        node.prev = self.head
        node.next = self.head.next
        self.head.next.prev, self.head.next = node, node

    def get(self, key):
        """
        :type key: int
        :rtype: int
        """
        if key not in self.dic:
            return -1
        else:
            node = self.dic[key]
            self.removeNode(node)
            self.insertNode(node)
            return node.value

    def put(self, key, value):
        """
        :type key: int
        :type value: int
        :rtype: void
        """
        if key in self.dic:
            node = self.dic[key]
            self.removeNode(node)
            self.insertNode(node)
            node.value = value
        else:
            # Remove the tailest node
            if self.size == self.capacity:
                remove = self.tail.prev
                self.removeNode(remove)
                del self.dic[remove.key]
                self.size -= 1
            # Insert the headest node
            node = self.Node(key, value)
            self.insertNode(node)
            self.dic[key] = node
            self.size += 1

双向链表

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。


class Node():
    def __init__(self,data=None):
        self.data=data
        self.pre=None
        self.next=None
"""
初始化双向链表
"""
def __init__(self):
    head=Node()
    tail=Node()
    self.head=head
    self.tail=tail
    self.head.next=self.tail
    self.tail.pre=self.head
def __len__(self):
    length=0
    node=self.head
    while node.next!=self.tail:
        length+=1
        node=node.next
    return length
def append(self,data):
    node=Node(data)
    pre=self.tail.pre
    pre.next=node
    node.pre=pre
    self.tail.pre=node
    node.next=self.tail
    return node
def get(self,index):
    length=len(self)
    if index>=0:
        index=index
    else:
        index=length+index
    if index>=length or index<0:
        return None
    node=self.head.next
    while index:
        node=node.next
        index-=1
    return node
def set(self,index,data):
    node=self.get(index)
    if node:
        node.data=data
    return node
def insert(self,index,data):
    length=len(self)
    if abs(index+1)>length:
        return False
    index =index if index>=0 else index+1+length
    next_node=self.get(index)
    if next_node:
        node=Node(data)
        pre_node=next_node.pre
        pre_node.next=node
        node.pre=pre_node
        node.next=next_node
        next_node.pre=node
        return node
def delete(self, index):
    node = self.get(index)
    if node:
        node.pre.next = node.next
        node.next.pre = node.pre
        return True

    return False

def clear(self):
    self.head.next = self.tail
    self.tail.pre = self.head
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值