格式:
题号+题名+简单思路+code
※T743: 网络延迟时间
- 暴力遍历每一条可以被放松的路径
- O ( N N + E l o g ( E ) ) O(N^N+Elog(E)) O(NN+Elog(E)) 时间复杂度
var MAXINT int = 1<<31-1
type Edge struct {
to int
time int
}
func networkDelayTime(times [][]int, N int, K int) int {
distances:=map[int]int{}
graph:=map[int][]Edge{}
for i:=1;i<=N;i++ {
distances[i]=MAXINT
graph[i]=[]Edge{}
}
distances[K]=0
for i:=0;i<len(times);i++ {
ti:=times[i]
graph[ti[0]]=append(graph[ti[0]],Edge{ti[1],ti[2]})
}
dfs(graph,distances,K)
totalTime:=0
for _,v:=range distances {
if v==MAXINT {
return -1
}
if v>totalTime {
totalTime=v
}
}
return totalTime
}
func dfs(graph map[int][]Edge, distances map[int]int,K int) {
tmp:=graph[K]
time:=distances[K]
for i:=0;i<len(tmp);i++ {
if time+tmp[i].time<distances[tmp[i].to] {
distances[tmp[i].to]=time+tmp[i].time
dfs(graph,distances,tmp[i].to)
}
}
}
- Dijsktra算法
- O(NlogN)时间复杂度
- 索引优先队列实现(《算法四》)
import "container/heap"
type Edge struct {
to int
time int
index int
}
type TimeHeap []*Edge
func (t TimeHeap) Len() int {
return len(t)
}
func (t TimeHeap) Less(i int, j int) bool {
return t[i].time-t[j].time <0
}
func (t TimeHeap) Swap(i int, j int) {
t[i],t[j]=t[j],t[i]
t[i].index,t[j].index=i,j
}
func (t *TimeHeap) Push(i interface{}) {
tmp:=i.(*Edge)
tmp.index=t.Len()
*t=append(*t,tmp)
}
func (t *TimeHeap) Pop() interface{} {
x:=(*t)[len(*t)-1]
*t=(*t)[:len(*t)-1]
x.index=-1
return x
}
func (t *TimeHeap) Update(e *Edge,time int) {
e.time=time
heap.Fix(t,e.index)
}
var MAXINT int=int(^uint(0) >> 1)
func networkDelayTime(times [][]int, N int, K int) int {
graph:=make(map[int][]Edge,N)
minL:=make(map[int]int,N)
for i:=1;i<=N;i++ {
graph[i]=[]Edge{}
minL[i]=MAXINT
}
for i:=0;i<len(times);i++ {
ti:=times[i]
graph[ti[0]]=append(graph[ti[0]],Edge{ti[1],ti[2],-1})
}
totalTime:=0
memo:=make(map[int]*Edge,0)
start:=&Edge{K,0,-1}
memo[K]=start
minL[K]=0
timeheap:=&TimeHeap{start}
for timeheap.Len()>0 {
edge:=heap.Pop(timeheap).(*Edge)
delete(memo,edge.to)
tmp:=graph[edge.to]
for i:=0;i<len(tmp);i++ {
n:=tmp[i].to
d:=tmp[i].time
if edge.time+d<minL[n] {
minL[n]=edge.time+d
if point,ok:=memo[n];ok {
timeheap.Update(point,minL[n])
} else {
start=&Edge{n,minL[n],-1}
heap.Push(timeheap,start)
memo[n]=start
}
}
}
}
for i:=range minL {
if minL[i]==MAXINT {
return -1
}
if minL[i]>totalTime {
totalTime=minL[i]
}
}
return totalTime
}
- 不进行Update,仅Push和去重
import "container/heap"
type Edge struct {
to int
time int
}
type TimeHeap []Edge
func (t TimeHeap) Len() int {
return len(t)
}
func (t TimeHeap) Less(i int, j int) bool {
return t[i].time-t[j].time <0
}
func (t TimeHeap) Swap(i int, j int) {
t[i],t[j]=t[j],t[i]
}
func (t *TimeHeap) Push(i interface{}) {
*t=append(*t,i.(Edge))
}
func (t *TimeHeap) Pop() interface{} {
x:=(*t)[len(*t)-1]
*t=(*t)[:len(*t)-1]
return x
}
var MAXINT int=int(^uint(0) >> 1)
func networkDelayTime(times [][]int, N int, K int) int {
graph:=make(map[int][]Edge,N)
minL:=make(map[int]int,N)
for i:=1;i<=N;i++ {
graph[i]=[]Edge{}
minL[i]=MAXINT
}
for i:=0;i<len(times);i++ {
ti:=times[i]
graph[ti[0]]=append(graph[ti[0]],Edge{ti[1],ti[2]})
}
totalTime:=0
memo:=make(map[int]interface{},0)
timeheap:=&TimeHeap{Edge{K,0}}
for timeheap.Len()>0 {
edge:=heap.Pop(timeheap).(Edge)
if _,ok:=memo[edge.to];ok {
continue
}
memo[edge.to]=nil
minL[edge.to]=edge.time
tmp:=graph[edge.to]
for i:=0;i<len(tmp);i++ {
n:=tmp[i].to
d:=tmp[i].time
if _,ok:=memo[n];!ok && edge.time+d<minL[n] {
heap.Push(timeheap,Edge{n,edge.time+d})
}
}
}
for i:=range minL {
if minL[i]==MAXINT {
return -1
}
if minL[i]>totalTime {
totalTime=minL[i]
}
}
return totalTime
}
T264: 丑数Ⅱ
- 练习预计算
- golang中使用全局变量
- 升序排列→堆排序
import (
"container/heap"
)
var pre []int=buildList()
type Stack []int
func (s Stack) Len() int {
return len(s)
}
func (s Stack) Less(i int, j int) bool {
return s[i]-s[j]<0
}
func (s Stack) Swap(i int,j int) {
s[i],s[j]=s[j],s[i]
}
func (s *Stack) Push(i interface{}) {
tmp:=*s
*s=append(tmp,i.(int))
}
func (s *Stack) Pop() interface{} {
tmp:=*s
x:=tmp[len(tmp)-1]
*s=tmp[:len(tmp)-1]
return x
}
func buildList() []int {
result:=make(map[int]interface{})
stack:=&Stack{1}
p_result:=make([]int,1690)
for index:=0;index<1690;index++ {
i:=heap.Pop(stack).(int)
if _,ok:=result[i];ok {
index--
continue
}
result[i]=nil
p_result[index]=i
heap.Push(stack,i*2)
heap.Push(stack,i*3)
heap.Push(stack,i*5)
}
return p_result
}
func nthUglyNumber(n int) int {
return pre[n-1]
}
- python中使用静态变量
from heapq import heappush,heappop
def buildList() -> List:
result=[0 for i in range(1690)]
memo=set()
heap=[1]
index=0
while index<1690:
i=heappop(heap)
if i in memo:
continue
memo.add(i)
result[index]=i
index+=1
heappush(heap,i*2)
heappush(heap,i*3)
heappush(heap,i*5)
return result
class Solution:
pre=buildList()
def nthUglyNumber(self, n: int) -> int:
return self.pre[n-1]
※T215: 数组中的第K大元素
- 快速选择算法
- 适用于有重复数组
- 最好时间复杂度O(N)
func findKthLargest(nums []int, k int) int {
return assist(nums,0,len(nums)-1,len(nums)+1-k)
}
func assist(nums []int,start int,end int,k int) int {
ans:=0
ref:=nums[start]
i1:=start
i2:=end
for end>start {
for ;end>start;end-- {
if nums[end]<ref {
nums[start]=nums[end]
break
}
}
for ;end>start;start++ {
if nums[start]>ref {
nums[end]=nums[start]
break
}
}
}
if k>start+1 {
ans=assist(nums,start+1,i2,k)
} else if k<start+1 {
ans=assist(nums,i1,start-1,k)
} else {
ans=ref
}
return ans
}
- 最小堆
- O(NlogK)
import "container/heap"
type Stack []int
func (s Stack) Len() int {
return len(s)
}
func (s Stack) Less(i int, j int) bool {
return s[i]-s[j]<0
}
func (s Stack) Swap(i int,j int) {
s[i],s[j]=s[j],s[i]
}
func (s *Stack) Push(i interface{}) {
*s=append(*s,i.(int))
}
func (s *Stack) Pop() interface{} {
tmp:=*s
x:=tmp[len(tmp)-1]
*s=tmp[:len(tmp)-1]
return x
}
func findKthLargest(nums []int, k int) int {
if len(nums)==0 {
return -1
}
stack:=&Stack{}
for i:=0;i<len(nums);i++ {
heap.Push(stack,nums[i])
if stack.Len()>k {
heap.Pop(stack)
}
}
return heap.Pop(stack).(int)
}
剑指40: 最小的k个数
- 快速选择,找到第k-1个位置后,取前k个数即可
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
if k<=0:
return []
return self.assist(arr, k-1, 0, len(arr)-1)
def assist(self, arr, k, lo, hi):
start=lo
end=hi
tmp=arr[lo]
while lo<hi:
while lo<hi and arr[hi]>=tmp:
hi-=1
arr[lo]=arr[hi]
while lo<hi and arr[lo]<=tmp:
lo+=1
arr[hi]=arr[lo]
arr[lo]=tmp # 易错
if lo<k:
return self.assist(arr, k, lo+1, end)
elif lo>k:
return self.assist(arr, k, start, lo-1)
else:
return arr[:k+1]
T378: 有序矩阵中第K小元素
- 最大堆
- O ( N 2 l o g K ) O(N^2logK) O(N2logK)
from heapq import heappop,heappush
class Solution:
def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
if k<1 or k>len(matrix)*len(matrix):
return -1
heap=[]
for i in matrix:
for j in i:
heappush(heap,-j)
if len(heap)>k:
heappop(heap)
return -heappop(heap)
- 值域二分查找;类似问题(快速选择算法和BST找第K小元素)
- 针对有序矩阵结构
- 取ceil
- O(NlogH)
from math import ceil
class Solution:
def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
lo=matrix[0][0]
hi=matrix[-1][-1]
while lo<hi:
mid=ceil((hi-lo)/2)+lo
rank=self.getRank(matrix,mid)
if k<rank+1:
hi=mid-1
else:
lo=mid
return lo
def getRank(self,matrix:List[List[int]],value:int) -> int:
count=0
i=len(matrix)-1
j=0
while i>=0 and j<=len(matrix)-1:
if matrix[i][j]>=value:
i-=1
else:
count+=i+1
j+=1
return count
T347: 前K个高频元素
- 最小堆
- O(NlogK)
import "container/heap"
type item struct {
val int
count int
}
type minHeap []item
func (m minHeap) Len() int {
return len(m)
}
func (m *minHeap) Swap(i int,j int) {
(*m)[i],(*m)[j]=(*m)[j],(*m)[i]
}
func (m minHeap) Less(i int,j int) bool {
return m[i].count-m[j].count<0
}
func (m *minHeap) Push(i interface{}) {
*m=append(*m,i.(item))
}
func (m *minHeap) Pop() interface{} {
i:=(*m)[len(*m)-1]
*m=(*m)[:len(*m)-1]
return i
}
func topKFrequent(nums []int, k int) []int {
if len(nums)==0 {
return nil
}
memo:=map[int]int{}
for _,i := range nums {
if _,ok:=memo[i];ok {
memo[i]++
} else {
memo[i]=1
}
}
tmp:=&minHeap{}
for key,value := range memo {
heap.Push(tmp,item{key,value})
if tmp.Len() > k {
heap.Pop(tmp)
}
}
ans:=[]int{}
for _,v := range *tmp {
ans=append(ans,v.val)
}
return ans
}
※T407: 接雨水Ⅱ
- 类似T42: 接雨水解法2,该方法通过计算最外端中较小值来更新答案,同时更新新的最外端高度值
- 该题与解法2基本思路是一样的,不过在二维上需要根据最外圈的最小值来更新答案,即木桶原理
- 因此首先将最外圈作为边界存入最小堆,同时用数组记录已遍历过的位置;然后弹出最小高度,比较其四个方向中合理且未遍历的位置,如果能接水则更新答案,最后将二者较高的高度加入堆中(即更新最外圈),并记录该位置已遍历
import "container/heap"
type Item struct {
i int
j int
height int
}
type Item_pri []Item
func (this Item_pri) Len() int {
return len(this)
}
func (this Item_pri) Less(idx_i int, idx_j int) bool {
return this[idx_i].height-this[idx_j].height<0
}
func (this Item_pri) Swap(idx_i int, idx_j int) {
this[idx_i],this[idx_j]=this[idx_j],this[idx_i]
}
func (this *Item_pri) Push(x interface{}) {
*this=append(*this,x.(Item))
}
func (this *Item_pri) Pop() interface{} {
x:=(*this)[len(*this)-1]
*this=(*this)[:len(*this)-1]
return x
}
func trapRainWater(heightMap [][]int) int {
m:=len(heightMap)
if m==0 {
return 0
}
n:=len(heightMap[0])
minHeap:=&Item_pri{}
directs:=[4][2]int{{0,1},{0,-1},{1,0},{-1,0}}
ans:=0
visited:=make([][]bool,m)
for i:=0;i<m;i++ {
visited[i]=make([]bool,n)
}
for i:=0;i<m;i++ {
for j:=0;j<n;j++ {
if i==0 || j==0 || i==m-1 || j==n-1 {
heap.Push(minHeap,Item{i,j,heightMap[i][j]})
visited[i][j]=true
}
}
}
for minHeap.Len() >0 {
minX:=heap.Pop(minHeap).(Item)
for k:=0;k<4;k++ {
idx_i:=minX.i+directs[k][0]
idx_j:=minX.j+directs[k][1]
if idx_i>0 && idx_i<m && idx_j>0 && idx_j<n && !visited[idx_i][idx_j] {
if heightMap[idx_i][idx_j]<minX.height {
ans+=minX.height-heightMap[idx_i][idx_j]
heap.Push(minHeap,Item{idx_i,idx_j,minX.height})
} else {
heap.Push(minHeap,Item{idx_i,idx_j,heightMap[idx_i][idx_j]})
}
visited[idx_i][idx_j]=true
}
}
}
return ans
}