56. 合并区间
思路:
(1)排序+双指针
不断判断left,right,next_left,next_right之间的关系,先sort一下使得next_left一定大于now_left。那么就只要判断以下情况,并做各自的处理。
时:O(nlogn) 空:O(nlogn)
class Solution(object):
def merge(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: List[List[int]]
"""
l = len(intervals)
if l == 1:
return intervals
ans = []
intervals.sort()
left = intervals[0][0]
right = intervals[0][1]
for i in range(1,l):
next_left = intervals[i][0]
next_right = intervals[i][1]
if next_left > right:
ans.append([left, right])
left = next_left
right = next_right
else:
if next_right > right:
right = next_right
if i == l-1: #注意判断到最后一个区间时要单独处理一下。
ans.append([left,right])
return ans
(2)排序+两两合并
同样先把数组按照left排序,然后就只需判断next_left、next_right与now_right之间的大小关系即可。如果next_left>now_right就把下一个区间append进答案数组;否则的话就判断next_right和now_right,如果next_right大就把now_right更新为next_right。
class Solution(object):
def merge(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: List[List[int]]
"""
intervals.sort()
ans = []
ans.append(intervals[0])
l = len(intervals)
for next_ in intervals[1:]:
if next_[0] > ans[-1][1]:#下一个区间的左端点>当前区间右端点直接加入答案
ans.append(next_)
else:
ans[-1][1] = max(ans[-1][1],next_[1])#下一个区间的左端点<=当前区间右端点就说明可以合并,判断下一个区间的右端点和当前区间的右端点哪个大以进行合并。
return ans
148. 排序链表
思路:
1、额外数组
(1)链表存入数组,数组排序后,按顺序修改链表结点的值。时:O(nlogn) 空:O(n)
(2)额外数组也可以不用排序,而是记录一下当前数的个数,这样就可以重建一个链表,返回这个链表的头结点。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def sortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
ans = []
index = head
while index:
ans.append(index.val)
index = index.next
ans.sort()
index = head
for i in ans:
index.val = i
index = index.next
return head
2、归并排序
首先要切分链表、写好merge函数,再用递归实现归并。时:O(nlogn) 空:O(logn)
每次把链表切分一半,找到中点。递归切分,最后再递归中逐层merge。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def sortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
def find_mid(head): #把链表拆成2部分,分别返回两部分的头结点
fast = slow = head
while fast.next and fast.next.next:
fast = fast.next.next
slow = slow.next
tmp = slow.next
slow.next = None
return head,tmp
def merge(head1,head2): #合并2个有序数组
if not (head1 and head2):
if not head1:
return head2
else:
return head1
dummy = ListNode(-1)
pre = dummy
while head1 and head2:
if head1.val < head2.val:
pre.next = head1
head1 = head1.next
else:
pre.next = head2
head2 = head2.next
pre = pre.next
if head1:
pre.next = head1
if head2:
pre.next = head2
return dummy.next
def sort_fun(head): #递归实现不断拆分合并
if not head or not head.next:
return head
first, second = find_mid(head)
return merge(sort_fun(first),sort_fun(second))
return sort_fun(head)
3、自底向上的归并排序
时:O(nlogn) 空:O(1)
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution(object):
def sortList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
dummy = ListNode(-1)
dummy.next = head
tmp = head
length = 0
while tmp:
length += 1
tmp = tmp.next
step = 1
while step < length:
cur = dummy.next #下一组没有处理的头结点
tail = dummy #上一组处理好的头结点
while cur:
left = cur
right = self.cut(cur,step)
cur = self.cut(right,step) #更新没处理的头结点
tail.next = self.merge(left, right) #把处理好的挂到末尾
while tail.next: #更新处理好的尾结点
tail = tail.next
step <<= 1 #注意左移1位不是2位,用不好别用
return dummy.next
def cut(self, head, size):
size -= 1#为了保存前一个结点
while head and size:
head = head.next
size -= 1
if not head:#可能出现不够size的情况
return None
tmp = head.next
head.next = None
return tmp
def merge(self, head1, head2):
if not (head1 and head2):
if not head1:
return head2
else:
return head1
dummy = ListNode(-1)
pre = dummy
while head1 and head2:
if head1.val < head2.val:
pre.next = head1
head1 = head1.next
else:
pre.next = head2
head2 = head2.next
pre = pre.next
if head1:
pre.next = head1
if head2:
pre.next = head2
return dummy.next
274. H 指数
思路
理解题意需要一会,自己举几个例子就明白了,发现降序排列后,只有citations[i]的值比i+1的大或者相等的时候才满足,如果citations[i]<i+1那就不满足了,h最大就是i+1了。
1、 排列+查找
先降序排列,再顺序查找什么时候不符合题意就break,返回ans。时O(nlogn) 空O(nlogn)都是排序的复杂度。
class Solution(object):
def hIndex(self, citations):
"""
:type citations: List[int]
:rtype: int
"""
citations.sort(reverse = True)
ans = 0
for i, num in enumerate(citations):
if num < i+1:
break
ans+=1
return ans
2、计数排序
开辟一个数组用来记录当前引用次数的论文有几篇。根据定义,H 指数不可能大于总的论文发表数,所以对于引用次数超过论文发表数的情况,可以将其按照总的论文发表数来计算即可。
这样就限制了参与排序的数的大小为[0,n](其中 n 为总的论文发表数),使得计数排序的时间复杂度降低到 O(n)。最后从后向前遍历数组 ,对于每个0≤i≤n,在数组r 中得到大于或等于当前引用次数 i 的总论文数。当找到一个 H 指数时跳出循环,并返回结果。
时O(n) 空O(n)
class Solution(object):
def hIndex(self, citations):
"""
:type citations: List[int]
:rtype: int
"""
length = len(citations)
arr = [0]*(length+1)
ans = 0
for i,num in enumerate(citations):
if num>=length:
arr[length] += 1
else:
arr[num] += 1
for i in range(length,-1,-1):
ans += arr[i]
if ans>=i:
return i
return 0