TalkGo 算法之美第七期

数学是计算机的重要基础,算法题中常常会用到数学知识,尤其是离散、具体的数学,以数论、排列组合、概率期望、多项式为代表,可以出现在几乎任何类别的题目中,所有题目涉及到的数学知识点都已标出,建议去oi-wiki 学习。

强烈建议小伙伴先尝试用非数学的常规解法思考以下题目(也许会更简单更好理解),再用数学的解法。

第一周

5月3日

5月5日

  • 超级丑数 做这题之前先学习求质数的几种方法 (强烈建议掌握),之后只需要思考如何求出第n个即可.
  • 石子游戏 经典的石子游戏肯定是不能错过的,建议先用动态规划解一遍。

5月7日

第二周

5月10日

5月14日

5月16日

第三周

5月19日

5月21日

第四周

5月26日

2 个赞

关于第一题斐波那契数列,我之前做了一个ppt,大家可以参考下。

我也有一篇矩阵相关的题解 矩阵+快速幂求解递推问题

斐波那契数列

func fib(n int) int {
	if n < 2 {
		return n
	}

	p, q, r := 0, 1, 1
	for i := 2; i <= n; i++ {
		r = (p + q) % (1e9 + 7)
		p = q
		q = r
	}

	return r
}



pub struct Solution;

impl Solution {
    pub fn multiply(a: [[i64; 2]; 2], b: [[i64; 2]; 2]) -> [[i64; 2]; 2] {
        let mut c:[[i64; 2]; 2] = [[0,0],[0,0]];
        for i in 0..2 {
            for j in 0..2 {
                c[i][j] = (a[i][0] * b[0][j] + a[i][1] * b[1][j]) % (1000000007)
            }
        }

        c
    }

    pub fn pow(mut a :[[i64;2];2], n:i32)-> [[i64; 2]; 2] {

        let mut c:[[i64; 2]; 2]= [[1,0],[0,1]];
        let mut n = n;
        while n>0{
            if n&1 ==1{
                c = Self::multiply(c, a);
            }

            a = Self::multiply(a, a);
            // println!("{:?}",a);
            n = n>>1;
        }

        c
    }

    pub fn fib(n: i32) -> i32 {
        if n <2{
            return n;
        }

        let r:[[i64; 2]; 2] = Self::pow([[1,1],[1,0]], n-1);
        return r[0][0] as i32

    }
}

#[cfg(test)]
mod tests {
    use crate::Solution;
    #[test]
    fn it_works() {
        assert_eq!(Solution::fib(5),5);
        assert_eq!(Solution::fib(48),807526948);
        assert_eq!(Solution::fib(6),8);
    }
}

1 个赞

剑指 Offer 10- I. 斐波那契数列

func fib(n int) int {
    if n < 2 { 
        return n 
    }
    prev, curr := 0, 1
    for i := 2; i <= n; i++ {
        sum := prev + curr
        prev = curr
        curr = sum % 1000000007
    }
    return curr 
}

509. 斐波那契数

方法一:递归

func fib(n int) int {
	if n == 0 || n == 1 {
		return n
	}
	return fib(n-1) + fib(n-2)
}

复杂度分析

  • 时间复杂度:O(2^n)。
  • 空间复杂度:O(h)。

方法二:带备忘录递归

闭包写法:

func fib(n int) int {
	memo := make([]int, n+1)//从0开始
	var helper func(int) int

	helper = func(n int) int {
		if n == 0 || n == 1 {
			return n
		}
		if memo[n] != 0 {
			return memo[n]
		}
		memo[n] = helper(n-1) + helper(n-2)
		return memo[n]
	}

	return helper(n)
}
func fib(n int) int {
	memo := make([]int, n+1)
	return helper(memo, n)
}
func helper(memo []int, n int) int {
	if n < 2 {
		return n
	}
	if memo[n] != 0 { //剪枝
		return memo[n]
	}
	memo[n] = helper(memo, n-1) + helper(memo, n-2)
	return memo[n]
}

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(n)。

方法三:动态规划

func fib(n int) int {
	if n == 0 {
		return 0
	}
	dp := make([]int, n+1)
	dp[0], dp[1] = 0, 1       //base case
	for i := 2; i <= n; i++ { //状态转移
		dp[i] = dp[i-1] + dp[i-2]
	}
	return dp[n]
}

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(n)。

方法四:滚动数组

动态规划空间优化:只存储前2项

func fib(n int) int {
	if n == 0 || n == 1 { //base case
		return n
	} //递推关系
	prev, curr := 0, 1
	for i := 2; i <= n; i++ {
		next := prev + curr
		prev = curr
		curr = next
	}
	return curr
}

复杂度分析

  • 时间复杂度:O(n)。
  • 空间复杂度:O(1)。
1 个赞

图用什么画的。画得很棒啊。

谢谢欣赏 :pray: :joy: Keynote 讲稿 (Mac ppt)

很厉害,可能需要一个教程:grin:

参考视频
参考文档

1 个赞