链表

补充:

1、哨兵节点

在某些实现中,可能会在第一个数据记录之前,或者最后一个数据记录之后添加 一个额外的哨兵节点或者哑元节点。 简化和加快一些列表处理的算法 。

2、对比

链表vs.动态数组

都需要动态分配内存块

动态数组: 通过索引访问和分配非常快速,时间复杂度为O(1)

添加元素(插入到数组的末尾)相对比较快,平摊时间复杂度为O(1)

在动态数组里的任意位置添加和删除节点会很慢,时间复杂度为O(n)

当需要对插入和删除做调整时,可能会出现不可预知的表现。 会有一些未使用的空间

链表: 在列表中的任意位置做插入和删除都很快,时间复杂度为O(1)

索引访问(随机访问)慢,时间复杂度为O(n)

 一、实现

class Node:
    def __init__ (self, value = None, next = None):
        self.value = value
        self.next = next

class LinkedList:
    def __init__(self):
        self.head = Node()
        self.tail = None
        self.length = 0

    def peek(self):
        if not self.head.next:
            raise Empty( 'LinkedList is empty' )
        return self.head.next

    def get_first(self):
        if not self.head.next:
            raise Empty( 'LinkedList is empty' )
        return self.head.next
        
    def get_last(self):
        if not self.head.next:
            raise Empty( 'LinkedList is empty' )
        node = self.head
        while node.next != None:
            node = node.next
        return node
    
    def get(self, index):
        if (index < 0 or index >= self.length):
            raise Outbound( 'index is out of bound' );
        if not self.head.next:
            raise Empty( 'LinkedList is empty' )
        node = self.head.next
        for i in range(index):
            node = node.next
        return node
                
    def add_first(self, value):
        node = Node(value, None)
        node.next = self.head.next
        self.head.next = node
        self.length += 1   
        
    def add_last(self, value):
        new_node = Node(value)
        node = self.head
        while node.next != None:
            node = node.next
        node.next = new_node
        self.length += 1

    def add(self, index, value):
        if (index < 0 or index > self.length):
            raise Outbound( 'index is out of bound' )
        if not self.head.next:
            raise Empty( 'LinkedList is empty' )
        new_node = Node(value)
        node = self.head
        for i in range(index):
            node = node.next
        new_node.next = node.next;
        node.next = new_node;
        self.length += 1     
        
    def remove_first(self):
        if not self.head.next:
            raise Empty( 'LinkedList is empty' )
        value = self.head.next
        self.head.next = self.head.next.next
        self.length -= 1
        return value    
        
    def remove_last(self):
        if not self.head.next:
            raise Empty( 'LinkedList is empty' )
        node = self.head.next
        prev = self.head
        while node.next != None:
            prev = node
            node = node.next
        prev.next = None
        return node.value

    def remove(self, index):
        if (index < 0 or index >= self.length):
            raise Outbound( 'index is out of bound' );
        if not self.head.next:
            raise Empty( 'LinkedList is empty' )
        node = self.head
        for i in range(index):
            node = node.next
        result = node.next;
        node.next = node.next.next;
        self.length += 1     
        return result;      
        
    def printlist(self):
        node = self.head.next
        count = 0
        while node and count<20:
            print(node.value, end = " ")
            node = node.next
            count = count + 1
        print('')

二、找到中间节点

方法:快慢指针

def find_middle(lst):
    assert lst.head is not None and lst.head.next is not None
    
    head = lst.head
    fast = head
    slow = head
    
    while fast is not None and fast.next is not None:
        fast = fast.next.next
        slow = slow.next
    
    return slow.value

三、判断一个链表是否有环

方法:快慢指针

def has_cycle(lst):
    return has_cycle_helper(lst.head)

def has_cycle_helper(head):
    if head is None:
        return False
    
    slow = head 
    fast = head
    
    while fast is not None and fast.next is not None:
        fast = fast.next.next
        slow = slow.next
        
        if slow==fast:
            return True
        
    return False

四、寻找循环链表开始节点

方法:快慢指针

def find_beginning(head):
    if head is None:
        return None
    
    slow = head
    fast = head
    
    while fast is not None and fast.next is not None:
        fast = fast.next.next
        slow = slow.next
        
        if slow==fast:
            fast = head
            break
        
    if fast is None or fast.next is None:
        return None
    
    while fast != slow:
        fast = fast.next
        slow = slow.next

    return slow

五、删除链表中的倒数第N个节点 

方法:快慢指针 

def remove_nth(lst, n):
    assert n<=lst.length and n > 0
    
    fast = lst.head
    while n>0:
        fast = fast.next
        n = n - 1
        
    slow = lst.head
    while fast.next is not None:
        fast = fast.next
        slow = slow.next
        
    result = slow.next
    slow.next = slow.next.next
    
    lst.length = lst.length - 1
        
    return result

六、将一个链表平分为两部分

方法:快慢指针

def split(head):
    if (head is None):
        return
    slow = head
    fast = head
    front_last_node = slow
    while (fast is not None):
        front_last_node = slow
        slow = slow.next
        fast = fast.next.next if fast.next is not None else None
    front_last_node.next = None
    front = head
    back = slow
    return (front, back)

七、合并两个有序链表

方法:双指针

# O(m + n)
def mergeTwoLists1(l1, l2):
    dummy = cur = Node(0)
    while l1 and l2:
        if l1.value < l2.value:
            cur.next = l1
            l1 = l1.next
        else:
            cur.next = l2
            l2 = l2.next
        cur = cur.next
    cur.next = l1 or l2
    return dummy.next

递归:

