给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 3
输出: [1,3,3,1]
进阶:
你可以优化你的算法到 O(k) 空间复杂度吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/pascals-triangle-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
long long int C(int m,int n)
{
long long int i=0,com=1,cm=1;
for(i=0;i<n;i++)
com = com*(m-i);
for(i=1;i<=n;i++)
cm = cm*i;
com = com/cm;
return com;
}
int* getRow(int rowIndex, int* returnSize){
int *zero = (int *)malloc(sizeof(int)*(rowIndex+1));
zero[0] = 1;
if(rowIndex == 0)
{
*returnSize = 1;
return zero;
}
int i=0,j=0;
int *array = (int *)malloc(sizeof(int)*(rowIndex+1));
memset(array,0,(rowIndex+1)*sizeof(int));
*returnSize = rowIndex+1;
array[0] = 1;
array[rowIndex] = 1;
if(rowIndex <= 27)
for(i=1;i<=rowIndex/2+1;i++)
{
array[i] = C(rowIndex,i);
array[rowIndex-i] = array[i];
}
else
{
int *narray = (int *)malloc(sizeof(int)*(rowIndex+1));
for(i=0;i<rowIndex+1;i++)
narray[i] = 1;
for(i=1;i<=27/2+1;i++)
{
narray[i] = C(27,i);
narray[27-i] = narray[i];
}
for(i=28;i<=rowIndex;i++)
{
for(j=1;j<=i/2+1;j++)
{
array[j] = narray[j-1]+narray[j];
array[i-j] = array[j];
}
for(j=1;j<rowIndex+1;j++)
narray[j] = array[j];
}
}
return array;
}
这里用了杨辉三角形的部分数学规律,比如某一行的元素个数是行数加1,、某一行关于中间处对称且两头都是1。
最主要的是这里使用了一个性质某一行某一位的数等于其组合数,即第M行第N个数即为C(M,N),利用这个性质我编写了一个计算组合数的函数。
但是有一个问题就是我编写的函数容易出现溢出问题,在rowIndex等于28时就直接溢出无法计算了,我想了两个解决办法:办法一是从计算组合数的函数下手,通过重新优化计算方法,使其不会溢出;办法二是使用杨辉三角另一个规律即第M行第N个数等于第M-1行第N-1个数和第N个数之和。
这里我采用了第二种方法,没有为什么,就是玩儿~(主要是想联系下使用加法解决该问题)
关于标题所说的memset()
赋初值问题,我到今天才发现之前用错了,正确的使用格式是:
memset(array,0,(rowIndex+1)*sizeof(int));
第一个变量是数组名,第二个变量是赋值的数,第三个是数组的空间大小。
这里注意的是说是赋初值,但其实是把数组清零,并没法赋其他的初值。如果想把数组全部赋初值为1,那么就会出现这种情况
原因是memset函数是按照字节赋值的,int 是4个字节所以为0x01010101,就是十进制的16843009。
另外一点需要注意的是第三个变量数组的空间大小,一般是这种形式的
memset(a,0,n*sizeof(type));
所以给数组赋初值除非是清零,不然还是用for循环吧。
看了官方解答后感觉自己想的太复杂了,又或者是想的太简单了。
直接使用一个二维数组,就避免了反复利用循环和利用新的数组去存储和计算所需值。另外对第i行的数据进行计算时只是用了第i-1行的数据,所以可以对其进行滚动数组处理,即大大起到压缩作用、
int* getRow(int rowIndex, int* returnSize) {
*returnSize = rowIndex + 1;
int* pre = malloc(sizeof(int) * (*returnSize));
memset(pre, 0, sizeof(int) * (*returnSize));
int* cur = malloc(sizeof(int) * (*returnSize));
memset(cur, 0, sizeof(int) * (*returnSize));
for (int i = 0; i <= rowIndex; ++i) {
cur[0] = cur[i] = 1;
for (int j = 1; j < i; ++j) {
cur[j] = pre[j - 1] + pre[j];
}
int* tmp = pre;
pre = cur;
cur = tmp;
}
return pre;
}
int* getRow(int rowIndex, int* returnSize) {
*returnSize = rowIndex + 1;
int* row = malloc(sizeof(int) * (*returnSize));
memset(row, 0, sizeof(int) * (*returnSize));
row[0] = 1;
for (int i = 1; i <= rowIndex; ++i) {
for (int j = i; j > 0; --j) {
row[j] += row[j - 1];
}
}
return row;
}
如果使用乘法:
int* getRow(int rowIndex, int* returnSize) {
*returnSize = rowIndex + 1;
int* row = malloc(sizeof(int) * (*returnSize));
row[0] = 1;
for (int i = 1; i <= rowIndex; ++i) {
row[i] = 1LL * row[i - 1] * (rowIndex - i + 1) / i;
}
return row;
}