算法练习--链表相关

合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。
新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:
在这里插入图片描述

输入: l 1 {l1} l1 = [1,2,4], l 2 {l2 } l2= [1,3,4]
输出:[1,1,2,3,4,4]   以列表 表示每个节点的value
 
示例 2:
输入: l 1 {l1} l1 = [], l 2 {l2} l2 = []
输出:[]   表示没有节点 None

示例 3:
输入:l1 = [], l2 = [0]
输出:[0]  表示有一个value为0的节点

提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 升序排列

python实现:双指针

# Definition for singly-linked list.
# class ListNode:   # 预定义好的  直接用就行
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:   # ListNode or None
        if not list1 and not list2:
            return None  # [] 代表空节点
        elif not list1 or not list2:
            return list1 if list1 else list2
        # 
        header = None
        p = None
        while list1 and list2:
            if list1.val <= list2.val:
                if header is None:
                    header = list1
                    p = list1
                else:
                    p.next = list1
                    p = list1
                list1 = list1.next

            else:
                if header is None:
                    header = list2
                    p = list2
                else:
                    p.next = list2
                    p = list2
                list2 = list2.next

        if list1:
            p.next = list1
        
        elif list2:
            p.next = list2
        
        return header

java实现
 

删除排序链表中的重复元素 1

给定一个已排序的链表的头 head , 删除重复的后继元素,使每个元素只出现一次 。返回 已排序的链表 。

示例 1:
在这里插入图片描述

输入:head = [1,1,2]
输出:[1,2]

示例 2:
在这里插入图片描述

输入:head = [1,1,2,3,3]
输出:[1,2,3]

python实现:递归算法

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None:
            return head

        # 至少两个节点
        cur = head
        if cur.val == cur.next.val:
            cur.next = cur.next.next
            return self.deleteDuplicates(head)
        else:
            cur.next = self.deleteDuplicates(cur.next)
			return head

java实现
在这里插入图片描述

删除排序链表中的重复元素 2

给一个已排序的链表的头 head , 删除原始链表中所有 重复数字的节点 ,返回该链表 。

重点:已排序

示例 1:
在这里插入图片描述

输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]
 
示例 2:
在这里插入图片描述

输入:head = [1,1,1,2,3]
输出:[2,3]

python实现: 递归解决

  • 情况1:删除头节点重复的部分,继续递归处理剩下的部分;
  • 情况2:保留头节点,继续处理剩下的部分
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None or head.next is None:
            return head
        # 至少两个节点
        cur = head
        if cur.val == cur.next.val: # 要删除头节点
            move = cur.next.next
            while move and cur.val == move.val: # 移动到不相等的节点
                move = move.next
            return self.deleteDuplicates(move)
        else:
            cur.next = self.deleteDuplicates(cur.next) # 保留头节点
        
        return head

同一段程序,多次提交,耗时和击败用户比率会不同;所以不用在乎这个击败比率。
在这里插入图片描述
java实现
pending

环形链表1

给一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。存在环 ,则返回 true 。 否则,返回 false 。

以下pos不作为参数

示例 1:
在这里插入图片描述
输入:head = [3,2,0,-4], pos = 1
输出:true

示例 2:
在这里插入图片描述

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:
在这里插入图片描述
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

进阶:你能用 O(1) 空间复杂度解决此问题吗?

python实现

# 辅助空间 + 循环
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        temp = []
        cur = head
        while cur:
            temp.append(cur)
            if cur.next in temp:  # python内置方法也慢
                return True
            cur = cur.next
        return False

# 双指针  一快 一慢   空间复杂度O(1)
# 快走两步  慢走一步  会在环内相遇
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        if head is None:
            return False
        
        slow_ptr = head  # 一次走一步
        fast_ptr = head  # 一次走两步
        while fast_ptr.next and fast_ptr.next.next:
            slow_ptr = slow_ptr.next
            fast_ptr = fast_ptr.next.next
            if fast_ptr is slow_ptr:
                return True
        
        return False

java双指针
在这里插入图片描述

环形链表2

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

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。
pos不传参,且不允许修改链表

示例 1:
在这里插入图片描述
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
 
示例 2:
在这里插入图片描述
输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
 
示例 3:
在这里插入图片描述

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。
 
python实现:

# 辅助空间 + 循环
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None:
            return None
        
        temp = []
        cur = head
        while cur:
            temp.append(cur)
            if cur.next in temp:
                return cur.next
            cur = cur.next
        return None

# 双指针  一快一慢   空间复杂度O(1)
# 快指针移动2步
# 漫指针移动1步
# 在环中相遇后,慢指针重置到head指针
# 然后两个指针均移动一步,直到再次相遇,即找到入环的节点
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None:
            return None
        slow_ptr = head
        fast_ptr = head
        has_circle = False
        while fast_ptr.next and fast_ptr.next.next:
            slow_ptr = slow_ptr.next
            fast_ptr = fast_ptr.next.next
            if fast_ptr is slow_ptr:
                has_circle = True
                break
            
        if has_circle:
            # 重置慢指针为head
            slow_ptr = head
            # 两个指针均移动一步,直到相遇
            while slow_ptr is not fast_ptr:
                slow_ptr = slow_ptr.next
                fast_ptr = fast_ptr.next

            # 相遇则为入环节点
            return fast_ptr
        
        return None