# recursively    
def mergeTwoLists2(l1, l2):
    if not l1 or not l2:
        return l1 or l2
    if l1.value < l2.value:
        l1.next = mergeTwoLists2(l1.next, l2)
        return l1
    else:
        l2.next = mergeTwoLists2(l1, l2.next)
        return l2

八、找到两个相交链表的交点

方法:双指针

方法一:

def getIntersectionNode(headA, headB):
    curA, curB = headA, headB
    lenA, lenB = 0, 0
    while curA is not None:
        lenA += 1
        curA = curA.next
    while curB is not None:
        lenB += 1
        curB = curB.next
    curA, curB = headA, headB
    if lenA > lenB:
        for i in range(lenA-lenB):
            curA = curA.next
    elif lenB > lenA:
        for i in range(lenB-lenA):
            curB = curB.next
    while curB != curA:
        curB = curB.next
        curA = curA.next
    return curA

方法二:

def getIntersectionNode2(headA, headB):
    if headA and headB:
        A, B = headA, headB
        while A!=B:
            A = A.next if A else headB
            B = B.next if B else headA
        return A

九、链表插入排序

def insertionSortList(head):
    dummy = Node(0)
    cur = head
    # pre is the sorted part
    # when see a new node, start from dummy
    # cur is the unsorted part
    while cur is not None:
        pre = dummy
        while pre.next is not None and pre.next.value < cur.value:
            pre = pre.next
        temp = cur.next
        cur.next = pre.next
        pre.next = cur
        cur = temp
    return dummy.next

十、链表排序,要求时间O(nlogn),空间O(1)

方法:归并排序

def sortList(head):
    if head is None or head.next is None:
        return head
    mid = getMiddle(head)
    rHead = mid.next
    mid.next = None
    return merge(sortList(head), sortList(rHead))

def merge(lHead, rHead):
    dummyNode = dummyHead = Node(0)
    while lHead and rHead:
        if lHead.value < rHead.value:
            dummyHead.next = lHead
            lHead = lHead.next
        else:
            dummyHead.next = rHead
            rHead = rHead.next
        dummyHead = dummyHead.next
    if lHead:
        dummyHead.next = lHead
    elif rHead:
        dummyHead.next = rHead
    return dummyNode.next

def getMiddle(head):
    if head is None:
        return head
    slow = head
    fast = head
    while fast.next and fast.next.next:
        slow = slow.next
        fast = fast.next.next
    return slow

十一、分区链表partition

def partition(head, x):
    left_head = Node(None)  # head of the list with nodes values < x
    right_head = Node(None)  # head of the list with nodes values >= x
    left = left_head  # attach here nodes with values < x
    right = right_head  # attach here nodes with values >= x
    # traverse the list and attach current node to left or right nodes
    while head:
        if head.value < x:
            left.next = head
            left = left.next
        else:  # head.val >= x
            right.next = head
            right = right.next
        head = head.next
    right.next = None  # set tail of the right list to None
    left.next = right_head.next  # attach left list to the right
    return left_head.next  # head of a new partitioned list

十二、反转链表

def reverse(lst):
    head = lst.head
    result = None
    current = head.next
    nxt = None
    
    while current is not None:
        nxt = current.next
        current.next = result
        result = current
        current = nxt
        
    head.next = result

递归:

def reverseRecursion(node):
    if (node is None or node.next is None):
        return node
    p = reverseRecursion(node.next)
    node.next.next = node
    node.next = None
    return p

十三、从位置m到位置n反转链表

def reverseBetween(head, m, n):
    if m == n:
        return head

    dummyNode = Node(0)
    dummyNode.next = head
    pre = dummyNode

    for i in range(m - 1):
        pre = pre.next

    # reverse the [m, n] nodes
    result = None
    current = pre.next
    for i in range(n - m + 1):
        nxt = current.next
        current.next = result
        result = current
        current = nxt

    pre.next.next = current
    pre.next = result

    return dummyNode.next

十四、成对交换节点

def swapPairs(head):
    dummy = cur = Node(0)
    dummy.next = head
    
    while cur.next and cur.next.next:
        p1 = cur.next
        p2 = cur.next.next
        cur.next  = p2
        p1.next = p2.next
        p2.next = p1
        cur = cur.next.next
    return dummy.next

十五、以K为一组交换链表

def reverseKGroup(head, k):
    if head is None or k < 2:
        return head
    
    next_head = head
    for i in range(k - 1):
        next_head = next_head.next
        if next_head is None:
            return head
    ret = next_head
    
    current = head
    while next_head:
        tail = current
        prev = None
        for i in range(k):
            if next_head:
                next_head = next_head.next
            nxt = current.next
            current.next = prev
            prev = current
            current = nxt
        tail.next = next_head or current
    return ret

 十六、判断是否是回文联表 要求时间O(N),空间O(1)

def isPalindrome(head):
    rev = None
    slow = fast = head
    while fast and fast.next:
        fast = fast.next.next
        rev, rev.next, slow = slow, rev, slow.next
    if fast:
        slow = slow.next
    while rev and rev.value == slow.value:
        slow = slow.next
        rev = rev.next
    return not rev

十七、从有序链表中删除重复元素(保留)

def deleteDuplicates(head):
    if head == None:
        return head

    node = head

    while node.next:
        if node.value == node.next.value:
            node.next = node.next.next
        else:
            node = node.next

    return head

十八、从有序链表中删除重复元素(不保留)

def deleteDuplicates2(head):
    dummy = pre = Node(0)
    dummy.next = head
    while head and head.next:
        if head.value == head.next.value:
            while head and head.next and head.value == head.next.value:
                head = head.next
            head = head.next
            pre.next = head
        else:
            pre = pre.next
            head = head.next
    return dummy.next

 

 

posted @ 2019-12-03 10:45  oldby  阅读(164)  评论(0编辑  收藏  举报