杨辉三角形

272 阅读3分钟

杨辉三角

思路 一:

找到规则,下一行由上一行的结果决定

输入为 n,则生成 n 行

func generate(numRows int) [][]int {
	//创建一个n行的二维数组
	var result [][]int
	for i := 0; i < numRows; i++ {
		var row []int
		if i == 0 {
			row = append(row, 1)
			result = append(result, row)
			continue
		}
		//根据上一行结果生成这一行结果
		lastRow := result[i-1]
		//这里是<=i,不是<=numRows
		//for index := 0; index < numRows; index++ {
		for index := 0; index <= i; index++ {
			val := getVal(index-1, lastRow) + getVal(index, lastRow)
			row = append(row, val)
		}
		//不要忘了加入到二维数组
		result = append(result, row)
	}
	return result
}

//获取指定下标的值,不存在返回0
func getVal(index int, row []int) int {
	if index < 0 || index > len(row)-1 {
		return 0
	}
	return row[index]
}

优化:杨辉三角形每一行是个对称结构,算一半即可

可否直接推出某一行的值

思路二:使用递归迭代,后一行依赖于上一行

思路一:记录所有结果,返回指定行

思路二:只记录上一行的结果,返回指定行

func getRow(rowIndex int) []int {
	//注意,这里给的是索引
	return generate(rowIndex + 1)[rowIndex]
}

func generate(numRows int) [][]int {
	//创建一个n行的二维数组
	var result [][]int
	for i := 0; i < numRows; i++ {
		var row []int
		if i == 0 {
			row = append(row, 1)
			result = append(result, row)
			continue
		}
		//根据上一行结果生成这一行结果
		lastRow := result[i-1]
		//这里是<=i,不是<=numRows
		//for index := 0; index < numRows; index++ {
		for index := 0; index <= i; index++ {
			val := getVal(index-1, lastRow) + getVal(index, lastRow)
			row = append(row, val)
		}
		//不要忘了加入到二维数组
		result = append(result, row)
	}
	return result
}

//获取指定下标的值,不存在返回0
func getVal(index int, row []int) int {
	if index < 0 || index > len(row)-1 {
		return 0
	}
	return row[index]
}

思路三:直接使用计算组合数的公式,利用阶乘

下面的代码会导致整数溢出,

// calculateFactorial 计算阶乘
func calculateFactorial(n int) int64 {
	if n == 0 || n == 1 {
		return 1
	}
	var factorial int64 = 1
	for i := 2; i <= n; i++ {
		factorial *= int64(i)
	}
	return factorial
}

// combination 使用阶乘定义计算组合数C(n, k)
func combination(n, k int) int {
	return (int)(calculateFactorial(n) / (calculateFactorial(k) * calculateFactorial(n-k)))
}

func getRow(rowIndex int) []int {
	result := make([]int, rowIndex+1)
	for i := 0; i <= rowIndex; i++ {
		//注意,这里不能在用append了
		//result = append(result, combination(rowIndex, i))
		result[i] = combination(rowIndex, i)
	}
	return result
}

优化:

记录阶乘中间结果,利用对称性质,仍然有溢出问题

// calculateFactorial 计算阶乘
func calculateFactorial(n int) (int64, map[int]int64) {
	myMap := map[int]int64{
		0: 1,
		1: 1,
	}
	if n == 0 || n == 1 {
		return 1, myMap
	}
	var factorial int64 = 1
	for i := 2; i <= n; i++ {
		factorial *= int64(i)
		myMap[i] = factorial
	}
	return factorial, myMap
}

// combination 使用阶乘定义计算组合数C(n, k)
func combination(n, k int) int {
	nFac, myMap := calculateFactorial(n)
	//注意,计算组合数,分母要加括号
	//return (int)(nFac / myMap[k] * myMap[n-k])
	return (int)(nFac / (myMap[k] * myMap[n-k]))
}

func getRow(rowIndex int) []int {
	result := make([]int, rowIndex+1)
	for i := 0; i <= rowIndex; i++ {
		//注意,这里不能在用append了
		//result = append(result, combination(rowIndex, i))
		//这里,利用对称的性质进行优化
		if i <= rowIndex/2 {
			result[i] = combination(rowIndex, i)
		} else {
			result[i] = result[rowIndex-i]
		}

	}
	return result
}

思路四:利用组合数的递推性质计算

func combination(n, k int) int {
	if k == 0 {
		return 1
	}
    //这里还能优化,把中间结果存下来
	return combination(n, k-1) * (n - k + 1) / k
}

func getRow(rowIndex int) []int {
	result := make([]int, rowIndex+1)
	for i := 0; i <= rowIndex; i++ {
		//注意,这里不能在用append了
		//result = append(result, combination(rowIndex, i))
		//这里,利用对称的性质进行优化
		if i <= rowIndex/2 {
			result[i] = combination(rowIndex, i)
		} else {
			result[i] = result[rowIndex-i]
		}

	}
	return result
}