【解题报告】《LeetCode零基础指南》(第九讲) 简单递归

【解题报告】《LeetCode零基础指南》(第九讲) 简单递归_第1张图片

☘前言☘

今天是九日集训第八天,我会记录一下学习内容和题解,争当课代表0.0.
链接:《LeetCode零基础指南》(第九讲) 简单递归

作者简介:一个从工业设计改行学嵌入式的年轻人
✨联系方式:2201891280(QQ)
全文大约阅读时间: 20min


全文目录

  • ☘前言☘
  • 主要知识点梳理
    • 1.递归含义
    • 2.递归调用阶乘
    • 3. 为什么叫递归
  • 课后习题
    • 172. 阶乘后的零
    • 1342. 将数字变成 0 的操作次数
    • 222. 完全二叉树的节点个数
    • LCP 44. 开幕式焰火
    • 397. 整数替换
    • 938. 二叉搜索树的范围和
    • 剑指 Offer 55 - I. 二叉树的深度
    • 104. 二叉树的最大深度
    • 226. 翻转二叉树
    • 剑指 Offer II 110. 所有路径
    • 797. 所有可能的路径
  • 写在最后


主要知识点梳理

1.递归含义

套娃生万物,而递归就是函数自己调用自己。
递归需要记住三点内容:

  1. 要实现一个函数,这个函数会自己调用自己,并且每次调用,函数传参是不一样的。
  2. 递归一定要有出口,即满足一定条件后需要return,否则就可能出现死递归(引起栈溢出)。
  3. 根据递归式来补充你的递归调用内容。

【解题报告】《LeetCode零基础指南》(第九讲) 简单递归_第2张图片

2.递归调用阶乘

我们知道,阶乘即:
n ! = n ∗ ( n − 1 ) ∗ ( n − 2 ) ∗ . . . ∗ 3 ∗ 2 ∗ 1 n! = n *(n-1)*(n-2)*...*3*2*1 n!=n(n1)(n2)...321
我们如果想用递归进行计算,就需要转换为递推式,如下:
n ! = n ∗ ( n − 1 ) ! n! = n*(n-1)! n!=n(n1)!
我们可以得出一下的递归式:
f ( n ) = n f ( n − 1 ) f(n) = n f(n-1) f(n)=nf(n1)


1. 实现一个函数

int JieCheng(int n){
}

2. 递归出口

int JieCheng(int n) {
  if(n <= 1) {
      return 1;
  }
}

3. 递推关系

int JieCheng(int n) {
  if(n <= 1) {
          return 1;
  }
  return n * JieCheng(n-1);
}

3. 为什么叫递归

f(5)
= 5 * f(4)
= 5 * (4 * f(3))
= 5 * (4 * (3 * f(2)))
= 5 * (4 * (3 * (2 * f(1))))
= 5 * (4 * (3 * (2 * 1)))
= 5 * (4 * (3 * 2))
= 5 * (4 * 6)
= 5 * 24
= 120

【解题报告】《LeetCode零基础指南》(第九讲) 简单递归_第3张图片


课后习题

172. 阶乘后的零

172. 阶乘后的零

题目描述

给定一个整数 n ,返回 n! 结果中尾随零的数量。
提示n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1

思路

因为阶乘的0的数量其实取决于这个数中10的因子个数。但是10 = 5 *2。其中2的数量会比5的数量多,所以只需要5因子的数量就好了。其中5的倍数贡献一个。25贡献两个,125贡献三个,但是25还是5的倍数,所以只需要再算一次就好了。 125也是一样的道理,125算一个就好了。

int trailingZeroes(int n){
    int ans = 0;
    for(int i = 5;i <= n;i*=5){
        ans += n / i;
    }
    return ans;
}

1342. 将数字变成 0 的操作次数

1342. 将数字变成 0 的操作次数

题目描述

给你一个非负整数 num,请你返回将它变成 0 所需要的步数。 如果当前数字是偶数,你需要把它除以 2 ;否则,减去 1 。

思路

按照要求进行除就好了。

int numberOfSteps(int num){
    if(num == 0) return 0;
    else if( num & 1 == 1)  return numberOfSteps(num -1) +1;
    else return numberOfSteps(num / 2) +1;
}

