leetcode48. Rotate Image
题目描述
给定一个n*n的2维矩阵,顺时针旋转矩阵90度。(原地旋转)
原地旋转:直接修正矩阵,不要创建额外的2维矩阵。
例子
Example 1:
Given input matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],
rotate the input matrix in-place such that it becomes:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
Example 2:
Given input matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],
rotate the input matrix in-place such that it becomes:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]
思想
拆分旋转90°的操作。关于轴、对角线的操作容易实现。
首先以辅对角线为轴进行翻转;然后以中心竖线为轴进行翻转。
解法
复杂度:时间O(n^2),空间O(1)
class Solution(object):
def rotate(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: void Do not return anything, modify matrix in-place instead.
"""
n = len(matrix)
# 以辅对角线为轴翻转
for i in range(n):
for j in range(i+1, n):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
# 以中心竖线为轴翻转
for i in range(n):
for j in range(n//2):
matrix[i][j], matrix[i][-j-1] = matrix[i][-j-1], matrix[i][j]
leetcode31. Next Permutation
题目描述
实现下一个序列:重组数字得到比当前值大的下一个字典序。
如果该重组序列不存在,则重组至字典序最小的序列。
要求:原地调整,使用常数空间。
例子
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
思想
下一个序列,肯定是要把大数移到小数前面。
1)从后往前找第一个逆序的数对(a, b),a<b。则b为要移动的大数,记boundary为a;
2)在boundary后面的数中,找到大于boundary的最小值,移到a前面;
3)boundary后的元素升序排列。
解法
复杂度:时间O(n),空间O(1)
class Solution(object):
def nextPermutation(self, nums):
"""
:type nums: List[int]
:rtype: void Do not return anything, modify nums in-place instead.
"""
bound = -1
for i in range(len(nums)-1, 0, -1):
if nums[i] > nums[i-1]:
bound = i-1
break
if bound == -1:
nums.reverse() # nums[:] = nums[::-1]
else:
num = nums[bound]
for i in range(len(nums)-1, bound, -1):
if nums[i] > num:
nums[i], nums[bound] = nums[bound], nums[i]
nums[bound+1:] = nums[bound+1:][::-1]
return
leetcode23. Merge k Sorted Lists
题目描述
合并k个有序链表,返回成一个有序链表。
例子
Input:
[
1->4->5,
1->3->4,
2->6
]
Output: 1->1->2->3->4->4->5->6
思想
假设每个链表的平均长度是n。
(法1 - 递归)
合并2个有序链表时,可以两两比较,时间复杂度O(m+n)。
合并k个链表时,类似归并排序。
(法2 - 非递归)
合并k个有序链表,步骤肯定如下:
1)比较k个头指针,找到最小的一个,作为最终链表的头指针;
2)比较k-1个头指针和候选链表的第二个指针,找到最小的一个,作为链表的第二个元素
…
【方法】
k个元素找出最小的一个,考虑堆排序,时间复杂度O(klogk)
然后在k-1个元素中插入一个元素,调整堆,时间复杂度O(logk)
…
(python最小堆heap)
import heapq、heapq.heappush(heap, num) #插入元素、heapq.heappop(heap) # 弹出最小元素
解法1
递归,类似归并排序。
第一次两两合并进行了k/2次,每次处理2n个值;
第二次两两合并进行了k/4次,每次处理4n个值;
…
最后一次两两合并进行了k/(2^logk)次,每次处理2^logk*n个值。
所以总时间复杂度:
O((2n) * (k / 2) + (4n) * (k / 4) + (8n) * (k / 8) + … + (2^logk*n) * (k / (2 ^logk)) )=O(nklogk)
空间复杂度O(1)。
# 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
"""
if not lists:
return None
if len(lists) == 1:
return lists[0]
mid = len(lists) // 2
left = self.mergeKLists(lists[:mid])
right = self.mergeKLists(lists[mid:])
return self.merge2Lists(left, right)
def merge2Lists(self, head1, head2):
p = ListNode(-1)
pNode = p
while head1 and head2:
if head1.val < head2.val:
p.next = head1
head1 = head1.next
else:
p.next = head2
head2 = head2.next
p = p.next
if head1:
p.next = head1
else:
p.next = head2
return pNode.next
解法2
堆调整时间复杂度为O(logk),每个元素都要取一次O(nk)。
所以总时间复杂度为O(nklogk),空间复杂度O(k)。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
import heapq
class Solution(object):
def mergeKLists(self, lists):
"""
:type lists: List[ListNode]
:rtype: ListNode
"""
heap = []
for head in lists:
if head: # ★
heapq.heappush(heap, (head.val, head))
p = ListNode(-1)
pNode = p
while heap:
node = heapq.heappop(heap)[1]
if node.next:
heapq.heappush(heap, (node.next.val, node.next))
p.next = node
p = p.next
return pNode.next