Leetcode 单链表题型总结

Leetcode 单链表题型总结

自己刷题的一个小记录,难度从easy --> hard,持续更新中。若有更好的方法,欢迎评论区讨论呀。
876. 返回单链表的中间节点。如果有两个中间节点,返回第二个。
两种思路,
第一种是先遍历一遍,记录长度后,再遍历到一半。时间复杂度O(n)
第二种是用两个指针,一快一慢,快指针每次走两步,慢指针每次走一步,当快指针走到链表最后时,慢指针所指的就是中间节点。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

'''
先遍历一遍,记录长度,再遍历一半。
class Solution:
    def middleNode(self, head: ListNode) -> ListNode:
        if head.next ==None:
            return head
        length = 1
        phead = head
        while head.next !=None:
            length +=1
            head = head.next
        
        mid = length//2
        for i in range(mid):
            phead = phead.next
        return phead
'''
# 直接快慢指针,快的到头以后,慢的就是中间值
class Solution:
    def middleNode(self, head: ListNode) -> ListNode:
        if head.next ==None:
            return head
        fast = head
        slow = head
        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
        return slow

206. 反转单链表
两种思路
递归
迭代

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
'''
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        # 递归版本,一直往后遍历,每次建立一个反转链接
        return self.reverse(head,None)
    
    def reverse(self, current, prev):
        if current == None:
            return prev
        
        nxt = current.next
        current.next = prev
        prev = current
        current = nxt
        
        return self.reverse(current, prev)
'''
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        # 迭代版本
        return self.reverse(head,None)
    
    def reverse(self, current, prev):
        if current == None:
            return prev
        while current!=None:
            nxt = current.next
            current.next = prev
            prev = current
            current = nxt
        return prev

237. 删除单链表中的某一节点
这题要注意的是,并没有给出完整的链表,函数参数中只是给了要删除的节点。
但由于是单链表,没法获取被删除节点前的节点,所以将被删除节点的值改为后面一个节点的值,然后删除后面一个节点即可。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteNode(self, node):
        """
        :type node: ListNode
        :rtype: void Do not return anything, modify node in-place instead.
        """
        # 没有给完整的单链表,只是给了要删除的节点!没有head!
        node.val = node.next.val
        node.next = node.next.next

21. 合并两个已排序的单链表
用两个指针分别遍历两个链表。遇到较小的一个,就加到合并列表后面,并指针后移。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        newlist = ListNode(0)
        tmp = newlist
        while l1!=None and l2!=None:
            if l1.val<l2.val:
                tmp.next = l1
                l1 = l1.next
            else:
                tmp.next = l2
                l2 = l2.next
            tmp = tmp.next
        if l1!=None:
            while l1!=None:
                tmp.next = l1
                l1 = l1.next
                tmp = tmp.next
        if l2!=None:
            while l2!=None:
                tmp.next = l2
                l2 = l2.next
                tmp = tmp.next
        return newlist.next
            

83.给定一个排序后的单链表,删除其中的重复节点,保证每个节点只出现一次。
思路:遇到重复的节点,就往后遍历,直到节点不重复即可。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        tmp = head
        while tmp!=None:
            nxt = tmp.next
            while nxt!=None and nxt.val== tmp.val:
                nxt = nxt.next
            tmp.next = nxt
            tmp = nxt
        return head

141. 判断单链表是否有环
思路:用快慢指针,如果有环,那么两个指针一定会相遇。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        # 快慢指针,如果有环,那么总归会相遇
        if head==None or head.next==None:
            return False
        fast = head.next
        slow = head
        flag = 0
        while fast!=slow:
            if fast==None or fast.next==None:
                return False
            fast = fast.next.next
            slow = slow.next
        return True