222. 完全二叉树的节点个数

222. 完全二叉树的节点个数

题目描述

给你一棵 完全二叉树 的根节点 root,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h层,则该层包含 1~ 2h个节点。

思路

利用先根遍历的写法就行了。

void previsit(struct TreeNode *root,int *ans){
    if(root){
        (*ans) ++;
        previsit(root->left,ans);
        previsit(root->right,ans);
    }
}

int countNodes(struct TreeNode* root){
    int ans = 0;
    previsit(root,&ans);
    return ans;
}

LCP 44. 开幕式焰火

LCP 44. 开幕式焰火

题目描述

「力扣挑战赛」开幕式开始了,空中绽放了一颗二叉树形的巨型焰火。
给定一棵二叉树root代表焰火,节点值表示巨型焰火这一位置的颜色种类。请帮小扣计算巨型焰火有多少种不同的颜色。

思路

利用hash表来做标记,然后进行先根遍历。然后最后算数量。

int hash[1001];
void get123(struct TreeNode * );

int numColor(struct TreeNode* root){
    int ans = 0;
    memset(hash,0,sizeof(hash));
    get123(root);
    for(int i = 0; i < 1001; ++i){
        if(hash[i]) ans++;
    }
    return ans;
}

void get123(struct TreeNode * root){
    if(root){
        if(root ->left) get123(root->left);
        hash[root->val]++;
        if(root->right) get123(root->right);
    }
}

397. 整数替换

397. 整数替换

题目描述

给定一个正整数 n,你可以做如下操作:

  1. 如果n 是偶数,则用n / 2替换n
  2. 如果n是奇数,则可以用n + 1n - 1替换n

n变为1所需的最小替换次数是多少?

思路

如果是偶数,毫无疑问是直接除以2就好了。
如果是奇数:

  1. 如果这个奇数是k = 4*n+1那么(k-1)/2会得到更小的值。
  2. 如果这个奇数是k = 4*n+3 那么(k+1)/4会得到最小的值,但是有一个特殊情况就是n=3
int integerReplacement(int n){
    int ans = 0;
    while(n != 1){
        if(n % 2 == 0)  n /= 2;
        else if(n % 4 == 1){
            n /= 2;
            ans++;
        }
        else{
            if(n == 3)  n = 1;
            else n = n/2 + 1;
            ans++;
        }
        ans++;
    }
    return ans;
}

938. 二叉搜索树的范围和

938. 二叉搜索树的范围和

题目描述

给定二叉搜索树的根结点 root,返回值位于范围[low, high]之间的所有结点的值的和。

思路

先根遍历的方式来统计和就好了。

void previsit(struct TreeNode *root,int low,int high,int *ans){
    if(root){
        if(root->val >= low && root->val <= high)  (*ans) += root->val;
        previsit(root->left,low,high,ans);
        previsit(root->right,low,high,ans);
    }
}

int rangeSumBST(struct TreeNode* root, int low, int high){
    int ans = 0;
    previsit(root,low,high,&ans);
    return ans;
}


剑指 Offer 55 - I. 二叉树的深度

剑指 Offer 55 - I. 二叉树的深度

题目描述

输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。
例如:
给定二叉树 [3,9,20,null,null,15,7],

思路

其实可能需要层序遍历的,但是也可以用先序遍历来看层的深度,做个记录就好了。

void previsit(struct TreeNode *root,int *max,int ceng){
    if(root){
        ceng ++;
        if(ceng > *max) *max = ceng;
        previsit(root->left,max,ceng);
        previsit(root->right,max,ceng);
    }
}

int maxDepth(struct TreeNode* root){
    int max = 0;
    previsit(root,&max,0);
    return max;
}


104. 二叉树的最大深度

104. 二叉树的最大深度

题目描述

给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树[3,9,20,null,null,15,7]

思路

其实可能需要层序遍历的,但是也可以用先序遍历来看层的深度,做个记录就好了。

void previsit(struct TreeNode *root,int *max,int ceng){
    if(root){
        ceng ++;
        if(ceng > *max) *max = ceng;
        previsit(root->left,max,ceng);
        previsit(root->right,max,ceng);
    }
}

