Python 力扣刷题之单链表专场!例题20+ 属性和方法60+

本文档详细介绍了单向链表的节点类和链表类的基本方法,涵盖了加法、删除倒数节点、合并排序等高级操作,适合链表算法深入学习者。

单向链表

节点类、链表类基本方法

开始刷题前先罗列一下单向链表的近40个基本属性和方法,大多数出自《触“类”旁通5|链表类才是单链表的主咖》一篇并且已是验证过的。仅用于方便创建和展示单链表,碰到实际问题时尽可能只用到类的初始化方法,而不是直接调用初始化之外的其他方法来解决问题。

class Node():
    def __init__(self, value=None, Next=None):
        self.val = value
        self.next = Next
        if (type(self.next)==Node and self.next.val==None
            or type(self.next)!=Node and self.next!=None):
            self.next = None
 
    def __repr__(self):
        return f'{self.val}->{self.next}'
 
    @property
    def values(self):
        ret,ptr = [],self
        while ptr is not None:
            ret.append(ptr.val)
            ptr = ptr.next
        return ret
 
    def build(*data, split=True):
        '''把数据转换成节点链表'''
        lst,ret = [],Node()
        for val in data:
            if type(val) is str:
                if not split:
                    lst.append(val)
                    continue
                if str=='':
                    continue
                try:
                    num = int(val)
                    lst.extend([int(_) for _ in val])
                except:
                    lst.extend([_ for _ in val])
            elif hasattr(val,'__iter__'):
                lst.extend([_ for _ in val])
            elif type(val) is Node:
                if val is not None:
                    lst.extend(val.values)
            elif type(val) is List:
                if val.head is not None:
                    lst.extend(val.head.values)
            else:
                lst.append(val)
        ret = Node()
        for i in lst[::-1]:
            ret = Node(i, ret)
        return ret

 
class List():
    def __init__(self, *node):
        self.head = Node.build(*node)
		
    def __repr__(self):
        return f'[{self.head}]'

    def __len__(self):
        return self.size()
 
    @property
    def length(self):
        return self.size()
 
    def is_empty(self):
        if self.head.val==None:
            return True
        else:
            return False
 
    def size(self):
        ret,ptr = 0,self.head
        if ptr.val==None: return 0
        while ptr:
            ptr = ptr.next
            ret += 1
        return ret

    def copy(self):
        return List(self.head)

    @property
    def tail(self):
        ptr = self.head
        while ptr.next:
            ptr = ptr.next
        return ptr
 
    @property
    def values(self):
        if self.is_empty():
            return []
        ret,ptr = [],self.head
        while ptr:
            ret.append(ptr.val)
            ptr = ptr.next
        return ret
 
    @property
    def items(self):
        ptr = self.head
        while ptr:
            yield ptr.val
            ptr = ptr.next

    def NthNode(self, n=1):
        ptr = self.head
        for _ in range(n-1):
            if ptr.next is None:
                raise ValueError('n large then length of List')
            ptr = ptr.next
        return ptr

    def NthNodefromEnd(self, n=1):
        fast = slow = self.head
        for _ in range(n):
            if fast is None:
                raise ValueError('n large then length of List')
            fast = fast.next
        while fast:
            fast,slow = fast.next,slow.next
        return slow

    def __contains__(self, data):
        if self.is_empty():
            return False
        if isinstance(data,List):
            data = data.head
        if isinstance(data,Node):
            count = self.find(data.val)+1
            if count==0: return False
            ptr1,ptr2 = self.head,data
            for _ in range(1,count):
                ptr1 = ptr1.next
                if ptr1 is None: return False
            while ptr2:
                if ptr1 is None or ptr1.val!=ptr2.val:
                    return False
                ptr1,ptr2 = ptr1.next,ptr2.next
            return True
        else:
            return bool(1 + self.find(data))
            
    def __eq__(self, data):
        if not isinstance(data,List):
            return False
        if data.is_empty():
            if self.is_empty(): return True
            else: return False
        #return data in self and self in data
        ptr1,ptr2 = self.head,data.head
        while ptr1:
            if ptr1.val!=ptr2.val: return False
            ptr1,ptr2 = ptr1.next,ptr2.next
        return True

    def push(self, data):
        if not isinstance(data, List):
            data = List(data)
        if self.is_empty():
            self.head = data.head
        else:
            ret = data.head
            ret.next,self.head = self.head,ret
        return self

    def append(self, data):
        if not isinstance(data, List):
            data = List(data)
        if self.is_empty():
            self.head = data.head
        else:
            ptr = self.head
            while ptr.next:
                ptr = ptr.next
            ptr.next = data.head
        return self

    def cat(self, *data):
        for val in data:
            self.append(val)
        return self

    def __add__(self, *data):
        self.cat(*data)
        return self

    def __radd__(self, *data):
        self.add(*data)
        return self

    def __getitem__(self, item):
        return self.values[item]
 
    def __setitem__(self, idx, value):
        length = self.size()
        if idx<0: idx += length
        if self.is_empty() or idx+1>length or idx<0:
            raise IndexError('List() index out of range.')
        if isinstance(value,Node) or isinstance(value,List):
            raise TypeError('value type Error')
        ptr = self.head
        for i in range(idx):
            ptr = ptr.next
        ptr.val = value

    def __delitem__(self, index):
        length = self.size()
        if index<0: index += length
        if self.is_empty() or index+1>length or index<0:
            raise IndexError('List() index out of range.')
        ptr = self.head
        if index>0:
            for i in range(index-1):
                ptr = ptr.next
            ptr.next = ptr.next.next
        else:
            if ptr.next is None: self.head = Node()
            else: self.head = self.head.next
        return self
    
    delete = __delitem__

    def nlargest(self):
        if self.is_empty():
            return None
        ptr,ret = self.head,self.head.val
        while ptr:
            ret = max(ret, ptr.val)
            ptr = ptr.next
        return ret
 
    def nsmallest(self):
        if self.is_empty():
            return None
        ptr,ret = self.head,self.head.val
        while ptr:
            ret = min(ret, ptr.val)
            ptr = ptr.next
        return ret

    def find(self, num):
        if self.is_empty():
            return -1
        ptr,ret = self.head,-1
        while ptr:
            ret += 1
            if ptr.val == num: break
            ptr = ptr.next
        else:
            ret = -1
        return ret

    def index(self, num):
        error = lambda i:ValueError(f'{i} is not in List')
        if self.is_empty():
            raise error(num)
        ptr,ret = self.head,-1
        while ptr:
            ret += 1
            if ptr.val == num: break
            ptr = ptr.next
        else:
            raise error(num)
        return ret

    def sort(self):
        length = self.size()
        for i in range(1, length):
            ptr = self.head
            for j in range(length - i):
                if ptr.val>ptr.next.val:
                    ptr.val,ptr.next.val = ptr.next.val,ptr.val
                ptr = ptr.next
        return self
 
    def sorted(self):
        if self.size()<2:
                return self
        return List(self.head).sort()

    def reverse(self):
        ptr,ret = self.head,Node()
        while ptr:
            ret,ptr = Node(ptr.val,ret),ptr.next
        self.head = ret
        return self

    def __reversed__(self):
        ret = List(self)
        return ret.reverse()

    def rotate(self, k):
        '''链表旋转|k|个节点,正数向左负数向右'''
        if k==0: return self
        dbouble,size = Node(self.head.val),0
        ptr,ptr1 = self.head,dbouble
        while ptr.next:
            ptr1.next = Node(ptr.next.val)
            ptr,ptr1 = ptr.next,ptr1.next
        ptr = self.head
        while ptr:
            size += 1
            ptr1.next = Node(ptr.val)
            ptr,ptr1 = ptr.next,ptr1.next
        k %= size
        if k==0: return self
        ret = Node()
        ptr,ptr1 = dbouble,ret
        for i in range(k+size):
            if i>=k:
                ptr1.next = Node(ptr.val)
                ptr1 = ptr1.next
            ptr = ptr.next
        return List(ret.next)

    def __lshift__(self, n):
        self.head = self.rotate(n).head
        return self
 
    def __rshift__(self, n):
        self.head = self.rotate(-n).head
        return self
    

