zoukankan      html  css  js  c++  java
  • 六、链表

    1. 使用python定义链表结构

    from util.Empty import Empty
    from util.Outbound import Outbound
    
    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('')
    

    2. 删除链表中的节点 

    • leetcode: 第237题. 删除链表中的节点,只允许访问要删除的那个节点。 难度:简单
    • leetcode: 面试题18. 删除链表的节点 与此题要求不一样,有可能包括尾节点也要删除
    # 传统的方法是找到prev节点,然后让prev.next = prev.next.next 
    # 现在不让访问prev了,只允许访问当前的node
    def delete_node(node):  
        print(node.value)  
        node.value = node.next.value    # 偷梁换柱,把下一个节点的value赋值给当前节点的值,删除下一个节点即可。
        node.next = node.next.next
    

    3. 找到链表的中间节点

    • leetcode 第876题. 链表的中间结点 难度:简单
    # 快慢指针思想
    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
    

    4. 确定链表是不是环形的

    • leetcode 第141题. 环形链表 难度:简单
      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

    5.  给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

    • leetcode 第142题. 环形链表 II 难度:中等
    • 面试题 02.08. 环路检测 难度:中等
    def find_beginning(head): 
        fast = head 
        slow = head 
        meet = None 
        while fast and fast.next is not None:
            fast = fast.next.next 
            slow = slow.next 
    
            if fast == slow:
                meet = fast 
                break 
    
        if meet is None or meet.next is None:
            return None 
    
        while head and meet:
            if head == meet:
                return meet 
            head = head.next
            meet = meet.next 
    
        return None
    

    6.

    给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。

    • leetcode 第19题. 删除链表的倒数第N个节点 难度:中等
    • 面试题22. 链表中倒数第k个节点 难度:简单
    • 面试题 02.02. 返回倒数第 k 个节点 
      def remove_nth(lst, n):
          assert n<=lst.length and n > 0
          
          fast = lst.head
          while n > 0:
              fast = fast.next
              n = n - 1
          
          if fast == None:
              return head 
              
          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

    7. 把链表从中间切开成两个链表

    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)
    

    8. 合并两个有序的链表

    • leetcode 第21题. 合并两个有序链表 难度:简单
    # iteratively
    # 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
    

    9.  找到两个链表的第一个公共节点

    A: a1 → a2

                     ↘
    
                       c1 → c2 → c3
    
                     ↗    

    B: b1 → b2 → b3

    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
    

    10.  插入排序

    • leetcode 第147题. 对链表进行插入排序 难度:中等
    # O(n^2)
    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
    

    11. 对链表进行排序

    • leetcode 第148题. 排序链表 难度:中等
    # Merge sort的思想
    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 

     12. 分隔链表

    给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。

    你应当保留两个分区中每个节点的初始相对位置。

    • leetcode 第86题. 分隔链表 难度:中等
    • 面试题 02.04. 分割链表 难度:中等
    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
    

     13.

    • 面试题24. 反转链表
    • leetcode 第206题. 反转链表 难度:简单
    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
    

    14. 

    • leetcode 第92题. 反转链表 II 难度:中等
    def reverseBetween(head, m, n):
        if m == n:
            return head
    
        dummyNode = Node(0)
        dummyNode.next = head
        pre = dummyNode
    
        for i in range(m - 1): # 先定位到m位置
            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
    

    15. 

    • leetcode 第25题. 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 # 先用ret记录住当前第一个反转列表的位置,也是整个反转列表的开头,反转完返回它即可。
        
        current = head
        while next_head:
            tail = current  # 先用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
    

    16. 

    • leetcode 第234题. 回文链表 难度:简单
    • 面试题 02.06. 回文链表 难度:简单
    # 找到中间节点和中间节点的前一个节点
    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 
    

    17. 

    Given 1->1->2, return 1->2.

    Given 1->1->2->3->3, return 1->2->3.

    • leetcode 第83题. 删除排序链表中的重复元素 
    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
    

    18. 

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

    Given 1->1->1->2->3, return 2->3.

    • leetcode 第82题. 删除排序链表中的重复元素 II 难度:中等
    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
    

      

     

  • 相关阅读:
    DLL库
    C#:时间转换
    视频通信网址
    C#:向exe传值
    C#:复杂条件判断类型(练习)
    注册、卸载DLL
    Windows:常见问题
    WPF:常见问题
    CentOS完美搭建Redis3.0集群并附测试
    xargs命令
  • 原文地址:https://www.cnblogs.com/carlber/p/14443338.html
Copyright © 2011-2022 走看看