Python数据结构与算法分类练习--链表

在有些情况下,存储数据的内存分配不能位于连续的内存块中。 通过指针将其中数据和数据元素的下一个位置的地址都存储起来,这样从当前数据元素的值中就知道下一个数据元素的地址。通常这样的结构被称为指针,而在Python中称为节点。

class Node(object):
    def __init__(self, x):
        self.data = x
        self.next = None

把一系列节点通过链接(next)连接在一起就组成了链表。 根据结构的不同,链表可以分为单向链表、单向循环链表、双向链表、双向循环链表等。下面是链表相关题型的分析和解答。

链表逆序

Reverse Linked List II(翻转列表指定范围)

for循环中的图示:

class Solution(object):
    def reverseBetween(self, head, m, n):
        dummy = ListNode(0)
        dummy.next = head
        curr = dummy
        for i in range(1, m):
            curr = curr.next
            
        tail = curr.next
        for i in range(m, n):
            if tail is None:
                break
            tmp = tail.next
            tail.next = tmp.next
            tmp.next = curr.next # not tail
            curr.next = tmp
            
        return dummy.next

Reverse Linked List(翻转整个链表)

while循环中的图示:

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

求两个链表的交点

Intersection of Two Linked Lists

分别遍历两个链表,得到分别对应的长度。然后求长度的差值,把较长的那个链表向后移动这个差值的个数,然后一一比较即可。

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        if not headA or not headB:
            return None
        countA = countB = 0
        currA, currB = headA, headB

        while currA:
            countA += 1
            currA = currA.next
        while currB:
            countB += 1
            currB = currB.next
        currA = headA
        currB = headB
        if countA > countB:
            for i in range(countA - countB):
                currA = currA.next
        elif countB > countA:
            for i in range(countB - countA):
                currB = currB.next
        
        while currA != currB: 
            currA = currA.next
            currB = currB.next
        return currA

成对交换链表的节点

Swap Nodes in Pairs

Given 1->2->3->4, you should return the list as 2->1->4->3.

while循环中的图示:

class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        curr = dummy = ListNode(0)
        dummy.next = head
        
        while curr.next and curr.next.next:
            node1, node2, node3 = curr.next, curr.next.next, curr.next.next.next
            curr.next = node2
            node2.next = node1
            node1.next = node3
            curr = node1
        return dummy.next

包含环的链表

Linked List Cycle(是否有环)

只需要设两个指针,一个每次走一步的慢指针和一个每次走两步的快指针,如果链表里有环的话,两个指针最终肯定会相遇。

class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        if head == None or head.next == None:
            return False
        fast = slow = head
        while fast and fast.next:# first fast can avoid AttributeError
            fast = fast.next.next
            slow = slow.next
            if fast is slow:
                return True
        return False

Linked List Cycle II(求环起始节点)

还是设置两个快慢指针,当两个指针相遇了后,让其中一个指针回到链表起始位置,快慢支针保持同步重新走,此时再相遇的位置就是链表中环的起始位置。

设m为表头到环起始点的距离,n为相遇时走过环起始点的距离,c为环的周长,a为正整数。那么有:

l_fast=m+n+a*c=2*l_slow

l_slow=m+n

=>m+n=a*c

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

链表划分

Partition List

Given 1->4->3->2->5->2 and x = 3,

return 1->2->2->4->3->5.

解法一:首先找到第一个大于或等于给定值的节点(4),然后再找小于给定值的节点,每找到一个就将其取出置于4之前即可。

解法二:将所有小于给定值的节点取出组成一个新的链表,此时原链表中剩余的节点的值都大于或等于给定值,只要将原链表直接接在新链表后即可。下面是解法二的实现:

def partition(self, head, x):
    h1 = l1 = ListNode(0)
    h2 = l2 = ListNode(0)
    while head:
        if head.val < x:
            l1.next = head
            l1 = l1.next
        else:
            l2.next = head
            l2 = l2.next
        head = head.next
    l2.next = None
    l1.next = h2.next
    return h1.next

复杂的链表复制

Copy List with Random Pointer

# Definition for singly-linked list with a random pointer.
# class RandomListNode(object):
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None

分三步进行:

1. 在原链表的每个节点后面拷贝出一个新的节点

2. 依次给新的节点的随机指针赋值:cur.next.random = cur.random.next

3. 断开链表可得到深度拷贝后的新链表

class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: RandomListNode
        :rtype: RandomListNode
        """
        # copy and combine copied list with original list
        cur = head
        while cur:
            copy = RandomListNode(cur.label)
            copy.next = cur.next
            cur.next = copy
            cur = copy.next
        # update random node in copied list    
        cur = head
        while cur:
            if cur.random:
                cur.next.random = cur.random.next
            cur = cur.next.next
        # split copied list from combined one
        dummy = RandomListNode(0)
        cur, copy_cur = head, dummy
        while cur:
            copy_cur.next = cur.next
            cur.next = cur.next.next
            copy_cur, cur = copy_cur.next, cur.next
        return dummy.next

合并链表(2个与多个) 

Merge Two Sorted Lists

新建一个链表,然后比较两个链表中的元素值,把较小的那个链到新链表中,由于两个输入链表的长度可能不同,所以最终会有一个链表先完成插入所有元素,则直接另一个未完成的链表直接链入新链表的末尾。

class Solution(object):
    def mergeTwoLists(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        init = out = ListNode(0)
        while l1 and l2:
            if l1.val < l2.val:
                out.next = l1
                l1 = l1.next
            else:
                out.next = l2
                l2 = l2.next
            out = out.next
        out.next = l1 or l2
        return init.next

Merge k Sorted Lists

解法一:利用mergeTwoLists进行两两合并。

解法二:把k个链表放入列表中排序,依次取出组成新的链表

class Solution(object):
    def mergeKLists(self, lists):
        def mergeTwoLists(L1,L2):
            pass
        if not lists:
            return None
        left, right = 0, len(lists)-1
        while right > 0:
            if left >= right:
                left = 0
            else:
                list[left] = mergeTwoLists(list[left],list[right])
                left += 1
                right -= 1
        return lists[0]

    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        values=[]
        for list1 in lists:
            while list1:
                values.append(list1.val)
                list1=list1.next
        values.sort()
        result=head=ListNode('')
        for i in values:
            head.next=ListNode(i)
            head=head.next 
        return result.next

猜你喜欢

转载自blog.csdn.net/ZJL0105/article/details/81194885