后补的几个方法:

    def insert(self,index,value):
        if index==0:
            self.push(value)
            return self
        length = self.size()
        if index==length:
            self.append(value)
            return self
        elif index>length or index<0:
            raise ValueError('range: 0 <= index <= length of List')
        ptr,ret = self.head,Node(value)
        for _ in range(1,index):
            ptr = ptr.next
        ret.next,ptr.next = ptr.next,ret
        return self

    def pophead(self):
        if not self:
            raise IndexError('pophead from empty Node')
        ret,self.head = self.head.val,self.head.next or Node()
        return ret

    def poptail(self):
        if not self:
            raise IndexError('poptail from empty Node')
        ret = Node()
        ptr,ptr1 = self.head,ret
        while ptr.next:
            ptr1.next = Node(ptr.val)
            ptr,ptr1 = ptr.next,ptr1.next
        tail,self.head = ptr.val,ret.next or Node()
        return tail

leetcode单链表专场

其中前11题在《触“类”旁通2》和《触“类”旁通3》中用节点类练习过,本篇将用链表类重新写过。
 

1. 整数的链表加法

Add Two Numbers (#2)
给定两个逆序表达整数各位数字的链表,求出两数之和的逆序表达的链表。

示例

输入: (2 -> 4 -> 3) + (5 -> 6 -> 4)
输出: 7->0->8
解释: 342 + 465 = 807

输入: (1->) + (9 -> 9 -> 9)
输出: 0->0->0->1
解释: 1 + 999 = 1000

    def addition(self, nodeList):
        if not (self and nodeList): return self or nodeList
        ret,carry = List(),0
        ptr,ptr1,ptr2 = ret.head,self.head,nodeList.head
        while ptr1 and ptr2:
            Sum = ptr1.val+ptr2.val+carry
            carry = 1 if Sum>9 else 0
            ptr.next = Node(Sum%10)
            ptr,ptr1,ptr2 = ptr.next,ptr1.next,ptr2.next
        ptr1 = ptr1 or ptr2
        while ptr1:
            Sum = ptr1.val+carry
            carry = 1 if Sum>9 else 0
            ptr.next = Node(Sum%10)
            ptr,ptr1 = ptr.next,ptr1.next
        if carry: ptr.next = Node(1)
        return List(ret.head.next)

>>> a = List(2,4,3)
>>> b = List(5,6,4)
>>> a.addition(b)
[7->0->8->None]
>>> b.addition(a)
[7->0->8->None]
>>> List.addition(a,b)
[7->0->8->None]
>>> a
[2->4->3->None]
>>> b
[5->6->4->None]
>>> 
>>> a = List(1)
>>> b = List(9,9,9)
>>> List.addition(a,b)
[0->0->0->1->None]
>>> List.addition(b,a)
[0->0->0->1->None]
>>> a,b
([1->None], [9->9->9->None])
>>> 

方法二:递归法

    def Add2Nums(self, node, carry=0):
        if isinstance(self,List): self = List(self).head
        if isinstance(node,List): node = List(node).head
        if not (self or node): return Node(1) if carry else None
        self,node = self or Node(0), node or Node(0)
        Sum = self.val + node.val + carry
        self.val,self.next = Sum%10,List.Add2Nums(self.next,node.next,int(Sum>9))
        return self

>>> list1 = List(2,4,3); list2 = List(5,6,4)
>>> list1.Add2Nums(list2)
7->0->8->None
>>> list2.Add2Nums(list1)
7->0->8->None

>>> list1 = List(9,9,9); list2 = List(1)
>>> list1.Add2Nums(list2)
0->0->0->1->None
>>> list2.Add2Nums(list1)
0->0->0->1->None
>>> 


2. 删除倒数第N个节点

Remove Nth Node From End of List (#19)
给定链表,删除其倒数第n个节点,返回它的头指针。

示例

输入: 1->2->3->4->5, and n = 2.
输出: 1->2->3->5.

    def removeNthEnd(self, n):
        head,size = self.head,0
        while head:
            size += 1
            head = head.next
        head = self.head
        if n>size or n<1:
            raise ValueError('n range out of [1,self.size]')
        if size==n:
            self.head = head.next if n!=1 else Node()
        else:
            for i in range(1,size-n): head = head.next
            head.next = head.next.next
        return self

>>> list1 = List(range(1,6))
>>> list1.removeNthEnd(2)
[1->2->3->5->None]
>>> list1.removeNthEnd(1)
[1->2->3->None]
>>> list1.removeNthEnd(3)
[2->3->None]
>>> list1.removeNthEnd(2)
[3->None]
>>> list1.removeNthEnd(1)
[None->None]
>>>  

方法二:定位倒数第n个位置时,先用快指针从头向后移动n个位置,再用慢指针从头开始和快指针从n位置同时向后反复步进1个位置;当快指针达到尾部时慢指针刚好到达倒数第n的位置。

    def delNthNodefromEnd(self, n=1):
        fast,ret = self.head,Node()
        for _ in range(n):
            if fast is None:
                raise ValueError('n large then length of List')
            fast = fast.next
        slow,ptr = self.head,ret
        while fast:
            ptr.next = Node(slow.val)
            fast,slow,ptr = fast.next,slow.next,ptr.next
        ptr.next = slow.next
        return List(ret.next)

>>> list1 = List(1,2,3,4,5)
>>> for i in range(1,6):
    list1.delNthNodefromEnd(i)

    
[1->2->3->4->None]
[1->2->3->5->None]
[1->2->4->5->None]
[1->3->4->5->None]
[2->3->4->5->None]

直接调用已定义的基本方法.delete()也能完成任务:

>>> list1 = List(range(1,6))
>>> n = 2
>>> del list1[-n]
>>> list1
[1->2->3->5->None]
>>> list1 = List(range(1,6))
>>> n = 2
>>> list1.delete(-n)
[1->2->3->5->None]
>>> 


3. 合并有序链表

Merge Two Sorted Lists (#21)
给定两个有序链表(升序),合并为一个新的有序链表并返回。

示例

输入:1->2>4->8
   1->3->3->5->5
输出:1->1->2->3->3->4->5->5->8

输入:0->2>4->8
   1->3->5->7->9
输出:0->1->2->3->4->5->6->7->8->9

    def merge(self, nodeList):
        '''合并两个有序链表'''
        if not self: return nodeList
        ret = List()
        ptr,ptr1,ptr2 = ret.head,self.head,nodeList.head
        while ptr1 and ptr2:
            if ptr1.val < ptr2.val:
                ptr.next = Node(ptr1.val)
                ptr1 = ptr1.next
            else:
                ptr.next = Node(ptr2.val)
                ptr2 = ptr2.next
            ptr = ptr.next
        ptr.next = ptr1 or ptr2
        return List(ret.head.next)

>>> list1 = List(1,2,4,8)
>>> list2 = List(1,3,3,5,5)
>>> list1.merge(list2)
[1->1->2->3->3->4->5->5->8->None]
>>> list1
[1->2->4->8->None]
>>> list2
[1->3->3->5->5->None]
>>> list1 = List(2,4,6,8)
>>> list2 = List(1,3,5,7,9)
>>> list2.merge(list1)
[1->2->3->4->5->6->7->8->9->None]
>>> list1,list2
([2->4->6->8->None], [1->3->5->7->9->None])

>>> List.merge(list1,list2)
[1->2->3->4->5->6->7->8->9->None]
>>> 

方法二:递归法

    def mergeNodes(self,node):
        if isinstance(self,List): self = List(self).head
        if isinstance(node,List): node = List(node).head
        if not (self and node): return self or node
        if self.val <= node.val:
            self.next = List.mergeNodes(self.next,node)
            return self
        else:
            node.next = List.mergeNodes(self,node.next)
            return node

>>> list1 = List(1,2,4,8); list2 = List(1,3,3,5,5)
>>> list1.mergeNodes(list2)
1->1->2->3->3->4->5->5->8->None
>>> list2.mergeNodes(list1)
1->1->2->3->3->4->5->5->8->None
>>> list1,list2
([1->2->4->8->None], [1->3->3->5->5->None])
>>> list1.mergeNodes(list1)
1->1->2->2->4->4->8->8->None
>>> list2.mergeNodes(list2)
1->1->3->3->3->3->5->5->5->5->None
>>> 


4. 合并多个有序链表

Merge k Sorted Lists (#23)
合并k个已排序的链表,并将其作为一个已排序的列表返回。前一题的升级版

示例

输入: 
[
1->4->5,
1->3->4,
2->6
]
输出:  1->1->2->3->4->4->5->6

    def Merge(self, *nodeList):
        ret = List(self.head)
        for lst in nodeList:
            ret = ret.merge(lst)
        return ret

>>> List.Merge(List(1,4,5),List(1,3,4),List(2,6))
[1->1->2->3->4->4->5->6->None]
>>> 


. 成对反转节点

Swap Nodes in Pairs (#24)
给定一个链表,每两个相邻节点交换一次,并返回其头指针。要求不能修改节点的数据域,假设或有成单的尾节点不反转。

示例

输入: 1->2->3->4.
输出: 2->1->4->3.

    def swapPairs(self):
        if not self.head.next: return self
        ptr1 = ptr2 = self.head
        ret = List()
        ptr,ptr1 = ret.head,ptr1.next
        while ptr1:
            ptr.next = Node(ptr1.val)
            ptr = ptr.next
            ptr.next = Node(ptr2.val)
            ptr = ptr.next
            ptr1,ptr2 = ptr1.next,ptr2.next
            if not ptr1: break 
            if not ptr1.next:
                ptr.next = Node(ptr1.val)
            ptr1,ptr2 = ptr1.next,ptr2.next
        self.head = ret.head.next
        return self

 >>> a = List(1,2,3,4)
>>> a.swapPairs()
[2->1->4->3->None]
>>> b = List(1,2,3,4,5)
>>> b.swapPairs()
[2->1->4->3->5->None]

方法二:迭代法

    def swap2pair(self):
        if isinstance(self,List):
            self = List(self.head)
            self = self.head
        if not self or not self.next:
            return self
        ptr = self.next
        self.next = List.swap2pair(ptr.next)
        ptr.next = self
        return ptr

>>> a = List(1,2,3,4)
>>> a.swap2pair()
2->1->4->3->None
>>> b = List(1,2,3,4,5)
>>> b.swap2pair()
2->1->4->3->5->None

# 迭代法返回的是节点Node()的链式结构而非链表List()


. 成组反转节点

Reverse Nodes in k-Group (#25)
给定一个链表,每k个相邻节点为一组,各组一一反转,返回修改后的列表。k小于或等于链表的长度。如果节点的数量不是k的倍数,那么最后剩下的个数小于k不满一组的则保持原样不反转。

示例

输入: 1->2->3->4->5.
输出: k=2时,2->1->4->3->5;
    k=3时,3->2->1->4->5.

    def reverseKGroup(self, k):
        if type(k) is not int or k<1:
            raise BaseException('K = 1, 2, 3, ...')
        if k==1: return self
        ret,self = Node(),List(self)
        ptr,ptr1 = self.head,ret
        size = 0
        while True:
            kgroup = Node()
            ptr2 = kgroup
            count = 0
            for _ in range(k):
                size += 1
                if ptr is None:
                    if k>=size:
                        raise BaseException('length of Node less than K')
                    break
                ptr2.next = Node(ptr.val)
                count += 1
                ptr,ptr2 = ptr.next,ptr2.next
            kgroup = kgroup.next
            if count==k:
                t,p = None,kgroup
                while p:
                    p.next,t,p = t,p,p.next
                kgroup = t
                ptr2 = kgroup
                for _ in range(k):
                    ptr1.next = Node(ptr2.val)
                    ptr1,ptr2 = ptr1.next,ptr2.next
            else:
                ptr1.next = kgroup
                break
        self.head = ret.next
        return self

>>> a = List(1,2,3,4,5)
>>> a.reverseKGroup(2)
[2->1->4->3->5->None]
>>> a.reverseKGroup(3)
[3->2->1->4->5->None]

>>> b = List(range(1,11))
>>> for i in range(1,8):
    b.reverseKGroup(i)

    
[1->2->3->4->5->6->7->8->9->10->None]
[2->1->4->3->6->5->8->7->10->9->None]
[3->2->1->6->5->4->9->8->7->10->None]
[4->3->2->1->8->7->6->5->9->10->None]
[5->4->3->2->1->10->9->8->7->6->None]
[6->5->4->3->2->1->7->8->9->10->None]
[7->6->5->4->3->2->1->8->9->10->None]
>>> 


7. 链表旋转

Rotate List (#61)
给定一个链表,将列表向右旋转k个节点,其中k为非负整数。

示例1

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
rotate 1 steps to the right: 5->1->2->3->4->NULL
rotate 2 steps to the right: 4->5->1->2->3->NULL

示例2

输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
rotate 1 steps to the right: 2->0->1->NULL
rotate 2 steps to the right: 1->2->0->NULL
rotate 3 steps to the right: 0->1->2->NULL
rotate 4 steps to the right: 2->0->1->NULL

    def rotateList(self,k):
        node1,node2,ptr = Node(),Node(),self.head
        length = self.size()
        k %= length
        if not k: return self
        head,tail = node1,node2
        for i in range(length-k):
            head.next = Node(ptr.val)
            head,ptr = head.next,ptr.next
        while ptr:
            tail.next = Node(ptr.val)
            tail,ptr = tail.next,ptr.next
        tail.next = node1.next
        return List(node2.next)

>>> a = List(1,2,3,4,5)
>>> a.rotateList(1)
[5->1->2->3->4->None]
>>> a.rotateList(2)
[4->5->1->2->3->None]

>>> b = List(0,1,2)
>>> for i in range(1,5):
    b.rotateList(i)

    
[2->0->1->None]
[1->2->0->None]
[0->1->2->None]
[2->0->1->None]
>>> 

直接调用已定义的基本方法.rotate()或者重载的右移运算也能完成任务:

>>> list1 = List(range(1,6))
>>> list1.rotate(-1)
[5->1->2->3->4->None]
>>> list1.rotate(-2)
[4->5->1->2->3->None]
>>> list1
[1->2->3->4->5->None]
>>> list1>>2
[4->5->1->2->3->None]
>>> list1
[4->5->1->2->3->None]
>>> 

>>> list2 = List(0,1,2)
>>> k = 4
>>> for i in range(1,k+1):
    print(list2.rotate(-i))

[2->0->1->None]
[1->2->0->None]
[0->1->2->None]
[2->0->1->None]
>>> list2
[0->1->2->None]
>>> list2 >> k
[2->0->1->None]
>>> list2
[2->0->1->None]
>>> 


8. 删除重复节点Ⅰ

Remove Duplicates from Sorted List (#82)
给定一个已排序链表,删除重复节点,原始链表中多次出现的数字只能保留一次。

示例

输入: 1->1->2
输出: 1->2

输入: 1->1->2->3->3
输出: 1->2->3

    def deleteDup(self):
        ret = List()
        head,ptr = self.head,ret.head
        while head:
            if head.val!=ptr.val:
                ptr.next = Node(head.val)
                ptr = ptr.next
            head = head.next
        return List(ret.head.next)

>>> list1 = List(1,1,2)
>>> list1.deleteDup()
[1->2->None]
>>> list2 = List(1,1,2,3,3)
>>> list2.deleteDup()
[1->2->3->None]
>>>  
>>> list3 = List(1,2,3,3,4,4,4,5)
>>> list3.deleteDup()
[1->2->3->4->5->None]


9. 删除重复节点Ⅱ

Remove Duplicates from Sorted List (#83)
给定一个排序链表,删除所有重复的节点,留原始链表有过重复的数字一个也不留。

示例

输入: 1->2->3->3->4->4->5
输出: 1->2->5

输入: 1->1->1->2->3
输出: 2->3

    def removeDup(self):
        ret = List()
        ptr1,ptr2 = self.head,ret.head
        if not ptr1.next: return self
        if ptr1.val!=ptr1.next.val:
            ptr2.next = Node(ptr1.val)
            ptr2 = ptr2.next
        t,ptr1 = ptr1.val,ptr1.next
        while ptr1.next:
            if t!=ptr1.val!=ptr1.next.val:
                ptr2.next = Node(ptr1.val)
                ptr2 = ptr2.next
            t = ptr1.val
            ptr1 = ptr1.next
        if t!=ptr1.val:
            ptr2.next = Node(ptr1.val)
        return List(ret.head.next)

>>> list1 = List(1,2,3,3,4,4,5)
>>> list1.removeDup()
[1->2->5->None]
>>> list2 = List(1,1,1,2,3)
>>> list2.removeDup()
[2->3->None]
>>> list3 = List(1,2,3,3)
>>> list3.removeDup()
[1->2->None]


10. 链表分组

Partition List (#86)
给定一个链表和一个整数,把链表分成“小于指定数”和“不小于指定数”的二组连接在一起,并且各组元素在本组中的先后位置保持与原链表相同。

示例

输入: 1->4->3->2->5->2->None, x = 3
输出: 1->2->2->4->3->5->None

    def partition(self,x):
        if not self.head.next: return self
        gt,lt = Node(),Node()
        ptr1,ptr2,ptr = gt,lt,self.head
        while ptr:
            if ptr.val<x:
                ptr1.next = Node(ptr.val)
                ptr1 = ptr1.next
            else:
                ptr2.next = Node(ptr.val)
                ptr2 = ptr2.next
            ptr = ptr.next
        ptr1.next = lt.next
        return List(gt.next)

>>> list1 = List(1,4,3,2,5,2); x = 3
>>> list1.partition(x)
[1->2->2->4->3->5->None]
>>> 


11. 反转链表中一段节点

Reverse Linked List (a part of NodeList)  (#92)
Reverse a linked list from position m to n. Do it in one-pass.
Note: 1 ≤ m ≤ n ≤ length of list.

示例

输入: 1->2->3->4->5->None, m = 2, n = 4
输出: 1->4->3->2->5->None


12. 重排链表

Reorder List (#143)
Given a singly linked list L: L0→L1→…→Ln-1→Ln, 
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You may not modify the values in the list's nodes, only nodes itself may be changed.
给定一个链表,不允许修改数据域,按“从头尾向中间的顺序“重排节点。

示例

Given 1->2->3->4, reorder it to 1->4->2->3.
Given 1->2->3->4->5, reorder it to 1->5->2->4->3.

方法一:先遍历出长度和倒序链表,然后把两个链表的前半部分混插。 

    def reorder(self):
        if not self.head.next: return self
        size,tmp,ptr = 0,Node(),self.head
        while ptr:
            size += 1
            tmp = Node(ptr.val,tmp)
            ptr = ptr.next
        ret = Node()
        ptr1,ptr2,ptr = self.head,tmp,ret
        for _ in range(size//2):
            ptr.next = Node(ptr1.val)
            ptr,ptr1 = ptr.next,ptr1.next
            ptr.next = Node(ptr2.val)
            ptr,ptr2 = ptr.next,ptr2.next
        if size%2: ptr.next = Node(ptr1.val)
        return List(ret.next)

 >>> a = List(*range(1,5))
>>> a.reorder()
[1->4->2->3->None]
>>> b = List(*range(1,6))
>>> b.reorder()
[1->5->2->4->3->None]
>>> c = List(*range(1,7))
>>> c.reorder()
[1->6->2->5->3->4->None]
>>> 

方法二:使用基本方法中的pophead(),poptail()反复弹出头尾节点,用弹出值新建一个链表。

    def reorderHT(self):
        if not self.head.next or not self.head.next.next:
            return self
        ret,self = Node(),List(self)
        ptr = ret
        while self:
            ptr.next = Node(self.pophead())
            ptr = ptr.next
            try: ptr.next = Node(self.poptail())
            except: break
            ptr = ptr.next
        return List(ret.next)

>>> a = List(1,2,3,4)
>>> a.reorderHT()
[1->4->2->3->None]
>>> b = List(1,2,3,4,5)
>>> b.reorderHT()
[1->5->2->4->3->None]
>>> c = List(1,2,3,4,5,6)
>>> c.reorderHT()
[1->6->2->5->3->4->None]
>>> c
[1->2->3->4->5->6->None]
>>> 


13. 链表插入排序

Insertion Sort List (#147)
Sort a linked list using insertion sort.

示例

输入: 4->2->1->3
输出: 1->2->3->4

输入: -1->5->3->4->0
输出: -1->0->3->4->5 

已定义的基本方法中sorted(),sort()已能实现排序功能,但是排序时直接比较数据域的。

>>> list1 = List(6,3,4,5,2,1)
>>> list1.sorted()
[1->2->3->4->5->6->None]
>>> list1
[6->3->4->5->2->1->None]
>>> list1.sort()
[1->2->3->4->5->6->None]
>>> list1
[1->2->3->4->5->6->None]
>>> 

插入排序: 

    def insertionSort(self):
        if not self.head.next: return self
        ret = Node()
        ptr,ptr1 = List(self).head,ret
        while ptr:
            Next = ptr.next
            while ptr1.next and ptr1.next.val<ptr.val:
                ptr1 = ptr1.next
            ptr.next,ptr1.next = ptr1.next,ptr
            ptr,ptr1 = Next,ret
        return List(ret.next)

>>> list1 = List(4,2,1,3)
>>> list1.insertionSort()
[1->2->3->4->None]
>>> list1
[4->2->1->3->None]
>>> list2 = List(-1,5,3,4,0)
>>> list2.insertionSort()
[-1->0->3->4->5->None]
>>> list2
[-1->5->3->4->0->None]
>>> 


14. 链表归并排序

Sort List (#148)
Sort a linked list in O(n log n) time using constant space complexity.

归并排序: 时间复杂度 O(n log n),空间复杂度 O(1)


15. 删除指定值的所有节点

Remove Linked List Elements (#203)
删除给定链表中所有数值域等于指定值val的节点。

示例

输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5

    def removeValues(self,val):
        if not self.head: return self
        ret = Node()
        ptr1,ptr2 = ret,self.head
        while ptr2:
            if ptr2.val!=val:
                ptr1.next = Node(ptr2.val)
                ptr1 = ptr1.next
            ptr2 = ptr2.next
        return List(ret.next)

>>> list1 = List(1,2,6,3,4,5,6); val = 6
>>> list1.removeValues(val)
[1->2->3->4->5->None]
>>> list1.removeValues(0)
[1->2->6->3->4->5->6->None]
>>> 

方法二:迭代法

    def removeElements(self,val):
        if isinstance(self,List):
            self = List(self.head.next) if self.head.val==val else List(self.head)
            self = self.head
        while self and self.val==val: self = self.next
        if self: self.next = List.removeElements(self.next,val)
        return self

>>> list1 = List(1,2,6,3,4,5,6); val = 6
>>> list1.removeElements(val)
1->2->3->4->5->None
>>> list1
[1->2->6->3->4->5->6->None]

>>> list2 = List(3,1,2,3,3,4,3,5,5,3); val = 3
>>> list2.removeElements(val)
1->2->4->5->5->None
>>> list2
[3->1->2->3->3->4->3->5->5->3->None]
>>> 


16. 反转链表

Reverse Linked List (#206)
Reverse a singly linked list.
链表的全部反转,这是很基础的方法。上面的第6题、第11题中已有部分的反转。

已定义的基本方法中已有 __reversed__、.reverse() 可以完成反转,把它们的代码稍作改进,相当于直接改变链表的指针方向,而不是用Node()嵌套新建一个链表,本质是一样的。

    def reverseList(self):
        ret,ptr = None,self.head
        while ptr: ptr.next,ret,ptr = ret,ptr,ptr.next
        self.head = ret
        return self

>>> a = List(range(1,6))
>>> a.reverseList()
[5->4->3->2->1->None]
>>> b = List(range(0,10,2))
>>> b.reverseList()
[8->6->4->2->0->None]
>>> c = List(1)
>>> c.reverseList()
[1->None]
>>> d = List()
>>> d.reverseList()
[None->None]
>>> b = List(range(0,9,2))
>>> b.reverseList()
[8->6->4->2->0->None]
>>> b = List(range(0,3,2))
>>> b.reverseList()
[2->0->None]
>>> 


17.  回文链表

Palindrome Linked List (#234)
判断给定链表是否为回文链表,即链表与反转后的一致。

示例

Input: 1->2
Output: False

Input: 1->2->2->1
Output: True

    def isPalindrome(self):
        if not self.head.next:
            return True
        ptr,tmp = self.head,[]
        while ptr:
            tmp.append(ptr.val)
            ptr = ptr.next
        ptr = self.head
        while ptr:
            if ptr.val!=tmp.pop():
                return False
            ptr = ptr.next
        return True

>>> list1 = List(1,2)
>>> list1.isPalindrome()
False
>>> list2 = List(1,2,2,1)
>>> list2.isPalindrome()
True
>>> list3 = List(1,2,3,2,1)
>>> List.isPalindrome(list3)
True
>>> 

直接调用已定义的基本方法__reversed__、__eq__、__contains__也能办到:

>>> list1 = List(1,2)
>>> list1 in reversed(list1)
False
>>> list1 == reversed(list1)
False

>>> list2 = List(1,2,2,1)
>>> list2 in reversed(list2)
True
>>> list2 == reversed(list2)
True
>>> 


18. 删除指定节点

Delete Node in a Linked List (#237)
Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.
Given linked list -- head = [4,5,1,9], which looks like following:

Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
Explanation: You are given the second node with value 5, the linked list
should become 4 -> 1 -> 9 after calling your function.
Input: head = [4,5,1,9], node = 1
Output: [4,5,9]
Explanation: You are given the third node with value 1, the linked list should
become 4 -> 5 -> 9 after calling your function.

Note:
The linked list will have at least two elements.
All of the nodes' values will be unique.
The given node will not be the tail and it will always be a valid node of the linked list.
Do not return anything from your function.

与15题类同但只删除一个,如果不像Note中说明的一样:节点的值都是唯一的;那么还延用15题的方法则需要设置一个标记:重复的只不复制第一个。

    def removeVal1(self,val):
        if not self.head: return self
        ret,flag = Node(),True
        ptr1,ptr2 = ret,self.head
        while ptr2:
            if flag and ptr2.val==val:
                flag = False
            else:
                ptr1.next = Node(ptr2.val)
                ptr1 = ptr1.next          
            ptr2 = ptr2.next
        return List(ret.next)

>>> list1 = List(4,5,1,9); val = 5
>>> list1.removeVal1(val)
[4->1->9->None]
>>> list1.removeVal1(1)
[4->5->9->None]

>>> list2 = List(1,2,6,3,4,5,6); val = 6
>>> list2.removeVal1(val)
[1->2->3->4->5->6->None]
>>> 

方法二:遇到指定值,直接跳指下一个节点,self的值会被变更。

    def removeVal2(self,val):
        if not self.head: return self
        if self.head.val==val:
            self.head = self.head.next
        else:
            ptr = self.head
            while ptr.next:
                if ptr.next.val==val:
                    ptr.next = ptr.next.next
                    break
                ptr = ptr.next
        self.head = self.head or Node()
        return self

>>> list1 = List(4,5,1,9); val = 5
>>> list1.removeVal2(val)
[4->1->9->None]
>>> list1.removeVal2(1)
[4->9->None]

>>> list2 = List(1,2,6,3,4,5,6); val = 6
>>> list2.removeVal2(val)
[1->2->3->4->5->6->None]
>>> list2.removeVal2(6)
[1->2->3->4->5->None]
>>> list2.removeVal2(1)
[2->3->4->5->None]
>>> 

直接调用已定义的基本方法.find()和.delete()也可完成:

>>> list1 = List(4,5,1,9); val = 5
>>> list1.delete(list1.find(val))
[4->1->9->None]
>>> list1.delete(list1.find(1))
[4->9->None]

>>> list2 = List(1,2,6,3,4,5,6); val = 6
>>> list2.delete(list2.find(val))
[1->2->3->4->5->6->None]
>>> list2.delete(list2.find(val))
[1->2->3->4->5->None]
>>> list2.delete(list2.find(1))
[2->3->4->5->None]
>>> 


19. 奇偶索引重排

Odd Even Linked List (#328)
给定一个单链表,按节点索引号的奇偶重新排列。

示例

输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL

输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL

    def oddevenIndex(self):
        if not self.head.next: return self
        odd,even,index = Node(),Node(),0
        ptr1,ptr2,ptr = odd,even,self.head
        while ptr:
            index += 1
            if index%2:
                ptr1.next = Node(ptr.val)
                ptr1 = ptr1.next
            else:
                ptr2.next = Node(ptr.val)
                ptr2 = ptr2.next
            ptr = ptr.next
        ptr1.next = even.next
        return List(odd.next)

>>> a = List(*range(1,6))
>>> a.oddevenIndex()
[1->3->5->2->4->None]
>>> b = List(2,1,3,5,6,4,7)
>>> b.oddevenIndex()
[2->3->6->7->1->5->4->None]
>>> 

类似题目:给定一个单链表,按节点数值域的奇偶重新排列。这类按要求分组的都与第10题属于同一类型。

    def oddevenNumber(self):
        if not self.head.next: return self
        odd,even = Node(),Node()
        ptr1,ptr2,ptr = odd,even,self.head
        while ptr:
            if ptr.val%2:
                ptr1.next = Node(ptr.val)
                ptr1 = ptr1.next
            else:
                ptr2.next = Node(ptr.val)
                ptr2 = ptr2.next
            ptr = ptr.next
        ptr1.next = even.next
        return List(odd.next)

>>> a = List(*range(1,6))
>>> a.oddevenNumber()
[1->3->5->2->4->None]

>>> b = List(2,1,3,5,6,4,7)
>>> b.oddevenNumber()
[1->3->5->7->2->6->4->None]
>>> 


20. 两数之和 II

Add Two Numbers II (#445)
You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Follow up:
What if you cannot modify the input lists? In other words, reversing the lists is not allowed.
第一题的变形,本题的链表是正序表示两个整数的非空链表,不允许反转完成加法。

示例

输入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出: 7 -> 8 -> 0 -> 7

    def Add2NumII(self,node):
        len1,len2 = self.size(),node.size()
        ret1,ret2,self = [],[],List(self.head)
        if len1>len2:
            ptr1,ptr2 = self.head,node.head
        else:
            ptr1,ptr2 = node.head,self.head
            len1,len2 = len2,len1
        for _ in range(len1-len2):
            ret1.append(ptr1.val)
            ret2.append(0)
            ptr1 = ptr1.next
        while ptr2:
            ret1.append(ptr1.val)
            ret2.append(ptr2.val)
            ptr1,ptr2 = ptr1.next,ptr2.next
        ret,carry = Node(),0
        for _ in range(len1):
            Sum = carry + ret1.pop() + ret2.pop()
            carry,Sum = divmod(Sum,10)
            ret = Node(Sum,ret)
        if carry: ret = Node(1,ret)
        return ret

>>> list1 = List(7,2,4,3); list2 = List(5,6,4)
>>> list1.Add2NumII(list2)
7->8->0->7->None
>>> list2.Add2NumII(list1)
7->8->0->7->None
>>> list1 = List(5,2,0,8); list2 = List(9,5,5,3,3)
>>> list1.Add2NumII(list2)
1->0->0->7->4->1->None
>>> list2.Add2NumII(list1)
1->0->0->7->4->1->None
>>> 


21 . 链表类设计

Design Linked List (#707)
Design your implementation of the linked list. You can choose to use the singly linked list or the
doubly linked list. A node in a singly linked list should have two attributes: val and next. val is the
value of the current node, and next is a pointer/reference to the next node. If you want to use the
doubly linked list, you will need one more attribute prev to indicate the previous node in the
linked list. Assume all nodes in the linked list are 0-indexed.
Implement these functions in your linked list class:
get(index) : Get the value of the index-th node in the linked list. If the index is invalid, return -1.
addAtHead(val) : Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
addAtTail(val) : Append a node of value val to the last element of the linked list.
addAtIndex(index, val) : Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
deleteAtIndex(index) : Delete the index-th node in the linked list, if the index is valid.

Example:
MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1, 2); // linked list becomes 1->2->3
linkedList.get(1); // returns 2
linkedList.deleteAtIndex(1); // now the linked list is 1->3
linkedList.get(1); // returns 3

Note:
All values will be in the range of [1, 1000].
The number of operations will be in the range of [1, 1000].
Please do not use the built-in LinkedList library.

类似的功能在已定义的基本方法中都有:

>>> linkedList = List(1)
>>> linkedList.append(3)
[1->3->None]
>>> linkedList.insert(1,2)
[1->2->3->None]
>>> linkedList[1]
2
>>> linkedList.delete(1)
[1->3->None]
>>> linkedList[1]
3


22 . 链表中间节点

Middle of the Linked List (#876)
Given a non-empty, singly linked list with head node head, return a middle node of linked list.
If there are two middle nodes, return the second middle node.
给定一个非空链表,返回中间节点。如有2个中间节点(节点数为偶数时)返回第2个。

方法一:先遍历出长度,再遍历一半长度

    def middleNode(self):
        if not self.head.next:
            return self.head.val
        ptr,size = self.head,0
        while ptr:
            size += 1
            ptr = ptr.next
        ptr = self.head
        for _ in range(size//2):
            ptr = ptr.next
        return ptr.val

>>> list1 = List(range(1,6))
>>> list1
[1->2->3->4->5->None]
>>> list1.middleNode()
3
>>> list2 = List(range(1,7))
>>> list2
[1->2->3->4->5->6->None]
>>> list2.middleNode()
4
>>>  

方法二:快指针步进2,慢指针步进1,当快指针移到尾部时,慢指针就在中间节点上。

    def middleNodefs(self):
        if not self.head.next: return self.head.val
        fast,slow = self.head,self.head
        while fast:
            if fast.next is None: return slow.val
            fast,slow = fast.next,slow.next
            fast = fast.next
        return slow.val

>>> list1 = List(range(1,6))
>>> list1.middleNodefs()
3
>>> list1 = List(range(1,7))
>>> list1.middleNodefs()
4
>>> 


23 . 下一个大节点

Next Greater Node In Linked List (#1019)
We are given a linked list with head as the first node. Let's number the nodes in the list: node_1, node_2, node_3, ... etc.
Each node may have a next larger value: for node_i, next_larger(node_i) is the node_j.val such that j > i, node_j.val > node_i.val, and j is the smallest possible choice. If such a j does not exist, the next larger value is 0.
Return an array of integers answer, where answer[i] = next_larger(node_{i+1}).
Note that in the example inputs (not outputs) below, arrays such as [2,1,5] represent the serialization of a linked list with a head node value of 2, second node value of 1, and third node value of 5.
找出链表中第一个比自己大的节点,没找到则为0。

示例

输入: [2,1,5]
输出: [5,5,0]

输入: [2,7,4,3,5]
输出: [7,0,5,5,0]

输入: [1,7,5,1,9,2,5,1]
输出: [7,9,9,9,0,5,0,0]

    def nextGreaterNode(self):
        ret,ptr = [],self.head
        while ptr:
            cur,tmp = ptr,ptr.val
            while cur:
                if cur.val>tmp:
                    ret.append(cur.val)
                    break
                cur = cur.next
            else:
                ret.append(0)
            ptr = ptr.next
        return ret

>>> a = List([2,1,5])
>>> a.nextGreaterNode()
[5, 5, 0]
>>> b = List([2,7,4,3,5])
>>> b.nextGreaterNode()
[7, 0, 5, 5, 0]
>>> c = List([1,7,5,1,9,2,5,1])
>>> c.nextGreaterNode()
[7, 9, 9, 9, 0, 5, 0, 0]
>>> 

------===The End===------

 

评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hann Yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值