力扣刷题笔记
leetcode 4月刷题笔记
栈
1 20有效的括号
func isValid(s string) bool {
// 左括号直接入栈
// 右括号对应左括号弹出
// 否则报错
validMap:=map[byte]byte{
')':'(',
'}':'{',
']':'[',
}
stack:=make([]byte,0,len(s))
for _,c:=range []byte(s){
switch c{
case '(','[','{':
stack=append(stack,c)
case ')',']','}':
if len(stack)>0{
if validMap[c]== stack[len(stack)-1]{
stack=stack[:len(stack)-1]
continue
}
return false
}
return false
}
}
if len(stack)==0{
return true
}
return false
}
2 155最小栈
type MinStack struct {
// 正常栈
commonStack []int
// 存储迄今为止的最小值栈
minStack []int
}
/** initialize your data structure here. */
func Constructor() MinStack {
return MinStack{
commonStack:make([]int,0),
minStack:make([]int,0),
}
}
func (this *MinStack) Push(val int) {
// 最小值栈需要比较和栈顶的大小
// 小者入栈
this.commonStack=append(this.commonStack,val)
minVal:=val
if len(this.minStack)>0 &&
this.minStack[len(this.minStack)-1]<minVal{
minVal=this.minStack[len(this.minStack)-1]
}
this.minStack=append(this.minStack,minVal)
return
}
func (this *MinStack) Pop() {
// 同时pop
if len(this.commonStack)>0{
this.commonStack=this.commonStack[:len(this.commonStack)-1]
this.minStack=this.minStack[:len(this.minStack)-1]
}
return
}
func (this *MinStack) Top() int {
if len(this.commonStack) <1 {
return -1
}
return this.commonStack[len(this.commonStack)-1]
}
func (this *MinStack) GetMin() int {
if len(this.minStack) <1 {
return -1
}
return this.minStack[len(this.minStack)-1]
}
/**
* Your MinStack object will be instantiated and called as such:
* obj := Constructor();
* obj.Push(val);
* obj.Pop();
* param_3 := obj.Top();
* param_4 := obj.GetMin();
*/
3 [重要]496 下一个更大元素1
func nextGreaterElement(nums1 []int, nums2 []int) []int {
// 单调栈
// 存储下一个最大值
res:=make([]int,len(nums1))
greaterMap:=make(map[int]int)
nextGreaterStack:=make([]int,0)
for _,i:=range nums2{
for len(nextGreaterStack)>0 &&
i > nextGreaterStack[len(nextGreaterStack)-1]{
// 当前值大 栈顶小值出栈
// 并设置小值下一个最大值
small := nextGreaterStack[len(nextGreaterStack)-1]
greaterMap[small] = i
nextGreaterStack = nextGreaterStack[:len(nextGreaterStack)-1]
}
nextGreaterStack = append(nextGreaterStack,i)
}
// 栈内剩余是没有下一个最大值的 即-1
for _,i:=range nextGreaterStack{
greaterMap[i]=-1
}
// 找到nums1对应的greater number
for idx,i:=range nums1{
res[idx]=greaterMap[i]
}
return res
}
4 剑指Offer 用两个栈实现队列
- 题目:https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof/
- 解法:go原生的slice就可以简单做到,如果非要用栈来实现队列,可以先用slice封装一层stack,再封装一层queue
type CQueue struct {
commonStack *Stack
otherStack *Stack
}
func Constructor() CQueue {
return CQueue{
commonStack:NewStack(),
otherStack:NewStack(),
}
}
func (this *CQueue) AppendTail(value int) {
// 直接common push就可以
this.commonStack.Push(value)
return
}
func (this *CQueue) DeleteHead() int {
// stack 从common转移到other
// 实现逆序 然后删除栈顶 即Head
if !this.otherStack.Empty(){
return this.otherStack.Pop()
}
for !this.commonStack.Empty(){
this.otherStack.Push(this.commonStack.Pop())
}
return this.otherStack.Pop()
}
type Stack struct{
stack []int
}
func NewStack() *Stack{
return &Stack{
stack:make([]int,0),
}
}
func (s *Stack) Empty() bool{
return len(s.stack)==0
}
func (s *Stack) Push(value int){
s.stack=append(s.stack,value)
}
func (s *Stack) Pop() int{
if len(s.stack)<1{
return -1
}
tail:=s.stack[len(s.stack)-1]
s.stack=s.stack[:len(s.stack)-1]
return tail
}
func (s *Stack) Top() int{
if len(s.stack)<1{
return -1
}
tail:=s.stack[len(s.stack)-1]
return tail
}
/**
* Your CQueue object will be instantiated and called as such:
* obj := Constructor();
* obj.AppendTail(value);
* param_2 := obj.DeleteHead();
*/
5 剑指 Offer 30. 包含min函数的栈
6 225 用队列实现栈
- 题目:https://leetcode-cn.com/problems/implement-stack-using-queues/
- 解法:go原生slice实现栈很简单,也可以先包一层queue,再包一层stack
7 682 棒球比赛
func calPoints(ops []string) int {
finalScores:=make([]int,0,len(ops))
for _,op:=range ops{
var temp int
switch op{
case "+":
if len(finalScores)>1{
temp=finalScores[len(finalScores)-1]+finalScores[len(finalScores)-2]
finalScores=append(finalScores,temp)
}
case "D":
if len(finalScores)>0{
temp=finalScores[len(finalScores)-1]*2
finalScores=append(finalScores,temp)
}
case "C":
if len(finalScores)>0{
finalScores=finalScores[:len(finalScores)-1]
}
default:
if val,err:=strconv.ParseInt(op,10,64);err==nil{
temp=int(val)
finalScores=append(finalScores,temp)
}
}
}
var finalScore int
for _,val:=range finalScores{
finalScore+=val
}
return finalScore
}
8
树
1 平衡二叉树
- 题目:https://leetcode-cn.com/problems/ping-heng-er-cha-shu-lcof/
- 解法:层序遍历计算高度,递归判断平衡
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func isBalanced(root *TreeNode) bool {
if root==nil{
return true
}
leftDepth:=Depth(root.Left)
rightDepth:=Depth(root.Right)
if leftDepth-rightDepth<(-1) || leftDepth-rightDepth>1{
return false
}
return isBalanced(root.Left)&&isBalanced(root.Right)
}
func Depth(root *TreeNode) int{
if root==nil{
return 0
}
var depth int
// 层序遍历计算深度
nodes:=make([]*TreeNode,0)
nodes=append(nodes,root)
for len(nodes)!=0{
// 当前层节点数量
curLen:=len(nodes)
depth++
for i:=0;i<curLen;i++{
// 取出节点
tmp:=nodes[0]
nodes=nodes[1:]
// 左右子节点入队
if tmp.Left!=nil{
nodes=append(nodes,tmp.Left)
}
if tmp.Right!=nil{
nodes=append(nodes,tmp.Right)
}
}
}
return depth
}
2 对称的二叉树
- 题目:https://leetcode-cn.com/problems/dui-cheng-de-er-cha-shu-lcof/
- 解法:辅助函数判断镜像对称
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func isSymmetric(root *TreeNode) bool {
return helper(root,root)
}
func helper(left, right *TreeNode) bool{
// 均为空
if left==nil&&right==nil{
return true
}
// 一边为空
if left==nil||right==nil{
return false
}
// 下一层已经出现了不相等
if left.Val!=right.Val{
return false
}
// 递归判断
return helper(left.Left,right.Right) &&
helper(left.Right,right.Left)
}
3 层序遍历
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func levelOrder(root *TreeNode) [][]int {
if root==nil{
return [][]int{}
}
res:=make([][]int,0)
nodes:=make([]*TreeNode,0)
nodes=append(nodes,root)
for len(nodes)!=0{
curLen:=len(nodes)
tempNodes:=make([]int,0,curLen)
for i:=0;i<curLen;i++{
temp:=nodes[0]
nodes=nodes[1:]
tempNodes=append(tempNodes,temp.Val)
if temp.Left!=nil{
nodes=append(nodes,temp.Left)
}
if temp.Right!=nil{
nodes=append(nodes,temp.Right)
}
}
res=append(res,tempNodes)
}
return res
}
4 二叉树的镜像
- 题目:https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/
- 解法:递归交换,或者slice广度优先遍历交换
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func mirrorTree(root *TreeNode) *TreeNode {
// 解法1:递归
// // 无左右子树
// if root==nil || (root.Left==nil &&root.Right==nil){
// return root
// }
// // 左右子树都有 交换 递归
// temp:=root.Left
// root.Left=root.Right
// root.Right=temp
// mirrorTree(root.Left)
// mirrorTree(root.Right)
// return root
// 解法2:广度优先使用slice实现
if root==nil || (root.Left==nil &&root.Right==nil){
return root
}
stack:=make([]*TreeNode,0)
stack = append(stack,root)
for(len(stack)>0) {
node:=stack[0]
stack=stack[1:]
// 进入
if node.Left!=nil{
stack = append(stack,node.Left)
}
if node.Right!=nil{
stack = append(stack,node.Right)
}
// 交换
node.Left,node.Right=node.Right,node.Left
}
return root
}
5 二叉树的深度
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func maxDepth(root *TreeNode) int {
// 解法1:递归
// if root==nil{
// return 0
// }
// if root.Left==nil && root.Right==nil{
// return 1
// }
// return int(math.Max(float64(maxDepth(root.Left)),float64(maxDepth(root.Right))))+1
// 解法2:BFS 使用slice
if root==nil{
return 0
}
depth:=0
queue:=make([]*TreeNode,0)
queue=append(queue,root)
for len(queue)>0{
curLen:=len(queue)
depth++
for i:=0;i<curLen;i++{
// 先进先出 下一层入队
node:=queue[0]
queue=queue[1:]
if node.Left!=nil{
queue=append(queue,node.Left)
}
if node.Right!=nil{
queue=append(queue,node.Right)
}
}
}
return depth
}
6 [重要]二叉树的最近公共祖先
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if root==nil||root.Val==p.Val||root.Val==q.Val{
return root
}
left:=lowestCommonAncestor(root.Left,p,q)
right:=lowestCommonAncestor(root.Right,p,q)
if left != nil && right != nil {
return root
}
if left == nil {
return right
}
return left
}
7.144. 二叉树的前序遍历
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
// var res []int
// func preorderTraversal(root *TreeNode) []int {
// res=make([]int,0)
// helper(root)
// return res
// }
// func helper(root *TreeNode){
// if root==nil{
// return
// }
// res=append(res,root.Val)
// helper(root.Left)
// helper(root.Right)
// return
// }
func preorderTraversal(root *TreeNode) []int {
if root==nil{
return []int{}
}
// 迭代方法 使用栈
// 右左顺序入栈 左右顺序出栈
res:=make([]int,0)
stack:=make([]*TreeNode,0)
stack=append(stack,root)
for ;len(stack)!=0;{
tmp:=stack[len(stack)-1]
res=append(res,tmp.Val)
stack=stack[0:len(stack)-1]
if tmp.Right!=nil{
stack=append(stack,tmp.Right)
}
if tmp.Left!=nil{
stack=append(stack,tmp.Left)
}
}
return res
}
8.145. 二叉树的后序遍历
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func postorderTraversal(root *TreeNode) []int {
if root==nil{
return []int{}
}
stack:=make([]*TreeNode,0)
res:=make([]int,0)
stack=append(stack,root)
for ;len(stack)!=0;{
tmp:=stack[len(stack)-1]
stack=stack[0:len(stack)-1]
res=append(res,tmp.Val)
// 先左后右入栈 先右后左出栈
if tmp.Left!=nil{
stack=append(stack,tmp.Left)
}
if tmp.Right!=nil{
stack=append(stack,tmp.Right)
}
}
// 整体reverse
for i:=0;i<=(len(res)-1)/2;i++{
ano:=len(res)-1-i
res[i],res[ano]=res[ano],res[i]
}
return res
}
9.94. 二叉树的中序遍历
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/
func inorderTraversal(root *TreeNode) []int {
if root==nil{
return []int{}
}
stack:=make([]*TreeNode,0)
res:=make([]int,0)
cur:=root
for ;len(stack)!=0 || cur!=nil;{
// 找到最左节点
for ;cur!=nil;{
stack=append(stack,cur)
cur=cur.Left
}
cur=stack[len(stack)-1]
stack=stack[0:len(stack)-1]
res=append(res,cur.Val)
cur=cur.Right
}
return res
}
链表
1.剑指 Offer 25. 合并两个排序的链表
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func mergeTwoLists(l1 *ListNode, l2 *ListNode) *ListNode {
if l1==nil{
return l2
}
if l2==nil{
return l1
}
// 循环合并
head:=&ListNode{-1,nil}
resHead:=head
for ;l1!=nil && l2!=nil;{
if l1.Val<l2.Val{
head.Next=l1
l1=l1.Next
}else{
head.Next=l2
l2=l2.Next
}
head=head.Next
}
if l1!=nil{
head.Next=l1
}
if l2!=nil{
head.Next=l2
}
return resHead.Next
}
2. 剑指 Offer 06. 从尾到头打印链表
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reversePrint(head *ListNode) []int {
if head==nil{
return []int{}
}
// 用先进后出的栈解决
res:=make([]int,0)
for ;head!=nil;head=head.Next{
res=append(res,head.Val)
}
// 倒置交换
for i:=0;i<len(res)/2;i++{
another:=len(res)-1-i
res[i],res[another]=res[another],res[i]
}
return res
}
3.链表中倒数第k个节点
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getKthFromEnd(head *ListNode, k int) *ListNode {
// 双指针 快指针先走k-1步 慢指针放在head
pSlow,pFast:=head,head
for ;k>0;k--{
pFast=pFast.Next
}
for ;pFast!=nil;pFast,pSlow=pFast.Next,pSlow.Next{
}
return pSlow
}
4. 剑指 Offer 24. 反转链表
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reverseList(head *ListNode) *ListNode {
if head==nil||head.Next==nil{
return head
}
var resHead,pre *ListNode
cur:=head
for ;cur!=nil;{
resHead=cur
cur=cur.Next
// 断开 指向前边
resHead.Next=pre
pre=resHead
}
return resHead
}
5. 剑指 Offer 18. 删除链表的节点
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func deleteNode(head *ListNode, val int) *ListNode {
// 特殊处理删除头结点的情况
if head.Val==val{
return head.Next
}
// 原题是指针 可以直接删除非尾节点 现在是int 只能遍历了
var pre,reallHead *ListNode
reallHead=head
for ;head!=nil;head=head.Next{
if head.Val==val{
pre.Next=head.Next
return reallHead
}
pre=head
}
return nil
}
6.剑指 Offer 52. 两个链表的第一个公共节点
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getIntersectionNode(headA, headB *ListNode) *ListNode {
if headA==nil||headB==nil{
return nil
}
// 将两个链表的公共节点都走上两遍
pA,pB:=headA,headB
for ;;{
// 到了公共节点
if pA!=nil && pB!=nil && pA==pB && pA.Val==pB.Val{
return pA
}
// 不相交 都走到了最后一个节点
if pA.Next==nil && pB.Next==nil{
return nil
}
if pA.Next==nil{
pA=headB
}else{
pA=pA.Next
}
if pB.Next==nil{
pB=headA
}else{
pB=pB.Next
}
}
return nil
}
7.删除排序链表中的重复元素
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func deleteDuplicates(head *ListNode) *ListNode {
if head==nil || head.Next==nil{
return head
}
cur:=head
for ;cur.Next!=nil;{
if cur.Val==cur.Next.Val{
cur.Next=cur.Next.Next
}else{
cur=cur.Next
}
}
return head
}
8. 环形链表
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func hasCycle(head *ListNode) bool {
// 快满指针 最终会相遇
if head==nil || head.Next==nil{
return false
}
pSlow,pFast:=head,head.Next
for ;pSlow!=pFast;{
// pFast 判断过不再需要pSlow判断
if pFast==nil || pFast.Next==nil{
return false
}
pSlow=pSlow.Next
pFast=pFast.Next.Next
}
return true
}
9. 移除链表元素
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeElements(head *ListNode, val int) *ListNode {
mockHead:=&ListNode{-1,head}
resHead:=mockHead
for mockHead.Next!=nil{
// 从head开始比较值
if mockHead.Next.Val==val{
mockHead.Next=mockHead.Next.Next
}else{
mockHead=mockHead.Next
}
}
return resHead.Next
}
10. 回文链表
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func isPalindrome(head *ListNode) bool {
if head==nil || head.Next==nil{
return true
}
// 找到中点 翻转后半部分链表
pSlow,pFast:=head,head
var pre *ListNode
for pFast!=nil && pFast.Next!=nil{
pre=pSlow
pSlow=pSlow.Next
pFast=pFast.Next.Next
}
// 断开
pre.Next=nil
// 如果总数为奇数 后半部分会多一个元素
// 不过没关系 后边比较的时候同时限定了两边都不为nil 这个元素会被忽略
// 翻转后半部分
var head2 *ListNode
for pSlow!=nil{
tmp:=pSlow.Next
pSlow.Next=head2
head2=pSlow
pSlow=tmp
}
for head!=nil && head2!=nil{
if head.Val!=head2.Val{
return false
}
head=head.Next
head2=head2.Next
}
return true
}
11.设计哈希集合
type ListNode struct {
Val int
Pre,Next *ListNode
}
type MyHashSet struct {
hashMap map[int]*ListNode
head,tail *ListNode
}
/** Initialize your data structure here. */
func Constructor() MyHashSet {
set:= MyHashSet{
hashMap:make(map[int]*ListNode),
head:&ListNode{-1,nil,nil},
tail:&ListNode{-1,nil,nil},
}
set.head.Next=set.tail
set.tail.Pre=set.head
return set
}
func (this *MyHashSet) Add(key int) {
node:=&ListNode{key,nil,nil}
this.hashMap[key]=node
nodePre:=this.tail.Pre
nodePre.Next=node
node.Pre=nodePre
node.Next=this.tail
this.tail.Pre
return
}
func (this *MyHashSet) Remove(key int) {
node,ok:=this.hashMap[key]
if !ok{
return
}
node.Pre.Next=node.Next
node.Next.Pre=node.Pre
delete(this.hashMap,key)
return
}
/** Returns true if this set contains the specified element */
func (this *MyHashSet) Contains(key int) bool {
return this.hashMap[key]!=nil
}
/**
* Your MyHashSet object will be instantiated and called as such:
* obj := Constructor();
* obj.Add(key);
* obj.Remove(key);
* param_3 := obj.Contains(key);
*/
12. 链表的中间结点
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func middleNode(head *ListNode) *ListNode {
if head==nil || head.Next==nil{
return head
}
// 快慢指针
pSlow,pFast:=head,head
for pFast.Next!=nil && pFast.Next.Next!=nil{
pSlow=pSlow.Next
pFast=pFast.Next.Next
}
if pFast.Next==nil{
return pSlow
}
return pSlow.Next
}
13.二进制链表转整数
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func getDecimalValue(head *ListNode) int {
// 使用栈 从低到高依次计算
nodes:=make([]*ListNode,0)
for head!=nil{
nodes=append(nodes,head)
head=head.Next
}
temp:=1
var sum int
for i:=len(nodes)-1;i>=0;i--{
sum+=nodes[i].Val*temp
temp*=2
}
return sum
}
14.143. 重排链表
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func reorderList(head *ListNode) {
if head==nil || head.Next==nil{
return
}
// 快慢指针找到中点
pSlow,pFast:=head,head
for pFast.Next!=nil && pFast.Next.Next!=nil{
pFast=pFast.Next.Next
pSlow=pSlow.Next
}
secondHead:=pSlow.Next
pSlow.Next=nil
// 后半部分翻转
var resHead,pre *ListNode
cur:=secondHead
for cur!=nil{
resHead=cur
cur=cur.Next
resHead.Next=pre
pre=resHead
}
// 合并两个链表
secondHead=resHead
for head!=nil && secondHead!=nil{
h:=head.Next
s:=secondHead.Next
head.Next=secondHead
head=h
secondHead.Next=head
secondHead=s
}
return
}
动态规划
1. 区域和检索 - 数组不可变
题解:
type NumArray struct {
nums []int
numSum []int
}
func Constructor(nums []int) NumArray {
arr:= NumArray{
nums:nums,
numSum:make([]int,len(nums)),
}
for i,v:=range nums{
if i==0{
arr.numSum[i]=v
continue
}
arr.numSum[i]=arr.numSum[i-1]+v
}
return arr
}
func (this *NumArray) SumRange(left int, right int) int {
return this.numSum[right]-this.numSum[left]+this.nums[left]
}
/**
* Your NumArray object will be instantiated and called as such:
* obj := Constructor(nums);
* param_1 := obj.SumRange(left,right);
*/
2.使用最小花费爬楼梯
题解:
func minCostClimbingStairs(cost []int) int {
// dp[i]只是说明走到了第i级 但是第i级还没有花费体力
dp:=make([]int,len(cost)+1)
for i:=2;i<=len(cost);i++{
dp[i]=min(dp[i-2]+cost[i-2],dp[i-1]+cost[i-1])
}
return dp[len(cost)]
}
func min(a,b int)int{
if a<b{
return a
}
return b
}
3.最大子序和
题解:
func maxSubArray(nums []int) int {
pre,maxAns:=0,nums[0]
for i:=0;i<len(nums);i++{
// 连续最大的
if pre+nums[i]>nums[i]{
pre+=nums[i]
}else{
pre=nums[i]
}
// 累积连续最大的
if pre>maxAns{
maxAns=pre
}
}
return maxAns
}
4.判断子序列
func isSubsequence(s string, t string) bool {
if s==""{
return true
}
// 双指针遍历一次
sb,tb:=[]byte(s),[]byte(t)
pA,pB:=0,0
for ;;{
if pA>=len(sb) || pB>=len(tb){
return false
}
if sb[pA]==tb[pB]{
pA++
pB++
}else{
pB++
}
if pA==len(sb){
return true
}
}
return false
}
5.除数博弈
func divisorGame(n int) bool {
// n变成1就可以停止操作了
if n==1{
return false
}
// 从1-n/2找到一个比0大的约数
// 最佳状态是指找到的数字尽量小?我尼玛。不应该尽量大吗?
begin:=0
for begin=1;begin<=n/2;begin++{
if n%begin==0{
break
}
}
return !divisorGame(n-begin)
}
6.比特位计数
func countBits(n int) []int {
if n==0{
return []int{0}
}
dp:=make([]int,n+1)
dp[1]=1
if n>=2{
dp[2]=1
}
for i:=3;i<n+1;i++{
if i&1==1{
dp[i]=dp[i-1]+1
}else{
dp[i]=dp[i/2]
}
}
return dp
}
7. 爬楼梯
func climbStairs(n int) int {
if n==0||n==1{
return 1
}
dp:=make([]int,n+1)
dp[0],dp[1]=1,1
for i:=2;i<=n;i++{
dp[i]=dp[i-1]+dp[i-2]
}
return dp[n]
}
8.买卖股票的最佳时机
func maxProfit(prices []int) int {
min:=-1
curMax:=math.MinInt64
totalMax:=0
for _,price:=range prices{
if price<min{
min=price
}
// 当前最大
curMax=price-min
// 累积最大
if curMax>totalMax{
totalMax=curMax
}
}
return totalMax
}
贪心算法
1.换酒问题
func numWaterBottles(numBottles int, numExchange int) int {
var res = numBottles
if numBottles<numExchange{
return res
}
// 循环换酒
// 还剩下多少可以喝的
left:=numBottles
// 换完之后还多余的
for ;;{
if left<numExchange{
// res+=left%numExchange
break
}
res+=left/numExchange
left=left/numExchange+left%numExchange
}
return res
}
2.模拟行走机器人
func robotSim(commands []int, obstacles [][]int) int {
// 这题感觉跟贪心算法没有半毛钱关系
// 北东南西分别定义为0123
// 记录对应方向应该如何移动
distance:=0
direct:=0
directX:=[]int{0,1,0,-1}
directY:=[]int{1,0,-1,0}
posX,posY:=0,0
// map记录坐标点是否有障碍物
obstacleMap:=make(map[[2]int]bool)
for _,o:=range obstacles{
if len(o)==2{
obstacleMap[[2]int{o[0],o[1]}]=true
}
}
for len(commands)>0{
c:=commands[0]
commands=commands[1:]
if c==-2{
direct=(direct+3)%4
}else if c==-1{
direct=(direct+1)%4
}else{
// 走c步
for i:=0;i<c;i++{
newX:=posX+directX[direct]
newY:=posY+directY[direct]
if obstacleMap[[2]int{newX,newY}]{
break
}
posX,posY=newX,newY
distance=max(distance,posX*posX+posY*posY)
}
}
}
return max(distance,posX*posX+posY*posY)
}
func max(a,b int)int{
if a>b{
return a
}
return b
}
3.分割平衡字符串
func balancedStringSplit(s string) int {
var res, num int
for _,b:=range []byte(s){
if b=='L'{
res++
}else if b=='R'{
res--
}
if res==0{
num++
}
}
return num
}
4.可以形成最大正方形的矩形数目
func countGoodRectangles(rectangles [][]int) int {
// key为边长 value为出现次数
goodCount:=make(map[int]int)
maxGood:=0
for _,r:=range rectangles{
if len(r)==2{
good:=min(r[0],r[1])
goodCount[good]=goodCount[good]+1
if good>maxGood{
maxGood=good
}
}
}
return goodCount[maxGood]
}
func min(a,b int) int{
if a>b{
return b
}
return a
}
5. 非递增顺序的最小子序列
func minSubsequence(nums []int) []int {
// 直接降序排序
// 然后依次选择
sort.Ints(nums)
var sum int
for _,n:=range nums{
sum+=n
}
res:=make([]int,0)
count,half,i:=0,sum/2,len(nums)
for count<=half{
i--
count+=nums[i]
res=append(res,nums[i])
}
return res
}
6. 重新分配字符使所有字符串都相等
func makeEqual(words []string) bool {
// 遍历确认可以均分到每个元素
lenW:=len(words)
alphaNum:=make(map[byte]int)
for _,w:=range words{
for _,b:=range []byte(w){
alphaNum[b]=alphaNum[b]+1
}
}
for _,num:=range alphaNum{
if num%lenW!=0{
return false
}
}
return true
}
7.最少操作使数组递增
func minOperations(nums []int) int {
if len(nums)<2{
return 0
}
// 找到递减的下一个元素
// 增加
var res int
for i:=range nums{
if i==0{
continue
}
if nums[i]<=nums[i-1]{
delta:=nums[i-1]+1-nums[i]
nums[i]+=delta
res+=delta
}
}
return res
}
8. 玩筹码
func minCostToMoveChips(position []int) int {
// 奇数全移到一起 偶数全移到一起 这一步代价为0
// 再看哪个数字小 移动到另一个
// 其实就是奇数偶数那个少就返回那个
var cnt1,cnt2 int
for _,p:=range position{
if p&1==1{
cnt1++
}else{
cnt2++
}
}
if cnt1<cnt2{
return cnt1
}
return cnt2
}
9. 生成交替二进制字符串的最少操作数
func minOperations(s string) int {
// 先构造两个交替的字符串
// 然后双指针比较那个移动的次数少
alter1:=make([]byte,0)
alter2:=make([]byte,0)
for i:=0;i<len(s);i++{
if i&1==1{
alter1=append(alter1,'0')
alter2=append(alter2,'1')
}else {
alter1=append(alter1,'1')
alter2=append(alter2,'0')
}
}
var cnt1,cnt2 int
for i,b:=range []byte(s){
if alter1[i]!=b{
cnt1++
}
if alter2[i]!=b{
cnt2++
}
}
if cnt1<cnt2{
return cnt1
}
return cnt2
}
10.
回溯算法
1.46. 全排列
- 思路:每次新一轮都从0开始,使用used状态数组,防止重复出现,比如[1,1,1]这种,长度够了即可停止递归,回退
var finalRes [][]int
func permute(nums []int) [][]int {
finalRes=make([][]int,0)
helper(nums,[]int{},make([]int,len(nums)),0)
return finalRes
}
func helper(nums, path, used []int,idx int){
if len(path)==len(nums){
finalRes=append(finalRes,deep(path))
return
}
for i:=0;i<len(nums);i++{
if used[i]==1{
continue
}
used[i]=1
path=append(path,nums[i])
helper(nums,path,used,i+1)
used[i]=0
path=path[0:len(path)-1]
}
}
func deep(path []int) []int{
r:=make([]int,0)
for _,p:=range path{
r=append(r,p)
}
return r
}
2.47. 全排列 II
var finalRes [][]int
func permuteUnique(nums []int) [][]int {
finalRes=make([][]int,0)
// 一定要排序
sort.Ints(nums)
helper(nums,[]int{},make([]int,len(nums)),0)
return finalRes
}
func helper(nums, path, used []int,idx int){
if len(path)==len(nums){
finalRes=append(finalRes,deep(path))
return
}
for i:=0;i<len(nums);i++{
// 连续相等只回溯一次 used[i-1]==0说明之前已经用过了,现在不需要再用
if used[i]==1 || (i>0 && nums[i]==nums[i-1] && used[i-1]==0){
continue
}
used[i]=1
path=append(path,nums[i])
helper(nums,path,used,i+1)
used[i]=0
path=path[0:len(path)-1]
}
}
func deep(path []int) []int{
r:=make([]int,0)
for _,p:=range path{
r=append(r,p)
}
return r
}
3.39. 组合总和
- 思路:总和大于target时,进行剪枝,因为可以重复用,每次从0开始即可;
helper(nums,path,target,sum,i)
这一行可以确保不会出现[2,2,3] [2,3,2]这样的组合。
var finalRes [][]int
func combinationSum(candidates []int, target int) [][]int {
finalRes=make([][]int,0)
helper(candidates,[]int{},target,0,0)
return finalRes
}
func helper(nums,path []int,target,sum,idx int){
if target==sum{
finalRes=append(finalRes,deep(path))
return
}
for i:=idx;i<len(nums);i++{
if sum<target{
sum+=nums[i]
path=append(path,nums[i])
helper(nums,path,target,sum,i)
sum-=nums[i]
path=path[0:len(path)-1]
}else{
break
}
}
}
func deep(path []int) []int{
r:=make([]int,0)
for _,p:=range path{
r=append(r,p)
}
return r
}
4. 39. 组合总和
- 思路:nums中出现了重复数字,这种情况需要使用used状态变量used记录,防止回溯到重复数字,used出现必须进行排序。因为每个数字只允许取一次,所以
helper(nums,path,used,target,sum,i+1)
var finalRes [][]int
func combinationSum2(candidates []int, target int) [][]int {
finalRes=make([][]int,0)
sort.Ints(candidates)
helper(candidates,[]int{},make([]int,len(candidates)),target,0,0)
return finalRes
}
func helper(nums,path,used []int,target,sum,idx int){
if target==sum{
finalRes=append(finalRes,deep(path))
return
}
for i:=idx;i<len(nums);i++{
if used[i]==1 || (i>0 && nums[i]==nums[i-1] && used[i-1]==0){
continue
}
if sum<target{
sum+=nums[i]
used[i]=1
path=append(path,nums[i])
helper(nums,path,used,target,sum,i+1)
sum-=nums[i]
used[i]=0
path=path[0:len(path)-1]
}else{
break
}
}
}
func deep(path []int) []int{
r:=make([]int,0)
for _,p:=range path{
r=append(r,p)
}
return r
}
5.77. 组合
- 思路:只允许用一次,used状态变量没跑了。
var finalRes [][]int
func combine(n int, k int) [][]int {
finalRes=make([][]int,0)
helper(n,k,[]int{},make([]int,n+1),1)
return finalRes
}
func helper(n,k int,path, used []int,idx int){
if len(path)==k{
finalRes=append(finalRes,deep(path))
return
}
for i:=idx;i<=n;i++{
if used[i]==1{
continue
}
used[i]=1
path=append(path,i)
helper(n,k,path,used,i+1)
used[i]=0
path=path[0:len(path)-1]
}
}
func deep(path []int) []int{
r:=make([]int,0)
for _,p:=range path{
r=append(r,p)
}
return r
}
6.78. 子集
var finalRes [][]int
func subsets(nums []int) [][]int {
finalRes=make([][]int,0)
helper(nums,[]int{},0)
return finalRes
}
func helper(nums,path []int,idx int){
finalRes=append(finalRes,deep(path))
for i:=idx;i<len(nums);i++{
path=append(path,nums[i])
helper(nums,path,i+1)
path=path[0:len(path)-1]
}
}
func deep(path []int) []int{
r:=make([]int,0)
for _,p:=range path{
r=append(r,p)
}
return r
}
7.90. 子集 II
- 思路:出现了重复数字,不用想,used状态变量+sort排序,稳稳的
var finalRes [][]int
func subsetsWithDup(nums []int) [][]int {
finalRes=make([][]int,0)
sort.Ints(nums)
helper(nums,[]int{},make([]int,len(nums)),0)
return finalRes
}
func helper(nums,path,used []int,idx int){
finalRes=append(finalRes,deep(path))
for i:=idx;i<len(nums);i++{
if used[i]==1 || (i>0 && nums[i]==nums[i-1] && used[i-1]==0){
continue
}
used[i]=1
path=append(path,nums[i])
helper(nums,path,used,i+1)
used[i]=0
path=path[0:len(path)-1]
}
}
func deep(path []int) []int{
r:=make([]int,0)
for _,p:=range path{
r=append(r,p)
}
return r
}
剑指offer
1.用两个栈实现队列
见栈相关题目
2.斐波那契数列
见动态规划相关题目
3.数组中重复的数字
func findRepeatNumber(nums []int) int {
// 原地交换 使nums[i]=i
for i:=0;i<len(nums);i++{
// 循环找到当前数字应该在的位置
// 直到当前位置也是合适的数字
// 如果找不到说明重复了
for ;;{
if i==nums[i]{
break
}
if nums[nums[i]]==nums[i]{
return nums[i]
}else{
temp:=nums[i]
nums[i]=nums[temp]
nums[temp]=temp
}
}
}
return -1
}
4.青蛙跳台阶问题
func numWays(n int) int {
if n<2{
return 1
}
dp:=make([]int,n+1)
dp[0],dp[1]=1,1
for i:=2;i<=n;i++{
// 相比于斐波那契 多了一个取余操作
dp[i]=(dp[i-1]+dp[i-2])%(1e9+7)
}
return dp[n]
}
5.旋转数组的最小数字
func minArray(numbers []int) int {
// 二分确认旋转点
left,right:=0,len(numbers)-1
for ;left<right;{
mid:=(left+right)/2
if numbers[mid]>numbers[right]{
// 在右半边
left=mid+1
}else if numbers[mid]<numbers[right]{
//
right=mid
}else{
right-=1
}
}
return numbers[left]
}