记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
第 11 天 哈希表
033. 变位词组
将字符串内字符从小到大排序 变成一个tag tag相同的说明字符串内字符出现情况相同
func groupAnagrams(strs []string) [][]string {
var m = make(map[string][]string)
for _, str := range strs {
s := []byte(str)
sort.Slice(s, func(i, j int) bool { return s[i] < s[j] })
tag := string(s)
m[tag] = append(m[tag], str)
}
var ans [][]string
for _, v := range m {
ans = append(ans, v)
}
return ans
}
034. 外星语言是否排序
map记录每个字母新的顺序
func isAlienSorted(words []string, order string) bool {
var m = make(map[string]int)
for i, c := range order {
m[string(c)] = i
}
for i := 0; i < len(words)-1; i++ {
var w1, w2 = words[i], words[i+1]
var l1, l2 = len(w1), len(w2)
var minl int
if l1 < l2 {
minl = l1
} else {
minl = l2
}
var same = true
for loc := 0; loc < minl; loc++ {
var c1 = string(w1[loc])
var c2 = string(w2[loc])
if m[c1] > m[c2] {
return false
} else if m[c1] < m[c2] {
same = false
break
} else {
continue
}
}
if l1 > minl && same {
return false
}
}
return true
}
035. 最小时间差
将所有时间点转化为分钟 0-1440
排序后比较相邻的时间差 最后比较开头和结尾
func findMinDifference(timePoints []string) int {
if len(timePoints) > 24*60 {
return 0
}
var l []int
for _, tp := range timePoints {
l = append(l, timeToInt(tp))
}
sort.Ints(l)
var ans = 1440 + l[0] - l[len(l)-1]
for i := 0; i < len(l)-1; i++ {
ans = min(ans, l[i+1]-l[i])
}
return ans
}
func min(i, j int) int {
if i < j {
return i
}
return j
}
func timeToInt(s string) int {
r := []rune(s)
ans := (int(r[0]-'0')*10+int(r[1]-'0'))*60 + int(r[3]-'0')*10 + int(r[4]-'0')
return ans
}
第 12 天 栈
036. 后缀表达式
遇到数字压入栈中
遇到运算符 取栈顶两个数字计算
将结果压入栈中
func evalRPN(tokens []string) int {
var l []int
for _, c := range tokens {
v, err := strconv.Atoi(c)
if err != nil {
var n = len(l) - 1
var v1, v2 = l[n-1], l[n]
l = l[:n-1]
switch c {
case "+":
l = append(l, v1+v2)
case "-":
l = append(l, v1-v2)
case "*":
l = append(l, v1*v2)
case "/":
l = append(l, v1/v2)
}
} else {
l = append(l, v)
}
}
return l[0]
}
037. 小行星碰撞
ans用来记录当前状态
如果ans为空或者行星为正 则直接加入ans中
如果行星为负 且前一个也为负 则永远不会消失 加入ans
只有当前一个为正 当前为负是会发生相撞
如果当前为负 将前面所有小于目前行星大小且运动方向为右的都去除 记录位置loc
如果位置loc>=0 说明ans中还有行星
如果ans中最后一个行星与当前大小相同方向相反 则两个都消失
若ans最后一个为证 则当前行星消失 记录ans = ans[0:loc]
否则当前行星存在 ans = append(ans, cur)
func asteroidCollision(asteroids []int) []int {
var ans []int
for _, cur := range asteroids {
if len(ans) == 0 || cur > 0 {
ans = append(ans, cur)
continue
}
pre := ans[len(ans)-1]
if pre < 0 {
ans = append(ans, cur)
continue
}
var loc = len(ans) - 1
for loc >= 0 && ans[loc] > 0 && ans[loc]+cur < 0 {
loc -= 1
}
if loc >= 0 {
if ans[loc]+cur == 0 {
ans = ans[:loc]
} else {
ans = ans[:loc+1]
if ans[loc] < 0 {
ans = append(ans, cur)
}
}
} else if loc == -1 {
ans = []int{cur}
}
}
return ans
}
038. 每日温度
单调栈
如果栈为空 或者栈顶温度比当前高 则将当前位置入栈
将所有比当前温度低的栈顶元素弹出 更新这些位置的值
func dailyTemperatures(temperatures []int) []int {
var n = len(temperatures)
var ans = make([]int, n)
var stack []int
for i, temp := range temperatures {
var n = len(stack)
if n == 0 || temperatures[stack[n-1]] >= temp {
stack = append(stack, i)
} else {
var loc = n - 1
for loc >= 0 && temperatures[stack[loc]] < temp {
ans[stack[loc]] = i - stack[loc]
loc -= 1
}
stack = stack[:loc+1]
stack = append(stack, i)
}
}
return ans
}
第 13 天 栈
039. 直方图最大矩形面积
单调栈 stack用来存放位置i
栈为空 或者当前位置值比栈顶位置值大时 入栈
如果当前值比较小 将栈顶值弹出
计算栈顶值能够围成的面积
h为栈顶值的高度 h=heights[stack[-1]]
w为栈顶值能够围成的宽度
如果此时栈顶值是唯一的值 那么w = i
否则w为当前坐标-栈顶第二个的坐标-1 w = i-stack[-2]-1
area = w*h
func largestRectangleArea(heights []int) int {
heights = append(heights, 0)
var ans int
var stack []int
for i, height := range heights {
var n = len(stack)
if n == 0 || heights[stack[n-1]] < height {
stack = append(stack, i)
continue
}
var loc = n - 1
for loc >= 0 && heights[stack[loc]] >= height {
var h = heights[stack[loc]]
var w int
if loc == 0 {
w = i
} else {
w = i - stack[loc-1] - 1
}
var area = h * w
ans = max(ans, area)
loc -= 1
}
stack = stack[:loc+1]
stack = append(stack, i)
}
return ans
}
func max(i, j int) int {
if i > j {
return i
}
return j
}
040. 矩阵中最大的矩形
从第一行开始遍历
在第i行 压缩前i行为一行 从底部网上连续的1累加可以看成高度
转换为第39题 求最大矩形面积
func maximalRectangle(matrix [][]byte) int {
if len(matrix) == 0 || len(matrix[0]) == 0 {
return 0
}
var ans = 0
var n, m = len(matrix), len(matrix[0])
for i := 0; i < n; i++ {
var curr = make([]int, m)
for j := i; j < n; j++ {
for k := 0; k < m; k++ {
if i == j {
if matrix[i][k] == '1' {
curr[k] = 1
}
} else {
if matrix[j][k] == '1' {
curr[k] += 1
} else {
curr[k] = 0
}
}
}
ans = max(ans, largestRectangleArea(curr))
}
}
return ans
}
func largestRectangleArea(heights []int) int {
heights = append(heights, 0)
var ans int
var stack []int
for i, height := range heights {
var n = len(stack)
if n == 0 || heights[stack[n-1]] < height {
stack = append(stack, i)
continue
}
var loc = n - 1
for loc >= 0 && heights[stack[loc]] >= height {
var h = heights[stack[loc]]
var w int
if loc == 0 {
w = i
} else {
w = i - stack[loc-1] - 1
}
var area = h * w
ans = max(ans, area)
loc -= 1
}
stack = stack[:loc+1]
stack = append(stack, i)
}
return ans
}
func max(i, j int) int {
if i > j {
return i
}
return j
}
第 14 天 队列
041. 滑动窗口的平均值
链表连接模拟滑动窗口
记录头尾
添加在尾部 并将头部往后移动
type Node struct {
Next *Node
Val int
}
type MovingAverage struct {
Size int
Count int
Sum int
Head *Node
Tail *Node
Init bool
}
/** Initialize your data structure here. */
func Constructor(size int) MovingAverage {
var mv MovingAverage
mv.Size = size
mv.Head = new(Node)
mv.Tail = mv.Head
return mv
}
func (this *MovingAverage) Next(val int) float64 {
var newNode = new(Node)
newNode.Val = val
this.Sum += val
this.Tail.Next = newNode
this.Tail = newNode
if !this.Init {
this.Init = true
this.Head = this.Tail
}
if this.Count < this.Size {
this.Count += 1
} else {
var next = this.Head.Next
this.Sum -= this.Head.Val
this.Head.Next = nil
this.Head = next
}
return float64(this.Sum) / float64(this.Count)
}
042. 最近请求次数
链表双指针
在结尾添加新数
从开头去除已经过期的数
记录总数
type Node struct {
Val int
Next *Node
}
type RecentCounter struct {
Head *Node
Tail *Node
Count int
Init bool
}
func Constructor() RecentCounter {
var rc RecentCounter
rc.Head = new(Node)
rc.Tail = rc.Head
return rc
}
func (this *RecentCounter) Ping(t int) int {
var node = new(Node)
node.Val = t
this.Tail.Next = node
this.Tail = node
this.Count += 1
if !this.Init {
this.Head = this.Tail
this.Init = true
}
for this.Head.Val < t-3000 {
var next = this.Head.Next
this.Head.Next = nil
this.Head = next
this.Count -= 1
}
return this.Count
}
043. 往完全二叉树添加节点
BFS按层遍历
curr 储存当前层节点
next存储下一层节点
type CBTInserter struct {
Root *TreeNode
Curr []*TreeNode
Next []*TreeNode
}
func Constructor(root *TreeNode) CBTInserter {
var cbt CBTInserter
cbt.Root = root
curr := []*TreeNode{root}
for {
next := []*TreeNode{}
var loc = -1
for i, node := range curr {
if node.Left != nil {
next = append(next, node.Left)
} else {
loc = i
break
}
if node.Right != nil {
next = append(next, node.Right)
} else {
loc = i
break
}
}
//当前层满了
if loc == -1 {
curr = next[:]
continue
} else {
cbt.Curr = curr[loc:]
cbt.Next = next[:]
break
}
}
return cbt
}
func (this *CBTInserter) Insert(val int) int {
var node = new(TreeNode)
node.Val = val
tmp := this.Curr[0]
if tmp.Left == nil {
tmp.Left = node
this.Next = append(this.Next, node)
} else if tmp.Right == nil {
tmp.Right = node
this.Next = append(this.Next, node)
if len(this.Curr) == 1 {
this.Curr = this.Next[:]
this.Next = []*TreeNode{}
} else {
this.Curr = this.Curr[1:]
}
}
return tmp.Val
}
func (this *CBTInserter) Get_root() *TreeNode {
return this.Root
}
第 15 天 队列
044. 二叉树每层的最大值
BFS按层遍历
curr 储存当前层节点
next存储下一层节点
func largestValues(root *TreeNode) []int {
if root == nil {
return []int{}
}
var curr = []*TreeNode{root}
var ans []int
for len(curr) > 0 {
var value = curr[0].Val
var next []*TreeNode
for _, node := range curr {
value = max(value, node.Val)
if node.Left != nil {
next = append(next, node.Left)
}
if node.Right != nil {
next = append(next, node.Right)
}
}
ans = append(ans, value)
curr = next[:]
}
return ans
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
045. 二叉树最底层最左边的值
BFS按层遍历
curr存储从左到右当前层节点
next存储下一层节点
如果next为空
那么当前层为最后一层 返回curr中第一个节点值
func findBottomLeftValue(root *TreeNode) int {
var curr = []*TreeNode{root}
for {
var next []*TreeNode
for _, node := range curr {
if node.Left != nil {
next = append(next, node.Left)
}
if node.Right != nil {
next = append(next, node.Right)
}
}
if len(next) == 0 {
return curr[0].Val
}
curr = next[:]
}
}
046. 二叉树的右侧视图
BFS按层遍历
curr存储从左到右当前层节点
next存储下一层节点
每一层保存最后一个节点
func rightSideView(root *TreeNode) []int {
if root == nil {
return []int{}
}
var curr = []*TreeNode{root}
var ans []int
for len(curr) > 0 {
var next []*TreeNode
for _, node := range curr {
if node.Left != nil {
next = append(next, node.Left)
}
if node.Right != nil {
next = append(next, node.Right)
}
}
ans = append(ans, curr[len(curr)-1].Val)
curr = next[:]
}
return ans
}