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
    

      

     

  • 相关阅读:
    欧拉公式
    isap的一些想法
    错误合集
    Hello World
    PAT (Advanced Level) Practice 1068 Find More Coins
    PAT (Advanced Level) 1087 All Roads Lead to Rome
    PAT (Advanced Level) 1075 PAT Judge
    PAT (Advanced Level) 1067 Sort with Swap(0, i)
    PAT (Advanced Level) 1017 Queueing at Bank
    PAT (Advanced Level) 1025 PAT Ranking
  • 原文地址:https://www.cnblogs.com/carlber/p/14443338.html
Copyright © 2011-2022 走看看