04. 二维数组中的查找 https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/
https://leetcode.cn/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/
 
思路:可以每层用以恶搞二分查找,优化思路:从左下角出发直接用二分。
07. 重建二叉树 https://leetcode.cn/problems/zhong-jian-er-cha-shu-lcof/
https://leetcode.cn/problems/zhong-jian-er-cha-shu-lcof/
思路:根据前序遍历和中序遍历来确定最终的树。
19. 正则表达式匹配 https://leetcode.cn/problems/zheng-ze-biao-da-shi-pi-pei-lcof/
https://leetcode.cn/problems/zheng-ze-biao-da-shi-pi-pei-lcof/
递归或者是动态规划
func isMatch(s string, p string) bool {
    dp := make([][]bool , len(s) + 1)
    for i := 0 ; i <= len(s); i++{
        dp[i] = make([]bool , len(p) + 1)
    }
    dp[0][0] = true
    for i := 1 ; i <= len(p); i++{ // s的长度为0的时候初始化
        if (i % 2) == 0 && p[i-1] == '*'{
            dp[0][i] = dp[0][i-2] 
        }
    }
    for i := 1; i <= len(s); i++{
        for j := 1 ; j <= len(p); j++{
            // 当前值相等的时候
            if p[j - 1] == '.' || p[j-1] == s[i - 1]{
                dp[i][j] = dp[i-1][j-1]
            }
            // 若果为*的时候考虑
            if p[j-1] == '*'{
                dp[i][j] = dp[i][j-2] // 表示当前x*为空
                if p[j-2] == '.' || p[j-2] == s[i-1]{ // 如果x等于当前值的话可以取一个x*,这里表示s[i-1]已经被解决了
                    dp[i][j] = dp[i][j] || dp[i-1][j]
                }
            }
        } 
    }
    return dp[len(s)][len(p)]
}递归的写法
func isMatch(s string, p string) bool {
    if len(p) == 0 && len(s) == 0{
        return true
    }
    if len(p) == 0{
        return false
    }
    if len(s) == 0{
        if len(p) >= 2 && p[1] == '*'{
            return isMatch(s , p[2:])
        }
        return false
    }
    if len(p) >= 2 && p[1] == '*'{
            if p[0] == '.' || s[0] == p[0]{
                return isMatch(s,p[2:]) || isMatch(s[1:] , p)
            }else{
                return isMatch(s , p[2:])
            }
        
    }else {
        if p[0] == '.' || s[0] == p[0]{
                return isMatch(s[1:] , p[1:])
        }
    }
    return false
}30. 包含min函数的栈 https://leetcode.cn/problems/bao-han-minhan-shu-de-zhan-lcof/
https://leetcode.cn/problems/bao-han-minhan-shu-de-zhan-lcof/
如何实现一个包含最小值的栈,要能O(1)的时间获取最小值,有两种思路,第一种可以考虑用一个链表去模拟栈,维护一个最小值的变量,第二种方案可以考虑用一个辅助栈去存储最小的值。
type MinStack struct {
    a []int
    b []int
}
/** initialize your data structure here. */
func Constructor() MinStack {
    return MinStack{
        []int{}, []int{math.MaxInt32},
    }
}
func min(i, j int) int {
    if i < j {
        return i
    }
    return j
}
func (this *MinStack) Push(x int) {
    this.a = append(this.a, x)
    this.b = append(this.b, min(x, this.b[len(this.b)-1]))
}
func (this *MinStack) Pop() {
    this.a = this.a[:len(this.a)-1]
    this.b = this.b[:len(this.b)-1]
}
func (this *MinStack) Top() int {
    return this.a[len(this.a)-1]
}
func (this *MinStack) Min() int {
    return this.b[len(this.b)-1]
}33.二叉搜索树的后序遍历序列 https://leetcode.cn/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/
https://leetcode.cn/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/
根据后续遍历:左右根,根的左右小于,根的右边大于
func verifyPostorder(postorder []int) bool {
    // 思路 找到右节点
    // 右节点的右边大于右节点的左边
    var recursion func(left , right int)bool
    recursion = func(left , right int)bool{
        if left >= right {
            return true
        }
        index := left 
        for index <= right && postorder[index] < postorder[right]{
            index++
        }
        index --
        for i := index + 1 ; i < right ; i++{
            if postorder[i] < postorder[right]{
                return false
            }
        }
        return recursion(left , index) && recursion(index + 1 , right - 1)
    }
    return recursion(0 , len(postorder)-1)
}43. 1~n 整数中 1 出现的次数 https://leetcode.cn/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/
https://leetcode.cn/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof/
44. 数字序列中某一位的数字 https://leetcode.cn/problems/shu-zi-xu-lie-zhong-mou-yi-wei-de-shu-zi-lcof/
https://leetcode.cn/problems/shu-zi-xu-lie-zhong-mou-yi-wei-de-shu-zi-lcof/
func findNthDigit(n int) int {
        if n == 0 {
                return 0
        }
        start := 1
        count := 9
        length := 1
        for n > count {
                n -= count
                start *= 10
                length++
                count = 9 * start * length
        }
        index := (n - 1) / length + start
        yu := (n - 1) % length
        return int(strconv.Itoa((index))[yu] - '0')
}
/* 数字范围    数量  位数    占多少位1-9        9      1       910-99      90     2       180100-999    900    3       27001000-9999  9000   4       36000  ...例如 2901 = 9 + 180 + 2700 + 12 即一定是4位数,第12位   n = 12;数据为 = 1000 + (12 - 1)/ 4  = 1000 + 2 = 1002定位1002中的位置 = (n - 1) %  4 = 3    s.charAt(3) = 2;*/49. 丑数 https://leetcode.cn/problems/chou-shu-lcof/
https://leetcode.cn/problems/chou-shu-lcof/
堆的应用
51. 数组中的逆序对 https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/
https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/
归并方法思路
func reversePairs(nums []int) int {
    res := 0
    tep := make([]int, len(nums))
    var mergeSort func(left, right int)
    merge := func(left, mid, right int) {
        i := left
        j := mid + 1
        index := left
        for i <= mid && j <= right {
            if nums[i] > nums[j] {
                tep[index] = nums[j]
                // fmt.Println("1111")
                res = res + (mid - i + 1)
                j++
            } else {
                tep[index] = nums[i]
                i++
            }
            index++
        }
        for i <= mid {
            tep[index] = nums[i]
            i++
            index++
        }
        for j <= right {
            tep[index] = nums[j]
            j++
            index++
        }
        for i := left; i <= right; i++ {
            nums[i] = tep[i]
        }
    }
    mergeSort = func(left, right int) {
        if left >= right {
            return
        }
        mid := left + (right-left)/2
        mergeSort(left, mid)
        mergeSort(mid+1, right)
        merge(left, mid, right)
    }
    mergeSort(0, len(nums)-1)
    return res
}
56 - I. 数组中数字出现的次数 https://leetcode.cn/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/
https://leetcode.cn/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/
数组中所有数字都出现两次,有两个出现一次的数字,找出来,这个就是利用二进制的原理进行分组,先全部异或,取出两数已获结果,在通过(n&-n)取出第一位置不一样的作为分组标志。
60n个骰子的点数 https://leetcode.cn/problems/nge-tou-zi-de-dian-shu-lcof/
https://leetcode.cn/problems/nge-tou-zi-de-dian-shu-lcof/
//浪费空间的写法,但是比较容易理解
func dicesProbability(n int) []float64 {
    dp := make([][]float64, n+1) // dp[i][j] 表示i个骰子,点数和为j的概率
    for i := 1; i <= n; i++ {
        dp[i] = make([]float64, 6*i+1)
    }
    for i := 1; i <= 6; i++ {
        dp[1][i] = float64(1) / 6
    }
    for i := 2; i <= n; i++ {
        for k := i; k <= 6*i; k++ { // 当前的点数
            for t := 1; t <= 6 && k > t; t++ { // 当前出现的点数
                if k-t <= 6*(i-1) { // 上一级合法出现的点数
                    dp[i][k] += dp[i-1][k-t] / 6 // 上一级出现的点数
                }
            }
        }
    }
    return dp[n][n:]
}func dicesProbability(n int) []float64 {
    dp := make([]float64, 6)
    for i := 0; i < 6; i++ {
        dp[i] = float64(1) / 6
    }
    for i := 1; i < n; i++ {
        tep := make([]float64, 6*(i+1)-i)
        for j := 0; j < len(dp); j++ {
            for t := 0; t < 6; t++ {
                tep[j+t] = tep[j+t] + dp[j]/6
            }
        }
        dp = tep
    }
    return dp
}62. 圆圈中最后剩下的数字 https://leetcode.cn/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/
https://leetcode.cn/problems/yuan-quan-zhong-zui-hou-sheng-xia-de-shu-zi-lcof/
思路:有三种解法,第一通过数组,第二通过链表,第三,递归去做,定义一个递归函数,f(n , k , i)表示有n个数,当删除第k个数,i表示正在删除第i次。
func lastRemaining(n int, m int) int {
    var f func(n , m , i int)int
    f = func (n , m , i int)int{
        if i == 1{
            return (n + m - 1) % n
        }
        return (f(n - 1 , m , i - 1) + m ) % n
    }
    return f(n , m , n)
}
64. 求1+2+…+n https://leetcode.cn/problems/qiu-12n-lcof/
https://leetcode.cn/problems/qiu-12n-lcof/
思路:不能使用公式、乘除法,for等,等价for得有递归操作。还可以用快速乘来替代普通的乘法。
65. 不用加减乘除做加法 https://leetcode.cn/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/
https://leetcode.cn/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/
思路:传统思路会直接按位进行计算,优化思路的话,可以考虑用递归的思路,a于b之和可以分为无进位之和和有进位之和,无进位是a^b,有进位的和是(a&b)<<1,对结果进行递归处理,当进位为0的时候,直接返回无进位和就行。
func add(a int, b int) int {
    if b == 0 {
        return a
    }
    return add(a ^ b , (a & b ) << 1)
}


