int maxDepth(struct TreeNode* root){
    int max = 0;
    previsit(root,&max,0);
    return max;
}


226. 翻转二叉树

226. 翻转二叉树

题目描述

翻转一棵二叉树。

思路

遍历每个节点,交换左右节点。

struct TreeNode* invertTree(struct TreeNode* root){
    if(root){
        struct TreeNode *temp;
        temp = root->left;
        root->left = root->right;
        root->right = temp;
        invertTree(root->left);
        invertTree(root->right);
    }
    return root;
}

剑指 Offer II 110. 所有路径

剑指 Offer II 110. 所有路径

题目描述

给定一个有 n 个节点的有向无环图,用二维数组graph表示,请找到所有从 0n-1的路径并输出(不要求按顺序)。

graph的第i个数组中的单元都表示有向图中i号节点所能到达的下一些结点(译者注:有向图是有方向的,即规定了 a→b 你就不能从 b→a ),若为空,就是没有下一个节点了。

思路

根据每个节点进行深度遍历,如果等于所要求的数据,就将路径所有的节点插入到最终的结果。因为无环,所以不需要标记数据。

void dfs(int x,int n, int **graph, int *graphColSize,int *returnSize,int **returnColumnSizes,int **ans,int *temp,int tempsize){
    if(x == n){
        int *tmp = malloc(sizeof(int)*tempsize);
        memcpy(tmp,temp,sizeof(int) * tempsize);
        ans[*returnSize] = tmp;
        (*returnColumnSizes)[(*returnSize)++] = tempsize;
        return;
    }
    for(int i = 0; i < graphColSize[x];i++){
        int y = graph[x][i];
        temp[tempsize++] = y;
        dfs(y,n, graph , graphColSize, returnSize,returnColumnSizes,ans,temp,tempsize);
        tempsize--;
    }
}
int** allPathsSourceTarget(int** graph, int graphSize, int* graphColSize, int* returnSize, int** returnColumnSizes){
    int **ans;
    int temp[15];
    int tempsize = 0;
    temp[tempsize++] = 0;
    ans = malloc(sizeof(int *) * (1<<13));
    *returnSize = 0;
    (*returnColumnSizes) = malloc(sizeof(int) *(1<<13));
    dfs(0,graphSize - 1, graph , graphColSize, returnSize,returnColumnSizes,ans,temp,tempsize);
    return ans;
}

797. 所有可能的路径

797. 所有可能的路径

题目描述

给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序)
二维数组的第 i 个数组中的单元都表示有向图中 i 号节点所能到达的下一些节点,空就是没有下一个结点了。
译者注:有向图是有方向的,即规定了 a→b 你就不能从 b→a 。

思路

和上面一样,所以看上面的把。

void dfs(int x,int n, int **graph, int *graphColSize,int *returnSize,int **returnColumnSizes,int **ans,int *temp,int tempsize){
    if(x == n){
        int *tmp = malloc(sizeof(int)*tempsize);
        memcpy(tmp,temp,sizeof(int) * tempsize);
        ans[*returnSize] = tmp;
        (*returnColumnSizes)[(*returnSize)++] = tempsize;
        return;
    }
    for(int i = 0; i < graphColSize[x];i++){
        int y = graph[x][i];
        temp[tempsize++] = y;
        dfs(y,n, graph , graphColSize, returnSize,returnColumnSizes,ans,temp,tempsize);
        tempsize--;
    }
}
int** allPathsSourceTarget(int** graph, int graphSize, int* graphColSize, int* returnSize, int** returnColumnSizes){
    int **ans;
    int temp[15];
    int tempsize = 0;
    temp[tempsize++] = 0;
    ans = malloc(sizeof(int *) * (1<<13));
    *returnSize = 0;
    (*returnColumnSizes) = malloc(sizeof(int) *(1<<13));
    dfs(0,graphSize - 1, graph , graphColSize, returnSize,returnColumnSizes,ans,temp,tempsize);
    return ans;
}

写在最后

今天结束了六级,也结束了数字集成电路的作业,所以最近有亿点点时间可以更新,所以要开算法坑了,有一起的同学们么?首页见!

你可能感兴趣的:(九日集训,leetcode,算法,职场和发展)