234.判断一个单链表是否是回文的。
思路1: 笨方法,遍历链表,将链表的节点值存储在数组中,再分别比较数组的头尾。
思路2: 先遍历一遍列表,记录长度。然后将链表分成两半,前面一半进行反转,然后与后面一半比较是否完全相等。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    '''另外用一个数组将链表节点的值存下来,空间复杂度O(N)'''
    '''
    def isPalindrome(self, head):
        vals = []
        while head:
            vals += head.val,
            head = head.next
        return vals == vals[::-1]
    '''
    def isPalindrome(self, head: ListNode) -> bool:
        # 先遍历一遍链表,记录链表长度。
        # 然后从中间将链表切成前后两半,并把前面一半进行反转,然后与后面一半进行比较
        if head==None or head.next==None:
            return True
        node = head
        count = 0
        while node!=None:
            count+=1
            node=node.next
            
        node = head
        prev = None
        for i in range(count//2):
            nxt = node.next
            node.next = prev
            prev = node
            node = nxt
        if count%2==0:
            h2 = node
        else:
            h2 = node.next
        h1 = prev
        while h1 and h2:
            if h1.val!=h2.val:
                return False
            h1 = h1.next
            h2 = h2.next
        return True

203. 给定一个链表和一个值val,将链表中值为val的节点都删除。
注意考虑头部节点需要删除的情况即可。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
        
        if head==None:
            return head
        if head.next==None:
            if head.val == val:
                return None
            else:
                return head
        while head!=None and head.val==val:
            head=head.next
        node = head
        while node!=None:
            if node.next!=None and node.next.val ==val:
                node.next = node.next.next
            else:
                node = node.next
        
        return head

160. 找两个链表的交点。
思路1: 先分别遍历一遍两个链表,记录他们的长度l1和l2,让长的那个链表先走|l1-l2|步,再同时走,就能走到交点处。
思路2: 更简洁的一个方法,两个链表同时从头节点走,其中一个走到头后,redirect到另一个链表的头节点。这样就能找到交点。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

'''
先分别记录两个链表的长度,然后让长的那个先走“差值”步,再同时走,就能一起走到交点处

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        if headA == None or headB==None:
            return None
        node1 = headA
        node2 = headB
        length1, length2 = 0, 0
        while node1!=None:
            length1+=1
            node1 = node1.next
        while node2!=None:
            length2+=1
            node2 = node2.next
        if length1>length2:
            for i in range(length1-length2):
                headA = headA.next
        else:
            for i in range(length2-length1):
                headB = headB.next
        while headA!=headB:
            headA = headA.next
            headB = headB.next
        return headA
'''
'''
更简洁的一个方法,两个链表同时从头节点走,其中一个走到头后,redirect到另一个链表的头节点。这样就能找到交点'''
class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        if headA == None or headB==None:
            return None
        node1 = headA
        node2 = headB
        while node1!=node2:
            node1 = headB if node1==None else node1.next
            node2 = headA if node2==None else node2.next
        return node1

707. 实现一个单链表类,包括一系列添加节点、删除节点的函数。

 class listNode:
    def __init__(self, val):
        self.val = val
        self.next = None
        
class MyLinkedList(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.head = None
        self.size = 0

    def get(self, index):
        """
        Get the value of the index-th node in the linked list. If the index is invalid, return -1.
        :type index: int
        :rtype: int
        """
        if index<0 or index>=self.size:
            return -1
        if self.head is None:
            return -1
        node = self.head
        for i in range(index):
            node = node.next
        return node.val

    def addAtHead(self, 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.
        :type val: int
        :rtype: None
        """
        newHead = listNode(val)
        newHead.next = self.head
        self.head = newHead
        self.size +=1
        
    def addAtTail(self, val):
        """
        Append a node of value val to the last element of the linked list.
        :type val: int
        :rtype: None
        """
        newnode = listNode(val)
        node = self.head
        if node ==None:
            self.head = newnode
        else:
            while node.next!=None:
                node = node.next
            node.next = newnode
        self.size+=1

    def addAtIndex(self, 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.
        :type index: int
        :type val: int
        :rtype: None
        """
        
        if index>0 and index <= self.size:
            node = self.head
            for i in range(index-1):
                node = node.next
            newnode = listNode(val)
            newnode.next = node.next
            node.next = newnode
            self.size +=1
        elif index<=0:
            self.addAtHead(val)
            

    def deleteAtIndex(self, index):
        """
        Delete the index-th node in the linked list, if the index is valid.
        :type index: int
        :rtype: None
        """
        if index>0 and index<self.size:
            node = self.head
            for i in range(index-1):
                node = node.next
            node.next = node.next.next
            self.size -=1
        elif index==0:
            self.head = self.head.next
            self.size -=1


# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)

1019.给定一个单链表,返回一个数组,数组中第i个元素是链表中第i个节点的next greater值,即最近的比第i个节点值大的节点值。
example:
Input: [1,7,5,1,9,2,5,1]
Output: [7,9,9,9,0,5,0,0]
思路:用一个栈来存储‘还没有遇到next greater的节点’,每次当前节点与栈顶进行比较。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

'''
用一个stack来存储‘还没有遇到next greater的节点’,每次当前节点与栈顶进行比较 '''
class Solution:
    def nextLargerNodes(self, head: ListNode) -> List[int]:
        if head==None:
            return None
        elif head.next == None:
            return [0]
        ans = []
        stack = []
        pos = -1
        while head:
            pos +=1
            ans.append(0)
            # 把栈顶元素和当前节点进行比较
            while stack and stack[-1][1]<head.val:
                # 小的话,就把栈顶元素弹出,并且写到ans数组中
                # 直到栈为空
                index, _ = stack.pop()
                ans[index] = head.val
            stack.append((pos,head.val))
            head = head.next
        return ans

817. 单链表的组成部分
给定一个单链表和一个数组,数组是单链表节点值的子集。返回一个number,代表数组中的值在单链表中分为几个相连部分。
example:
输入:
head: 0->1->2->3
G = [0, 1, 3]
输出: 2
Explanation: 0 and 1 are connected, so [0, 1] and [3] are the two connected components.
思路:遍历单链表的节点,如果节点值在数组中出现,那么往后遍历,直到不出现则出现断点,就表示number+=1。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    '''
    def numComponents(self, head: ListNode, G: List[int]) -> int:
        # 遍历单链表,然后看连续的链表部分是否出现在list中
        node = head
        count = 0
        while node!=None:
            if node.val in G:
                while node!=None and node.val in G:
                    node = node.next
                count+=1
            if node!=None:
                node = node.next
        return count
    '''
    #更简洁的写法
    def numComponents(self, head, G):
        setG = set(G)
        res = 0
        while head:
            if head.val in setG and (head.next == None or head.next.val not in setG):
                res += 1
            head = head.next
        return res

445. 给定两个单链表,分别表示两个整数,返回两个整数的和。且题目要求不能反转链表。
example:
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7
思路:由于不能反转链表,那么我想到的只能是把数存下来,相加后再构造新的链表。有更好的方法会再更新。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        # 不能反转链表
        # 第一个方法,将链表遍历后,得到数字,相加后再构造一个链表
        num1, num2 = 0,0
        while l1!=None:
            num1 = num1*10 + l1.val
            l1 = l1.next
        while l2!=None:
            num2 = num2*10 + l2.val
            l2 = l2.next
        x = num1+num2
        
        head = ListNode(0)
        if x == 0: return head
        while x:
            v, x = x%10, x//10
            head.next, head.next.next = ListNode(v), head.next
            
        return head.next

328. 给定一个单链表,把链表中的奇数节点都放到前面,偶数节点放到后面,且不改变奇数之间和偶数之间的相对顺序。
思路:与86题相似,建立两个空节点,然后奇数偶数分别连到后面,再合并链表。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def oddEvenList(self, head):
        dummy1 = odd = ListNode(0)
        dummy2 = even = ListNode(0)
        while head:
            odd.next = head
            even.next = head.next
            odd = odd.next
            even = even.next
            head = head.next.next if even else None
        odd.next = dummy2.next
        return dummy1.next

725. 给定一个单链表,和一个数字k,要求把链表分为k个部分,且每个部分的元素个数相差不超过1。
example:
Input: root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
思路:首先考虑k比链表长度小的情况,直接分割即可。其他的,先遍历链表,记录长度len,len//k表示每个组元素的最少个数,len%k=num表示多的元素个数,分别在前num个块中加上1个元素。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]:
        # 先记录链表长度length,然后length/k,余数yushu表示多的,那么在前yushu个段加1个
        node = root
        length = 0
        while node!=None:
            length+=1
            node = node.next
        
        ans =[]
        node = root
        
        shang = length//k
        yushu = length%k
        
        for i in range(k):
            head = ListNode(0)
            s = head
            if i<yushu:
                for j in range(shang+1):
                    head.next = node
                    node = node.next
                    head = head.next
            else:
                for j in range(shang):
                    head.next = node
                    node = node.next
                    head = head.next
            head.next = None
            ans.append(s.next)
        return ans

24. 交换链表中每两个相邻的节点。
example:
Given 1->2->3->4, you should return the list as 2->1->4->3.

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def swapPairs(self, head):
        pre, pre.next = self, head
        while pre.next and pre.next.next:
            a = pre.next
            b = a.next
            pre.next, b.next, a.next = b, a, b.next
            pre = a
        return self.next

430. 把一个层级的,含有子节点的双向链表进行flatten,表示成一个新的双向链表。
example:
Leetcode 单链表题型总结_第1张图片
思路:用一个栈来存储4、9节点。即遇到有子节点的节点,将后面的节点入栈。遍历到最后一层的最后节点后,开始出栈,将节点加到后面,直到栈为空。

"""
# Definition for a Node.
class Node:
    def __init__(self, val, prev, next, child):
        self.val = val
        self.prev = prev
        self.next = next
        self.child = child
"""
class Solution:
    # 每次遇到有child节点的节点,就把next入栈。遍历到最后之后,再从栈里pop出节点加在后面
    def flatten(self, head: 'Node') -> 'Node':
        stack = []
        node = head
        prev = node
        while node:
            if node.child!=None:
                if node.next:
                    stack.append(node.next)
                node.child.prev = node
                node.next = node.child
                node.child = None
            if not node.next and len(stack):
                curr = stack.pop()
                curr.prev = node
                node.next = curr
            node = node.next
        return head

1171. 给定一个单链表,删除其中和为0的部分。
example:
Input: head = [1,2,-3,3,1]
Output: [3,1]
Note: The answer [1,2,1] would also be accepted.
思路:用一个字典来存储当前的累加值,如果累加值出现重复,那么说明有和为0的部分存在。把这部分节点删去,同时注意删去字典中存储的这部分节点累加值。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeZeroSumSublists(self, head: ListNode) -> ListNode:
        # 用一个值来存当前的累加和
        # 再用一个字典来存累加和出现的次数
        node = head
        sums, zidian = 0, {}
        while node:
            sums += node.val
            if sums ==0:
                head = node.next
                zidian.clear()
            else:
                if sums not in zidian:
                    zidian[sums] = node
                else:
                    #zidian[sums].next = node.next
                    pre = zidian[sums]
                    sums2 = sums + pre.next.val
                    while sums2 != sums:
                        curr = zidian[sums2]
                        del zidian[sums2]
                        sums2 += curr.next.val
                    pre.next = node.next  
                #zidian[sums] = None
            node = node.next
        
        return head

86. 给定一个单链表和一个值x,把链表中小于x的节点放在前面,大于x的节点放到后面。
example:
Input: head = 1->4->3->2->5->2, x = 3
Output: 1->2->2->4->3->5
思路:和奇偶划分类似,构造两个新的节点。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def partition(self, head: ListNode, x: int) -> ListNode:
        l1 = ListNode(0)
        l2 = ListNode(0)
        s1,s2 = l1, l2
        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 = s2.next
        return s1.next

你可能感兴趣的:(leetcode)