LeetCode算法题-链表类
1.将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 (可以参照第2的merge2List实现)
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-two-sorted-lists
易错点:
(1)没考虑其中一个是空链表情况
(2)往前插入和往后插入的情况处理没想清楚
最后提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def mergeTwoLists(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
if l1 is None:
return l2
if l2 is None:
return l1
head = None
cur = l1
l2_cur = l2
while l2_cur is not None:
l2_cur_tmp = l2_cur.next
if cur.val > l2_cur.val:
head = l2_cur
l2_cur.next = cur
cur = l2_cur
else:
if head is None:
head = cur
while cur.next is not None and cur.next.val <= l2_cur.val:
cur = cur.next
l2_cur.next = cur.next
cur.next = l2_cur
cur = cur.next
l2_cur = l2_cur_tmp
return head
2.合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
易错点:
(1)比较容易想到第1个和第2个合并,然后再和第3个合并,但这属于暴力破解法了
(2)还容易想到每次比较每个链表的最前面节点调最小的,比较的方法可以使用最小堆
(3)其实好的方法应该是分治思想,比如先每组两两结合,然后4,4结合,以此类推,做到时间复杂度为O(nlgk)
(4)实现merge2List函数使用一个head作为头指针,可使得程序更易读和写
最后提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
list_num = len(lists)
interval= 1
while interval < list_num:
for i in range(0, list_num - interval, interval * 2):
lists[i] = self.merge2Lists(lists[i], lists[i+interval])
interval *= 2
return lists[0] if list_num > 0 else None def merge2Lists(self, l1, l2):
pre_cur = head = ListNode(0)
cur = l1
head.next = cur
while l2 != None:
l2_next = l2.next
if cur is None or cur.val > l2.val:
l2.next = cur
pre_cur.next = l2
pre_cur = l2
else:
while cur.next != None and l2.val >= cur.next.val:
cur = cur.next
l2.next = cur.next
cur.next = l2
pre_cur = cur
cur = cur.next
l2 = l2_next
return head.next
官方对于merge2Lists有个更优的解放:
def merge2Lists(self, l1, l2):
point = head = ListNode(0)
while l1 and l2:
if l1.val <= l2.val:
point.next = l1
l1 = l1.next
else:
point.next = l2
l2 = l1
l1 = point.next.next
point = point.next
if l1:
point.next = l1
else:
point.next = l2
return head.next
优点:当两个链表长度相差较大时,时间复杂度是O( min( l1_len, l2_len ) )
实现思路:
point始终和l1保持在一条链表上,方便判断
3.给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs
易错点:
(1)两两交换后,没有考虑前面的指向,比如交换了3和4,但却没有把1的指向指向4,导致输出结果为2->1->3,这是我一开始犯的错
(2)增加一个pre指针头部可以让程序逻辑简化
最后提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def swapPairs(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
pre = ListNode(0)
pre.next = head
first = head
head = pre
while first and first.next:
second = first.next
first.next = second.next
second.next = first
pre.next = second
pre = first
first = first.next
return head.next
4.给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例 :
给定这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group
易错点和关键点:
(1)首先联系到链表的翻转算法逻辑,每个k个翻转一次就好,最后一个可能不够k,所以遍历时发现不够就再翻转一次即返回之前那样
(2)处理每段k个这里的细节第一版代码处理的很繁琐,这里想了许久,实现思想如下图
当处理完1,2,3,4时,1指向5,但当处理完5,6,7,8时,1应改为指向8
第一版提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def reverseKGroup(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
if k <= 0:
return None
if k == 1:
return head
pre_list_node = None
cur = head
head = None
while cur != None:
ret = self.reverse_k_list(cur, k)
if ret == cur:
break
if pre_list_node != None:
pre_list_node.next = ret
pre_list_node = cur
if not head:
head = ret
cur = cur.next
return head if head else cur def reverse_k_list(self, cur, k):
flag = 0
first = cur
pre = None
while cur and flag < k:
flag += 1
l_next = cur.next
cur.next = pre
pre = cur
cur = l_next
if flag < k:
cur = pre
pre = None
while flag > 0:
flag -= 1
l_next = cur.next
cur.next = pre
pre = cur
cur = l_next
else:
first.next = cur
return pre
经过优化修改后的版本:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def reverseKGroup(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
if k <= 0:
return None
if k == 1:
return head
pre_list_node = ListNode(0)
cur = head
head = pre_list_node
while cur != None:
ret = self.reverse_k_list(cur, k)
pre_list_node.next = ret
pre_list_node = cur
cur = cur.next
return head.next def reverse_k_list(self, cur, k, is_reverse_back=False):
flag = 0
first = cur
pre = None
while cur and flag < k:
flag += 1
l_next = cur.next
cur.next = pre
pre = cur
cur = l_next
if flag < k:
pre = self.reverse_k_list(pre, flag, is_reverse_back=True)
else:
if not is_reverse_back:
first.next = cur
return pre
这个版本的优化在于优化了一些繁琐的代码,比如再翻转可以利用原函数,找head更简单,使程序逻辑看上去更清晰
5.给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。
示例 1:
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2:
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-list
关键点和易错点:
(1)这道题思路很简单,一开始想到的就是跟倒数第几个类似的方法,这里多了对k取模操作,但不必通过走到最后一个None才知道哪个是要变头部的,因为我们有整个链表长度了,可以直接计算得到第几个
(2)计算第几个时注意要用l_len-k才是算第几个,否则是倒数的
连接成环再拆思路代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def rotateRight(self, head, k):
"""
:type head: ListNode
:type k: int
:rtype: ListNode
"""
if not head:
return head
tmp_head = head
l_len = 1
while tmp_head.next:
l_len += 1
tmp_head = tmp_head.next
tmp_head.next = head
k = k % l_len
k = l_len - k
tmp_head = head
pre = None
while k > 0:
pre = tmp_head
tmp_head = tmp_head.next
k -= 1
pre.next = None
head = tmp_head
return head
6.给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深拷贝。
示例:
输入:
{"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1}
解释:
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer
关键点和易错点:
(1)这道题的难点在于处理这个random,常规的方法很容易想到,用一个字典保存原节点对应新节点,然后遍历一遍即可
(2)第一种思路需要使用O(n)的空间,有一种巧妙的解法是O(1)的空间复杂度,但时间复杂度是O(3n),第一遍遍历复制节点并把新节点放到旧结点的前面,用next指针串起来,然后再遍历一遍处理random指针,最后一遍遍历处理next指针
第一种解法代码:
"""
# Definition for a Node.
class Node(object):
def __init__(self, val, next, random):
self.val = val
self.next = next
self.random = random
"""
class Solution(object):
def copyRandomList(self, head):
"""
:type head: Node
:rtype: Node
"""
if not head:
return None
record = {}
tmp_head = Node(head.val, None, None)
record[head] = tmp_head
while head:
if head not in record:
head2 = Node(head.val, None, None)
record[head] = head2
else:
head2 = record[head]
if head.next:
if head.next not in record:
head2_next = Node(head.next.val, None, None)
record[head.next] = head2_next
else:
head2_next = record[head.next]
head2.next = head2_next
if head.random:
if head.random not in record:
head2_random = Node(head.random.val, None, None)
record[head.random] = head2_random
else:
head2_random = record[head.random]
head2.random = head2_random
head = head.next
return tmp_head
第二种解法代码:
"""
# Definition for a Node.
class Node(object):
def __init__(self, val, next, random):
self.val = val
self.next = next
self.random = random
"""
class Solution(object):
def copyRandomList(self, head):
"""
:type head: Node
:rtype: Node
"""
if not head:
return None
ptr = head
while ptr:
new_node = Node(ptr.val, None, None)
new_node.next = ptr.next
ptr.next = new_node
ptr = new_node.next ptr = head
while ptr:
if ptr.random:
ptr.next.random = ptr.random.next
ptr = ptr.next.next ret_head = head.next
ptr = head
while ptr:
old_node = ptr.next
ptr.next = old_node.next
old_node.next = old_node.next.next if old_node.next else None
ptr = ptr.next return ret_head
7.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-cycle-ii
关键点和易错点:
(1)第一步应该判断出是否有环,可以采用快慢指针来找出
(2)根据快慢指针特性列出公式计算出如何找到环的开始点
很明显two_step走的路程肯定是one_step的两倍,所以可列出公式:
2 * D(one_step) = D(two_step)
= 2 (F + a) = F + n(a+b) + a
= F + a = n(a+b)
= F = n(a+b) - (a+b) +b
= F = (n-1)(a+b) + b
由于a+b是一个环路,所以如果从起点和相遇点同时走,这两个指针一定会在起始点相遇
提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def detectCycle(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
one_step = head
two_step = head
ptr1 = head
ptr2 = None
while two_step:
if two_step.next and two_step.next.next:
two_step = two_step.next.next
else:
break
one_step = one_step.next
if one_step == two_step:
ptr2 = two_step
break if ptr2:
while ptr1 != ptr2:
ptr1 = ptr1.next
ptr2 = ptr2.next
return ptr1
return None
8.对链表进行插入排序
插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。
插入排序算法:
插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/insertion-sort-list
关键点和易错点:
(1)这道题目看着很简单,但其实有几个是很难察觉到的,且不调试很难看出来,花了一个多钟才完成,复习时去重做一遍
(2)head是会变的,这里是个易错点,想当然的tmp_head = t_head.next写成了tmp_head = head,很难察觉
(3)中间插入过程中很容易忘记已排序的最后一个元素的指向应该改为指向在排的下一个元素,因为以前的插入排序是数组,所以没有考虑这个,换成指针这里很难察觉到,就错了,而且很难发现
(4)加上一个tail指针可以优化算法平均时间
提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def insertionSortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head:
return head
t_head = ListNode(0)
t_head.next = head
cur = head.next
tail = head
while cur:
cur_next = cur.next
tmp_head = t_head.next
pre = t_head
if tail.val > cur.val:
while tmp_head != cur and tmp_head.val <= cur.val:
pre = tmp_head
tmp_head = tmp_head.next
if tmp_head != cur:
cur.next = pre.next
pre.next = cur
tail.next = cur_next
else:
tail = cur
cur = cur_next
return t_head.next
9.编写一个程序,找到两个单链表相交的起始节点。
示例 1:
注意:
如果两个链表没有交点,返回 null.
在返回结果后,两个链表仍须保持原有的结构。
可假定整个链表结构中没有循环。
程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists
易错点和关键点:
(1)有点难想到可以根据路程来解决此题,解题思路是某条链表的走到尾后,再走另外一条链表头开始走,如果有相交的,则它们一定会相遇,因为路程相等,比如上面的图:4-1-8-4-5-5-0-1-8跟5-0-1-8-4-5-5-1-8这两者走的步数是一样的,都是走9步后到的,原理其实就是A+B=B+A
(2)要判断不相交,则可以用最后一个元素来判断,如果不相交最后一个元素肯定是不相同的
提交代码:
# 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 not headA or not headB:
return None
first_tail = None
curA = headA
curB = headB
while True:
if curA == curB:
return curA
if curA.next == None:
if first_tail:
if first_tail != curA:
return None
else:
first_tail = curA
curA = headB
else:
curA = curA.next
if curB.next == None:
if first_tail:
if first_tail != curB:
return None
else:
first_tail = curB
curB = headA
else:
curB = curB.next
10.给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。
请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。
示例 1:
输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL
示例 2:
输入: 2->1->3->5->6->4->7->NULL
输出: 2->3->6->7->1->5->4->NULL
说明:
应当保持奇数节点和偶数节点的相对顺序。
链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/odd-even-linked-list
关键点和易错点:
(1)这道题本身难度很小,但是要把它写到优雅,这是个难题
(2)用当前偶数节点来作为while里的判断可以保证当前奇数节点一定不是None的,所以节省了很多繁琐判断逻辑
提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def oddEvenList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head:
return head
even = head.next
odd_cur = head
even_cur = even
while even_cur and even_cur.next:
odd_cur.next = even_cur.next
odd_cur = odd_cur.next
even_cur.next = odd_cur.next
even_cur = even_cur.next
odd_cur.next = even
return head
11.给定两个非空链表来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储单个数字。将这两数相加会返回一个新的链表。
你可以假设除了数字 0 之外,这两个数字都不会以零开头。
进阶:
如果输入链表不能修改该如何处理?换句话说,你不能对列表中的节点进行翻转。
示例:
输入: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
输出: 7 -> 8 -> 0 -> 7
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/add-two-numbers-ii
关键点和易错点:
(1)这道题比较直观的想法是用递归,需要给比较短的那条链表前面插入几个0,使两者长度相同,然后递归回溯相加解决,因为题目说不能改变原始链表,所以要删除掉添加的,如果可以改变原始链表,其实翻转链表更简单
(2)其实可以使用双栈法实现,要注意的就是短的链表在到None时不要插入0填充,,这是我一开始犯的错
(3)往前面填充计算的单元,即头插法
提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
stack_l1 = []
stack_l2 = []
while l1 or l2:
if l1:
stack_l1.append(l1.val)
l1 = l1.next
if l2:
stack_l2.append(l2.val)
l2 = l2.next carry_flag = 0
tmp_head = ListNode(0)
while len(stack_l1) > 0 or len(stack_l2) > 0:
tmp1 = 0 if len(stack_l1) <= 0 else stack_l1.pop(-1)
tmp2 = 0 if len(stack_l2) <= 0 else stack_l2.pop(-1)
add_result = tmp1 + tmp2 + carry_flag
new_node = ListNode(add_result%10)
carry_flag = add_result / 10
new_node.next = tmp_head.next
tmp_head.next = new_node if carry_flag > 0:
new_node = ListNode(carry_flag)
new_node.next = tmp_head.next
tmp_head.next = new_node return tmp_head.next
12.给出一个以头节点 head 作为第一个节点的链表。链表中的节点分别编号为:node_1, node_2, node_3, ... 。
每个节点都可能有下一个更大值(next larger value):对于 node_i,如果其 next_larger(node_i) 是 node_j.val,那么就有 j > i 且 node_j.val > node_i.val,而 j 是可能的选项中最小的那个。如果不存在这样的 j,那么下一个更大值为 0 。
返回整数答案数组 answer,其中 answer[i] = next_larger(node_{i+1}) 。
注意:在下面的示例中,诸如 [2,1,5] 这样的输入(不是输出)是链表的序列化表示,其头节点的值为 2,第二个节点值为 1,第三个节点值为 5 。
示例 1:
输入:[2,1,5]
输出:[5,5,0]
示例 2:
输入:[2,7,4,3,5]
输出:[7,0,5,5,0]
示例 3
输入:[1,7,5,1,9,2,5,1]
输出:[7,9,9,9,0,5,0,0]
提示:
对于链表中的每个节点,1 <= node.val <= 10^9
给定列表的长度在 [0, 10000] 范围内
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-greater-node-in-linked-list
关键点和易错点:
(1)一看到这题目总让人感觉不简单的样子,然后就想到是不是可以使用归并排序思想来解决,但是链表其实做归并这种思路其实操作很不方便,而且复杂度是O(nlgn),我一开始就是卡死在这个思路了,正确的方法应该是放弃这个思路,寻找其它思路
(2)其实有点规律在这里面的,假设n-2,n-1都还没找到那个合适的值,已经说明了n-1肯定是比n-2小的,而且没有匹配到的都是这样递减的,是不是可以把匹配到的可以先抽出来,留下未匹配的,只要比较下最前面的未匹配的来决定是否要匹配之前的,这里其实就剪枝了,所以本题使用了一个栈来保存还未匹配的,此方法叫做单栈法
思维图解:
提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def nextLargerNodes(self, head):
"""
:type head: ListNode
:rtype: List[int]
"""
result = []
stack = []
cur = head
while cur:
result_index = len(result) - 1
while len(stack) > 0 and stack[len(stack)-1] < cur.val:
while result[result_index] != 0:
result_index -= 1
result[result_index] = cur.val
stack.pop(-1)
result.append(0)
stack.append(cur.val)
cur = cur.next
return result
13.给你一个单链表的引用结点 head。链表中每个结点的值不是 0 就是 1。已知此链表是一个整数数字的二进制表示形式。
请你返回该链表所表示数字的 十进制值 。
示例 1:
输入:head = [1,0,1]
输出:5
解释:二进制数 (101) 转化为十进制数 (5)
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-binary-number-in-a-linked-list-to-integer
关键点和易错点:
(1)这道题比较直观的是想到链表翻转来计算,但很难跟位运算联系起来(其实遇到0,1就应该往位运算方面去想才是正确的思路),用位运算完美解决此问题,所以很多算法有时就巧在会把知识融会贯通
提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def getDecimalValue(self, head):
"""
:type head: ListNode
:rtype: int
"""
result = 0
while head:
result <<= 1
result += head.val
head = head.next
return result
14.在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-list
关键点和易错点:
(1)看到题目要求的O(nlgn)的时间复杂度,我们就应该联想到快速排序、堆排序和归并排序等,快速排序只是平均时间复杂度是O(nlgn),最坏情况下是O(n²),用归并排序是比较方便且时间复杂度满足要求的,中间节点使用快慢指针来查找
(2)这里有个易错点是l1_head = self.sortList(head),我写成了l1_head = self.sortList(one_step),提交代码后错误了,看了n遍也没找到这个问题,这是非常容易错且不易发现的问题,传参时一定要谨慎再谨慎
提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def sortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head or not head.next:
return head one_step = head
two_step = head.next
while two_step and two_step.next:
one_step = one_step.next
two_step = two_step.next.next two_step = one_step.next
one_step.next = None
l1_head = self.sortList(head)
l2_head = self.sortList(two_step)
return self.merge(l1_head, l2_head) def merge(self, l1, l2):
tmp_head = ListNode(0)
cur = tmp_head
while l1 and l2:
if l1.val <= l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
if l1:
cur.next = l1
else:
cur.next = l2
return tmp_head.next
15.给你一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。
删除完毕后,请你返回最终结果链表的头节点。
你可以返回任何满足题目要求的答案。
(注意,下面示例中的所有序列,都是对 ListNode 对象序列化的表示。)
示例 :
输入:head = [1,2,3,-3,-2]
输出:[1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-zero-sum-consecutive-nodes-from-linked-list
易错点和关键点:
(1)一时很难想到可以使用前缀和来判断
(2)用hashmap来记录
(3)下面代码的while循环那里while delete_node is not head这里一开始想错了,这个是不用del的;还有del时需要判断下该值是否在hash中不然del直接抛异常了
提交代码:
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None class Solution(object):
def removeZeroSumSublists(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
tmp_head = ListNode(0)
tmp_head.next = head
sum_hash = {}
sum_hash[0] = tmp_head
pre_sum = 0
while head:
total_sum = pre_sum + head.val
pre_sum = total_sum
if total_sum in sum_hash:
tmp = sum_hash[total_sum]
delete_node = tmp.next
tmp.next = head.next
while delete_node is not head:
total_sum += delete_node.val
if total_sum in sum_hash:
del sum_hash[total_sum]
delete_node = delete_node.next
head = tmp.next
else:
sum_hash[total_sum] = head
head = head.next
return tmp_head.next
16.设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。
在链表类中实现这些功能:
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
示例:
MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2); //链表变为1-> 2-> 3
linkedList.get(1); //返回2
linkedList.deleteAtIndex(1); //现在链表是1-> 3
linkedList.get(1); //返回3
提示:
所有val值都在 [1, 1000] 之内。
操作次数将在 [1, 1000] 之内。
请不要使用内置的 LinkedList 库。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/design-linked-list
提交代码(双链表实现):
class ListNode(object): def __init__(self, val):
"""
Initialize ListNode
""" self.val = val
self.pre = None
self.next = None class MyLinkedList(object): def __init__(self):
"""
Initialize your data structure here.
""" self.list_head = ListNode(0)
self.list_len = 0 def get_index_node(self, index):
"""
Get the index-th node in the linked list, If the index is invaild, return None
:type index: int
:rtype: ListNode
""" if index >= self.list_len or index < 0:
return None cur = self.list_head.next
while index > 0:
index -= 1
cur = cur.next
return cur 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
""" node = self.get_index_node(index)
if node:
return node.val
else:
return -1 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
""" tmp = ListNode(val)
if self.list_head.next:
tmp.next = self.list_head.next
self.list_head.next.pre = tmp
else:
self.list_head.pre = tmp
tmp.next = self.list_head
self.list_head.next = tmp
tmp.pre = self.list_head
self.list_len += 1 def addAtTail(self, val):
"""
Append a node of value val to the last element of the linked list.
:type val: int
:rtype: None
""" tmp = ListNode(val)
if self.list_head.next:
last_node = self.list_head.pre
last_node.next = tmp
tmp.pre = last_node
tmp.next = self.list_head
self.list_head.pre = tmp
self.list_len += 1
else:
self.addAtHead(val) 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:
self.addAtHead(val)
elif index == self.list_len:
self.addAtTail(val)
else:
pre_node = self.get_index_node(index-1)
if pre_node:
tmp = ListNode(val)
tmp.next = pre_node.next
pre_node.next.pre = tmp
pre_node.next = tmp
tmp.pre = pre_node
self.list_len += 1 def deleteAtIndex(self, index):
"""
Delete the index-th node in the linked list, if the index is valid.
:type index: int
:rtype: None
""" node = self.get_index_node(index)
if not node:
return None if node.next is self.list_head and node.pre is self.list_head:
self.list_head.next = None
self.list_head.pre = None
elif node.next is self.list_head:
node.pre.next = self.list_head
self.list_head.pre = node.pre
else:
node.pre.next = node.next
node.next.pre = node.pre
self.list_len -= 1
LeetCode算法题-链表类的更多相关文章
- LeetCode算法题-Design LinkedList(Java实现)
这是悦乐书的第300次更新,第319篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第168题(顺位题号是707).设计链表的实现.您可以选择使用单链表或双链表.单链表中的 ...
- 【算法】LeetCode算法题-Merge Two Sorted List
这是悦乐书的第148次更新,第150篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第7题(顺位题号是21).合并两个已排序的链表并将其作为新链表返回. 新链表应该通过拼接 ...
- LeetCode算法题-Design HashMap(Java实现)
这是悦乐书的第299次更新,第318篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第167题(顺位题号是706).在不使用任何内置哈希表库的情况下设计HashMap.具体 ...
- LeetCode算法题-Kth Largest Element in a Stream(Java实现)
这是悦乐书的第296次更新,第315篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第164题(顺位题号是703).设计一个类来查找流中第k个最大元素.请注意,它是排序顺序 ...
- LeetCode算法题-Valid Palindrome II(Java实现)
这是悦乐书的第287次更新,第304篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第155题(顺位题号是680).给定非空字符串s,最多可以删除一个字符. 判断它是否是回 ...
- LeetCode算法题-Construct String from Binary Tree(Java实现)
这是悦乐书的第273次更新,第288篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第141题(顺位题号是606).构造一个字符串,该字符串由二叉树中的括号和整数组成,并具 ...
- LeetCode算法题-N-ary Tree Postorder Traversal(Java实现)
这是悦乐书的第269次更新,第283篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第136题(顺位题号是590).给定一个n-ary树,返回其节点值的后序遍历.例如,给定 ...
- LeetCode算法题-Maximum Depth of N-ary Tree(Java实现)
这是悦乐书的第261次更新,第274篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第128题(顺位题号是559).给定n-ary树,找到它的最大深度.最大深度是从根节点到 ...
- LeetCode算法题-Reverse String II(Java实现)
这是悦乐书的第256次更新,第269篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第123题(顺位题号是541).给定一个字符串和一个整数k,你需要反转从字符串开头算起的 ...
随机推荐
- 如何为非常不确定的行为(如并发)设计安全的 API,使用这些 API 时如何确保安全
原文:如何为非常不确定的行为(如并发)设计安全的 API,使用这些 API 时如何确保安全 .NET 中提供了一些线程安全的类型,如 ConcurrentDictionary<TKey, TVa ...
- 上传自己的 NuGet 包
参考:https://blog.csdn.net/gulijiang2008/article/details/41724927 STEP 1:在NuGet上注册并获取API Key STEP 2:下载 ...
- 系統启动直接进BIOS
- python-django中使用事务以及小坑
django中使用事务 一.导入事务模块 from django.db import transaction 二.对相应的业务进行事务操作 方式一:为整个函数进行事务操作 @transaction.a ...
- JML规格编程系列——OO Unit3分析和总结
本文是BUAA OO课程Unit3在课程讲授.三次作业完成.自测和互测时发现的问题,以及倾听别人的思路分享所引起个人的一些思考的总结性博客.主要包含JML相关梳理.SMT Solver验证.JML单元 ...
- Hook executed successfully but returned HTTP 403
jenkins配置gitlab的webhook,完成配置,测试结果显示 Hook executed successfully but returned HTTP 403 解决: 进入jenkins: ...
- Laravel5.6---从头做一个项目web
简介:类似论坛的项目,纯web,响应式,主要包含登录注册.支付.评论.富文本.文章列.个人中心等 目录: 1.初始化项目 ======================================= ...
- windows+phpstudy(apache) 以cgi方式运行python
Apache配置 在httpd.conf中查找DocumentRoot: +ExecCGI 支持cgi DocumentRoot "F:\phpStud\PHPTutorial\WWW&qu ...
- 百度云服务器CentOs6.8安装gnome图形化界面并通过VNC远程访问
一:安装gnome桌面 利用xshell 登陆上远程主机 依次执行下列命令: [root@lys]#yum groupinstall -y "X Window System" [r ...
- 【实战1】记一次提至administrator权限历程
本文首发于先知社区 https://xz.aliyun.com/t/5080 前言:这是一次挖掘cms通用漏洞时发现的网站,技术含量虽然不是很高,但是也拿出来和大家分享一下吧,希望能给一部分人带来收获 ...