C++ 算法之递归问题总结

斐波那契数列:

n=0,f(n)=0,n=1,f(n)=1

f(n) = f(n-1) + f(n-2) 

递归解法:

int Fibonacci(int n)
    {
        if(n <= 1)
        {
            return n;
        }
        else
        {
            return Fibonacci(n - 1) + Fibonacci(n - 2);
        }
    }

问题:n过大容易导致栈溢出,改为循环

int Fibonacci(int n) {
        // 非常容易理解,0,1,2的时候单独处理
        if(n <= 0){
            return 0;
        }
        if(n == 1 || n ==2){
            return 1;
        }
        int a = 1;
        int b = 1;
        int result;
        // 然后处理的时候获取到A+B的结果,然后把B赋值给A,结果赋值给B,一步步忘后面移动
        for(int i = 3;i<=n;i++){
            result = a + b;
            a = b;
            b = result;
        }
        return result;
    }

 

青蛙变态跳台阶问题:

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

由于每次跳的阶数不确定,没有一个固定的规律,但是可以了解的是后一次跳是在前一次跳的结果上累加的,因此我们可以考虑使用递归的方法来解决问题。

  那么从递归的三个步骤开始寻找解决方案:

  1. 递归截止条件。

  由于每次可以跳1-n的任意阶数,因此无论有多少阶,都可以一次跳完,为了表示方便,我们将一次性跳完的情况设为F(0),当n=1时,只能有一种情况,F(1) = 1。当n=2时,可以每次跳1阶,也可以一次跳两阶,则F(2) = 2。

  2. 递归的前后衔接。

  假设现在又n阶,可以跳完n阶的情况分别是:一次跳完F(0);先跳一步F(1),后面还有F(n-1)种跳法;或者先跳两步F(2),后面还有F(n-2)种跳法。依次类推,第一次跳出n阶后,后面还有 F(n-n)中跳法。可以得出:

   F(n) = F(n-1)+F(n-2)+F(n-3)+..........+F(0)=2F(n-1)

递归写法:

int jumpFloorII(int number) {
        if(number<=0) 
           return 0;
        else if(number==1) 
           return 1;
        else 
           return 2*jumpFloorII(number-1);
    }

循环写法:

int JumpFloorII(int target) {
         if(target==0||target==1)
             return 1;
         if(target==2)
             return 2;
         int sum = 0;
         for(int i=0;i<target;i++){
             sum += JumpFloorII(i);
         }
         return sum;
     }

 

合并两个排序链表:

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

 ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        
        if(pHead1==nullptr)
            return pHead2;
        else if(pHead2==nullptr)
            return pHead1;
        
        ListNode* pMerge=nullptr;
        
        if(pHead1->val>pHead2->val){
            pMerge=pHead2;
            pMerge->next=Merge(pHead1,pHead2->next);
        }
        else{
            pMerge=pHead1;
            pMerge->next=Merge(pHead1->next,pHead2);
        }
        return pMerge;
    }

 

二叉树的深度:

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

int TreeDepth(TreeNode* pRoot)
    {
        if(pRoot==nullptr)
            return 0;
        
        int nleft=TreeDepth(pRoot->left);
        int nright=TreeDepth(pRoot->right);
        
        return (nleft>nright)?(nleft+1):(nright+1);
    
    }

 

二叉树的镜像:

void Mirror(TreeNode *pRoot) {
        if(pRoot){
        TreeNode *tmp = pRoot->left;
        pRoot->left = pRoot->right;
        pRoot->right = tmp;

        Mirror(pRoot->left);
        Mirror(pRoot->right);
        }
            return ;
}

 

对称二叉树:

给定一个二叉树,判断是否为对称二叉树。

bool isSymmetrical(TreeNode* pRoot1, TreeNode* pRoot2){//递归判断两个左右子树是否对称

        if (pRoot1 == NULL && pRoot2 == NULL){//如果均为空,说明相等,是对称的
            return true;
        }

        if (pRoot1 == NULL || pRoot2 == NULL){//如果有一个为空,另一个不为空,说明不对称
            return false;
        }

        if (pRoot1->val != pRoot2->val){//都不为空时,判断值是否相等,再递归判断左右子树
            return false;
        }

        return (isSymmetrical(pRoot1->left, pRoot2->right) &&
               (isSymmetrical(pRoot1->right, pRoot2->left)));
    }

 

一般二叉树的最低公共祖先

当遍历到一个root点的时候,

1.判断root是不是null如果root为null,那么就无所谓祖先节点,直接返回null就好了

2.如果root的左子树存在p,右子树存在q,那么root肯定就是最近祖先

3.如果pq都在root的左子树,那么就需要递归root的左子树,右子树同理

 

 TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
      if(root == NULL || root == p || root ==q) 
          return root;
      TreeNode* left = lowestCommonAncestor(root->left, p, q);
      TreeNode* right = lowestCommonAncestor(root->right, p, q);
      if(left && right){
          return root;
      }
      else
      {
          return left == NULL ? right : left;
      }
 }

 

树的子结构(两重递归):

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

bool DoseTree1HaveTree2(TreeNode* pRoot1,TreeNode* pRoot2){
        
            if(pRoot2==nullptr)
                return true;
            if(pRoot1==nullptr)
                return false;
            if(pRoot1->val!=pRoot2->val)
                return false;
            return DoseTree1HaveTree2(pRoot1->left,pRoot2->left)&&
                DoseTree1HaveTree2(pRoot1->right,pRoot2->right);
        }
    
    
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        bool result=false;
        
        if(pRoot1!=nullptr&&pRoot2!=nullptr)
        {
            if(pRoot1->val==pRoot2->val)
                result=DoseTree1HaveTree2(pRoot1,pRoot2);
            if(result==0)
                result=HasSubtree(pRoot1->left,pRoot2);
            if(result==0)
                result=HasSubtree(pRoot1->right,pRoot2);
        }
       return result;
    }

 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值