优化前后时间对比:
在这里插入图片描述

java实现
在这里插入图片描述

相交链表

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

你能否设计一个时间复杂度 O(m + n) 、仅用 O(1) 内存的解决方案?
m,n 分别为链表A B的节点数。

图示两个链表在节点 c1 开始相交:
在这里插入图片描述

示例 1:
在这里插入图片描述

输入:listA = [4,1,8,4,5], listB = [5,6,1,8,4,5]
skipA = 2, skipB = 3 intersectVal = 8,
输出:node 8 对象

 
示例 2:
在这里插入图片描述
输入:listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 intersectVal = 2,
输出:node 2
 
示例 3:
在这里插入图片描述
输入:listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 intersectVal = 0,
输出:null

python 实现
双指针 循环移动 直至相遇

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

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
        if headA is None or headB is None:
            return None

        pa = headA
        pb = headB
        while pa is not pb:
            pa = pa.next if pa else headB
            pb = pb.next if pb else headA
        
        return pa

也可以计算链表的长度差值,较长的链表指针移动长度差个步子。
 
 

反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:
在这里插入图片描述

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

 
示例 2:
在这里插入图片描述

输入:head = [1,2]
输出:[2,1]
 
示例 3:

输入:head = []
输出:[]

进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
python实现

在这里插入代码片

java实现
在这里插入图片描述

插入链表,然后删除指定值的节点

输入一个单向链表和一个节点的值,从单向链表中删除等于该值的节点,删除后如果链表中无节点则返回空指针。

链表的值不能重复。

构造过程,例如输入一行数据为:
6 2 1 2 3 2 5 1 4 5 7 2 2
则第一个参数6表示输入总共6个节点,第二个参数2表示头节点值为2,剩下的2个一组表示第2个节点值后面插入第1个节点值,为以下表示:
1 2 表示为
2->1
链表为2->1

3 2表示为
2->3
链表为2->3->1

5 1表示为
1->5
链表为2->3->1->5

4 5表示为
5->4
链表为2->3->1->5->4

7 2表示为
2->7
链表为2->7->3->1->5->4

最后的链表的顺序为 2 7 3 1 5 4

最后一个参数为2,表示要删掉节点为2的值
删除 结点 2

则结果为 7 3 1 5 4

测试用例保证输入合法

输入描述:
输入一行,有以下4个部分:
1 输入链表结点个数
2 输入头结点的值
3 按照格式插入各个结点
4 输入要删除的结点的值

输出描述:
输出一行
输出删除结点后的序列,每个数后都要加空格

示例1
输入:
5 2 3 2 4 3 5 2 1 4 3
输出:
2 5 4 1

示例2
输入:
6 2 1 2 3 2 5 1 4 5 7 2 2
输出:
7 3 1 5 4

python
使用列表(瞎扯)

while True:
    try:
        l = input().split()
        head = l[1]
        rm = l[-1]
        l = l[2:-1]
        res = [head]
        for i in range(0, len(l), 2):
            a = l[i]
            b = l[i+1]
            res.insert(res.index(b)+1, a)
 
        res.remove(rm)
        print(' '.join(res)+" ")
    except:
        break

使用链表:

class Node():
    def __init__(self, val=None, next=None):
        self.val = val
        self.next = next
    
class LinkedList():
    def __init__(self):
        self.head = Node()
        self.length = 0
        
    def insert(self, val1, val2):
        cur = self.head
        node = Node(val2)
        while cur:
            if cur.val == val1:
                node.next = cur.next
                cur.next = node
                break
            else:
                cur = cur.next  # 找不到插入点,则不插入
    
    def remove(self, val): # 只删除一个
        cur = self.head
        pre = None
        while cur:
            if cur.val == val:
                if not pre:
                    self.head = cur.next
                else:
                    pre.next = cur.next
                break
            else:
                pre = cur
                cur = cur.next
                
    def walk(self):
        cur = self.head
        while cur:
            print(cur.val, end=' ')
            cur = cur.next
        print()
        
while True:
    try:
        nums = list(map(int, input().split()))
        L = LinkedList()
        L.length, L.head.val = nums[0], nums[1]
        lst = nums[2:-1]
        i, j, pairs = 0, 1, []
        while i < len(lst):
            pairs.append((lst[i], lst[j]))
            i += 2
            j += 2
        for p in pairs:
            L.insert(p[1], p[0])
        L.remove(nums[-1])
        L.walk()
    except:
        break

猜你喜欢

转载自blog.csdn.net/weixin_45228198/article/details/132128442