力扣刷题笔记

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 用两个栈实现队列

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 用队列实现栈

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 平衡二叉树

/**
 * 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 对称的二叉树

/**
 * 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 二叉树的镜像

/**
 * 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]

}
posted @ 2021-10-18 19:34  朕蹲厕唱忐忑  阅读(35)  评论(0编辑  收藏  举报