1.检查是否所有字符出现次数相同 (hash计数略)
2.最小未被占据椅子的编号 (优先队列+模拟)
用两个优先队列来,一个用座位号+离开时间进行排序,另一个用座位号来排序,按时间顺序模拟就好
type friend struct {
arrive int
leave int
num int
}
type seat struct {
freeTime int
seatNum int
}
// 优先级队列需要实现heap的interface
type PriorityQueue []*seat
// 绑定Len方法
func (pq PriorityQueue) Len() int {
return len(pq)
}
// 绑定Less方法,这里用的是小于号,生成的是小根堆
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].freeTime < pq[j].freeTime
}
// 绑定swap方法
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
}
// 绑定put方法,将index置为-1是为了标识该数据已经出了优先级队列了
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
*pq = old[0 : n-1]
return item
}
// 绑定push方法
func (pq *PriorityQueue) Push(x interface{}) {
item := x.(*seat)
*pq = append(*pq, item)
}
type IntHeap []int // 定义一个类型
func (h IntHeap) Len() int { return len(h) } // 绑定len方法,返回长度
func (h IntHeap) Less(i, j int) bool { // 绑定less方法
return h[i] < h[j] // 如果h[i]<h[j]生成的就是小根堆,如果h[i]>h[j]生成的就是大根堆
}
func (h IntHeap) Swap(i, j int) { // 绑定swap方法,交换两个元素位置
h[i], h[j] = h[j], h[i]
}
func (h *IntHeap) Pop() interface{} { // 绑定pop方法,从最后拿出一个元素并返回
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func (h *IntHeap) Push(x interface{}) { // 绑定push方法,插入新元素
*h = append(*h, x.(int))
}
func smallestChair(times [][]int, targetFriend int) int {
friends := make([]friend, len(times))
for i := 0 ; i < len(times) ; i++ {
friends[i] = friend{arrive:times[i][0], leave:times[i][1], num:i}
}
sort.Slice(friends, func(i, j int) bool {
if friends[i].arrive < friends[j].arrive {
return true
}
return false
})
cur := 0
needFree := make(PriorityQueue, 0)
freeSeat := &IntHeap{}
for i := 0 ; i < len(friends) ; i++ {
if needFree.Len() != 0 && needFree[0].freeTime <= friends[i].arrive {
for needFree.Len() > 0 && needFree[0].freeTime <= friends[i].arrive {
val, _ := heap.Pop(&needFree).(*seat)
heap.Push(freeSeat, val.seatNum)
}
if friends[i].num == targetFriend {
return (*freeSeat)[0]
}
heap.Push(&needFree, &seat{freeTime:friends[i].leave, seatNum:(*freeSeat)[0]})
heap.Pop(freeSeat)
} else if freeSeat.Len() > 0 {
if friends[i].num == targetFriend {
return (*freeSeat)[0]
}
heap.Push(&needFree, &seat{freeTime:friends[i].leave, seatNum:(*freeSeat)[0]})
heap.Pop(freeSeat)
} else {
if friends[i].num == targetFriend {
return cur
}
heap.Push(&needFree, &seat{friends[i].leave, cur})
cur++
}
}
return 0
}
3.描述绘画结果 (差分)
题目已经给出了颜色不会相同的条件,同时只需要输出颜色的和,所以就用差分数组,把所有颜色和统计下来,由于没有相同的颜色,所以在一个颜色加入或者离开时,一定是一个可以输出的线段,需要用一个数组来记录端点,详情见代码。
func splitPainting(segments [][]int) [][]int64 {
diff := make([]int, 100001)
visited := make([]bool, 100001)
res := make([][]int64, 0)
for i := 0 ; i < len(segments) ; i++ {
diff[segments[i][0]] += segments[i][2]
diff[segments[i][1]] -= segments[i][2]
visited[segments[i][0]] = true
visited[segments[i][1]] = true
}
val := 0
start := 0
for i := 0 ; i < len(diff) ; i++ {
if visited[i] {
if val != 0 {
t := make([]int64, 3)
t[0] = int64(start)
t[1] = int64(i)
t[2] = int64(val)
res = append(res, t)
}
start = i
val += diff[i]
}
}
return res
}
4.队列中可以看到的人数 (单调栈)
转化一下就是要求num[i]右边第一个比他大的数的位置,以及中间的数的数量,注意一点,中间的数是可以被遮挡的。考虑从后向前遍历,维护一个递减栈,如果当前元素比栈顶大,则直接出栈,并统计数量,这个值就是当前元素能看到的人数,同时已经出栈的这些元素对后续的元素也没有影响,因为比当前元素小,会被挡住。
func canSeePersonsCount(heights []int) []int {
res := make([]int, len(heights))
s := make([]int, 0)
for i := len(heights) - 1; i >= 0 ; i-- {
for len(s) > 0 && heights[i] > heights[s[len(s) - 1]] {
res[i]++
s = s[:len(s) - 1]
}
if len(s) > 0 {
res[i]++
}
s = append(s, i)
}
return res
}