functwoSum(nums []int, target int) []int { total := make(map[int]int) for i, v := range nums { if idx, ok := total[target-v]; ok { return []int{idx, i} } total[v] = i } returnnil }
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ funcisPalindrome(head *ListNode)bool { total := make([]*ListNode,0,100) for head != nil { total = append(total,head) head = head.Next } for i:=0;i < len(total) >> 1; i++{ if total[i].Val != total[len(total)-1-i].Val { returnfalse } }
returntrue }
141. 环形链表
知识点:链表,hashmap
首先可以考虑使用hashmap,记录所有已经写入进去的节点。
还有一种更快的方法,快慢指针,慢指针一次性走一步,快指针一次性走两步,如果重合了说明有环。
hashmap 比较容易想出来,这里使用快慢指针;
1 2 3 4 5 6 7 8 9 10 11 12 13
funchasCycle(head *ListNode)bool { // 快慢指针 fast,slow := head,head for fast != nil && fast.Next != nil { fast = fast.Next fast = fast.Next slow = slow.Next if fast == slow { returntrue } } returnfalse }
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcinorderTraversal(root *TreeNode) (res []int) { if root == nil { returnnil }
// 处理左边 res = inorderTraversal(root.Left) // 把自己放进去 res = append(res,root.Val) // 处理右边 res = append(res,inorderTraversal(root.Right)...)
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcinvertTree(root *TreeNode) *TreeNode { if root == nil { returnnil }
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcisSymmetric(root *TreeNode)bool { var dfs func(left,right *TreeNode)bool dfs = func(left,right *TreeNode)bool { if left == nil && right == nil { returntrue } elseif left != nil && right != nil { // fmt.Println(left.Val,right.Val) return left.Val == right.Val && dfs(left.Left,right.Right) && dfs(left.Right,right.Left) }
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcdiameterOfBinaryTree(root *TreeNode) (res int) { var dfs func(node *TreeNode)int dfs = func(node *TreeNode)int { if node == nil { return0 }
l,r := dfs(node.Left),dfs(node.Right) res = max(res,l+r) return max(l,r)+1 } dfs(root)
funclongestConsecutive(nums []int) (res int) { total := make(map[int]struct{},len(nums)) for _,v:= range nums { total[v]= struct{}{} }
for i := range total { if _, ok:= total[i-1];!ok{ // 左边不存在,开始计算 l:=i+1 for { if _,o := total[l];!o{ // 此时 l 不在了,退出循环 break } l++ } res = max(res,l-i) } } return res }
11. 盛最多水的容器
知识点:双指针
左指针在最左边,右指针在最右边,两个指针往中间移动,获取当前容量。左右两个指针较小的值往中间移动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
funcmaxArea(height []int) (res int) { l,r:=0,len(height)-1 for l<r { tmp := (r-l) * min(height[l],height[r]) res = max(res,tmp) if height[l] > height[r] { r-- } else { l++ } }
funclengthOfLongestSubstring(s string) (res int) { // 记录索引+1,避免 0 影响 total := [256]int{} l := 0
for i,v := range s { if total[int(v)] > 0 { // 代表以前出现过 if l < total[int(v)] { // l 只能往右移动 l = total[int(v)] } } // 记录最后出现的位置 total[int(v)] = i+1 // 判断结果 res = max(res,i+1-l) }
return }
438. 找到字符串中所有字母异位词
知识点:双指针。
由于 p 是由小写字母组成,可以使用有限数组记录 p,然后遍历 s 时,遍历对应长度的子串,判断子串是否也可以组成数组。
可以理解为左边指针是遍历字符串,右边指针从左指针开始,移动到长度为 p 的地方
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
funcfindAnagrams(s string, p string) (res []int) { total := [256]int{} for _, v := range p { total[int(v)]++ }
for i := 0; i <= len(s)-len(p); i++ { tmp := [256]int{} for j:=0;j<len(p);j++{ tmp[int(s[i+j])]++ } if tmp == total { res = append(res,i) } } return }
funcsubarraySum(nums []int, k int) (res int) { // 前缀和 total := map[int]int{0:1} var sum int for _,v := range nums { sum += v res += total[sum-k] total[sum] ++ }
funcproductExceptSelf(nums []int) []int { // 记录0的个数和位置 var size,idx int total := 1 for i,v := range nums{ if v == 0 { size++ idx = i } else { total *= v } } res := make([]int,len(nums)) if size == 0 { for i,v := range nums{ res[i] = total / v } } elseif size == 1 { res[idx] = total } return res }
funcsetZeroes(matrix [][]int) { x,y:=make([]int,0),make([]int,0) for i,row := range matrix { for j,v := range row { if v == 0 { x = append(x,i) y = append(y,j) } } }
for _,i := range x { for j := 0;j < len(matrix[0]);j++{ matrix[i][j] = 0 } } for _,i := range y { for j := 0;j < len(matrix);j++{ matrix[j][i] = 0 } } }
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ funcdetectCycle(head *ListNode) *ListNode { fast,slow := head,head // 第一次相遇 for fast!=nil&& fast.Next != nil { fast = fast.Next.Next slow = slow.Next if fast == slow { break } } // 没有环 if fast == nil || fast.Next == nil { returnnil } // 寻找第二次相遇 fast = head for fast != slow { fast = fast.Next slow = slow.Next }
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ funcaddTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { pre := &ListNode{} node := pre
// 满 10 之后要进一位 var gate int for l1 != nil && l2 != nil { val := l1.Val + l2.Val + gate gate = val / 10 val = val % 10 node.Next = &ListNode{Val:val} node = node.Next l1 = l1.Next l2 = l2.Next } // 再处理剩下的 for l1 != nil { val := l1.Val + gate gate = val / 10 val = val % 10 node.Next = &ListNode{Val:val} node = node.Next l1 = l1.Next } for l2 != nil { val := l2.Val + gate gate = val / 10 val = val % 10 node.Next = &ListNode{Val:val} node = node.Next l2 = l2.Next } // 最后处理多进的一位 if gate > 0 { node.Next = &ListNode{Val:gate} }
return pre.Next }
19. 删除链表的倒数第 N 个结点
知识点:链表
核心点是找到倒数第 n 个节点是哪个,因此,可以尝试做补全,假设有一个节点在前n 个的地方,逐步移动这两个节点,当节点移动为空,前面的节点就是倒数第 n 个节点。
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ funcremoveNthFromEnd(head *ListNode, n int) *ListNode { pre := &ListNode{Next:head} node,target := head,pre
for node != nil { node = node.Next if n > 0 { n -- } else { target = target.Next } }
// 此时 pre 的下一个节点就是需要删除的节点 target.Next = target.Next.Next
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ funcswapPairs(head *ListNode) *ListNode { if head == nil || head.Next == nil { return head }
pre := &ListNode{Next:head} node,next := head,head.Next // 交换 pre.Next = next // 处理后面的 node.Next = swapPairs(next.Next) next.Next = node
return pre.Next }
138. 随机链表的复制
知识点:链表
先将链表按照 next 拷贝出来,核心在于找到 random,既可以使用 hashmap ,值是老的链表,value 是新的链表,也可以使用两个链表一起遍历,前者快一些,后者慢一些,毕竟便利的时候需要从头开始。
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ funcsortList(head *ListNode) *ListNode { if head == nil { return head }
// 都拿出来 total := make([]*ListNode, 0, 100) for head != nil { total = append(total, head) head = head.Next } // 排序 sort.Slice(total, func(i, j int)bool { return total[i].Val < total[j].Val })
// 组合 for i := 0; i < len(total)-1; i++ { total[i].Next = total[i+1] } total[len(total)-1].Next = nil
func(this *LRUCache) Get(key int) int { n, ok := this.all[key] if !ok { // 没有找到 return-1 } // 找到了,这里不要直接调用 put 去偷懒,避免逻辑混乱了 // 从原先的位置去掉 pre, next := n.pre, n.next pre.next = next next.pre = pre
func(this *LRUCache) Put(key int, value int) { // put 的时候首先判断这个节点是否存在,如果存在需要从链表中删除 n, ok := this.all[key] if ok { // 找到了,先删除 pre, next := n.pre, n.next pre.next = next next.pre = pre
// 然后更新值,放在最前面 n.val = value // 插入开头 start := this.start.next this.start.next = n n.pre = this.start
n.next = start start.pre = n
return }
// 没有找到 n = &node{key:key,val: value} // 判断是否满了 iflen(this.all) == this.capacity { // 满了需要去掉最后一位 del := this.end.pre delete(this.all,del.key) end := del.pre
end.next = this.end this.end.pre = end }
// 然后放在最前面 start := this.start.next
// 放在最前面 this.start.next = n n.pre = this.start
// 插队 start.pre = n n.next = start
this.all[key] = n }
/** * Your LRUCache object will be instantiated and called as such: * obj := Constructor(capacity); * param_1 := obj.Get(key); * obj.Put(key,value); */
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funclevelOrder(root *TreeNode) (res [][]int) { if root == nil { returnnil } total := []*TreeNode{root} forlen(total) > 0 { tmp := make([]*TreeNode,0,len(total)*2) tmpRes := make([]int,0,len(total)) for _,v := range total { tmpRes = append(tmpRes,v.Val) if v.Left != nil { tmp = append(tmp,v.Left) } if v.Right != nil { tmp = append(tmp,v.Right) } } total = tmp res = append(res,tmpRes) }
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcisValidBST(root *TreeNode)bool { var dfs func(node *TreeNode, ma int, mi int)bool dfs = func(node *TreeNode, ma int, mi int)bool { if node == nil { returntrue } // fmt.Println(node.Val,ma,mi) return node.Val < ma && node.Val > mi && dfs(node.Left, min(ma, node.Val), mi) && dfs(node.Right, ma, max(mi, node.Val)) }
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcrightSideView(root *TreeNode) (res []int) { if root == nil { returnnil }
total := []*TreeNode{root} forlen(total) > 0 { tmpTotal := make([]*TreeNode,0,len(total)*2) res = append(res,total[len(total)-1].Val) for _,v := range total { if v.Left != nil { tmpTotal = append(tmpTotal,v.Left) } if v.Right != nil { tmpTotal = append(tmpTotal,v.Right) } } total = tmpTotal }
return res }
114. 二叉树展开为链表
知识点:链表
按照题目所述是先序遍历,因此按照先序遍历处理即可。这种返回一个节点的要求,一半可以使用 pre 虚拟节点来实现。
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcflatten(root *TreeNode) { pre := &TreeNode{Right: root} tmp := pre
var dfs func(node *TreeNode) dfs = func(node *TreeNode) { if node == nil { return }
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcbuildTree(preorder []int, inorder []int) *TreeNode { iflen(preorder) == 0 { returnnil }
node := &TreeNode{Val: preorder[0]} var idx int for inorder[idx] != node.Val { idx++ } li := inorder[:idx] ri := inorder[idx+1:] lp := preorder[1 : 1+len(li)] rp := preorder[1+len(li):] node.Left = buildTree(lp, li) node.Right = buildTree(rp, ri)
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcpathSum(root *TreeNode, targetSum int) (res int) { var dfs func(node *TreeNode, dis int, total []int) dfs = func(node *TreeNode, dis int, total []int) { if node == nil { return }
// 先计算自己的前缀和 dis += node.Val tmp := dis-targetSum // fmt.Println(node.Val, tmp, total) for _, v := range total { if tmp == v { // fmt.Println(node.Val) res++ } } total = append(total, dis) dfs(node.Left, dis, total) dfs(node.Right, dis, total) } dfs(root, 0, []int{0})
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funclowestCommonAncestor(root, p, q *TreeNode) *TreeNode { if root == nil { returnnil }
if root == p || root == q { return root } l,r := lowestCommonAncestor(root.Left,p,q),lowestCommonAncestor(root.Right,p,q) if l != nil && r != nil { return root } elseif l == nil { return r }
func(n *stack) Pop() interface{} { x := (*n)[len(*n)-1] *n = (*n)[:len(*n)-1] return x }
funcmaxSlidingWindow(nums []int, k int) []int { var s stack for i := 0; i < k; i++ { heap.Push(&s, [2]int{i, nums[i]}) } res := make([]int, 0, len(nums)-k+1) res = append(res, s[0][1]) for i := k; i < len(nums); i++ { // 先入栈 heap.Push(&s, [2]int{i, nums[i]}) // 判断是否在窗口中 for s[0][0] <= i-k { heap.Pop(&s) } res = append(res, s[0][1]) }
return res }
76. 最小覆盖子串
知识点:滑动窗口、双指针
使用双指针记录滑动窗口中的内容,先移动右边,找到包含 t 的所有子串,记录此时的答案;滑动左边,直到不包含子串,然后查询下一个包含 t 的子串。
/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ funcreverseKGroup(head *ListNode, k int) *ListNode { if head == nil { return head }
// 判断是否满足 k 个 tmp := make([]*ListNode, 0, k) for i := 0; i < k && head != nil; i++ { tmp = append(tmp,head) head = head.Next } // 不满 iflen(tmp) != k { return tmp[0] } // fmt.Println(tmp,head)
func(s *stack) Pop() interface{} { x := (*s)[len(*s)-1] (*s) = (*s)[:len(*s)-1] return x }
funcmergeKLists(lists []*ListNode) *ListNode { var s stack // 入栈 for _,v := range lists { if v != nil { heap.Push(&s,v) } } pre := &ListNode{} node := pre
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ funcmaxPathSum(root *TreeNode) (res int) { res = math.MinInt var dfs func(node *TreeNode)int dfs = func(node *TreeNode)int { if node == nil { return0 }
l, r := dfs(node.Left), dfs(node.Right) if l >= 0 && r >= 0 { res = max(res, l+r+node.Val) } elseif l < 0 && r >= 0 { res = max(res, r+node.Val) } elseif l >= 0 && r < 0 { res = max(res, l+node.Val) } else { res = max(res, node.Val) } return max(0, max(l, r)) + node.Val }