力扣递归训练

本文介绍了如何生成每种字符数为奇数的字符串,设计了一个循环队列实现,以及针对两两交换链表节点、判断子树、路径和计算、链表加法、二叉搜索树生成和不同二叉搜索树的解决方案。这些算法涉及数据结构、字符串操作和树的遍历等核心概念。
摘要由CSDN通过智能技术生成

1374 生成每种字符都是奇数个的字符串

解题思路

分析好题的关键技巧即可,
用’a’,'b’最简单。n为奇数就返回n个’a’即可
n如果为偶数,就返回n-1个’a’再加上一个’b’即可。

代码

class Solution {
public:
    string generateTheString(int n) {
        string s="";
        if(n % 2== 0){
            for(int i = 0;i<n-1;i++)
                s += 'a';
            s += 'b';
        }else{
            for(int i = 0;i<n;i++)
                s += 'a';
        }
        
        return s;
    }
};

622 设计循环队列

解题思路

队列一定要有指向初始位置,以及结束位置的front和rear。
题中还要再记录一下队列的长度,用于进行front以及rear循环取余的判断。

注意:
1.队列长度为k但实际上最大的索引为k-1,另外由于需要我们空出一个位置,来区分起始位置和其余情况的是否队列为满的问题。所以最终申请的长度为k+1。为了对front以及rear取余我们对k2设置为k+1.
2.我们此处采用初始front= 0,rear = -1;的方式。如果为队列为空则rear+1 == front为true.
3.每次我们空出的那个格子都是front前面的一个格子。
4.其余就每次插入前判断是否为满,删除前判断是否为空即可。

代码

class MyCircularQueue {
public:
	vector<int> ans;
	int front;
	int rear;
	int k2;
	//构造器,设置队列长度为 k 。
    MyCircularQueue(int k) {
        front = 0;
        rear = -1;
        k2 = k+1;
        ans = vector<int>(k+1);//提前开辟这么大的空间 
    }
    //向循环队列插入一个元素。如果成功插入则返回真。
    bool enQueue(int value) {
    	if(isFull()) return false;
    	else{
            rear++;rear %= k2; //记得每步加加后都要取余.
    		ans[rear] = value;
    		
			return true;
    	}
			
    }
    //从循环队列中删除一个元素。如果成功删除则返回真。
    bool deQueue() {
		if(isEmpty())return false;
		else{
			front += 1;
			front %= k2;
			return true;
		}
    }
    //从队首获取元素。如果队列为空,返回 -1 。
    int Front() {
        if(isEmpty())return -1;
        else
		    return ans[front];
    }
    //获取队尾元素。如果队列为空,返回 -1 。
    int Rear() {
        if(isEmpty()) return -1;
        else
		    return ans[rear];
    }
    //检查循环队列是否为空。
    bool isEmpty() {
		return 	rear + 1 == front;
    }
    //检查循环队列是否已满。
    bool isFull() {
    	//开始时刻和这种情况相同 (rear+1) % k2 == front,所以空一位. 
		return 	(rear + 2) % k2 == front;
    }
};

24 两两交换链表中的结点

解题思路

首先我们要知道,只要剩下的未交换过的结点数为1或0则可以停止交换了。

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
    ListNode* node;
public:
    ListNode* swapPairs(ListNode* head) {
        if(head == nullptr || head->next == nullptr){
            return head;
        }
        ListNode* newhead = head->next;//由于交换过后head->next打头,则直接让头指针指向该结点。
        head->next = swapPairs(newhead->next);//要知道head指向的结点将会和后面的结点连接,则重新更新head->next.
        newhead->next = head;//将当前头结点和第二个结点建立联系。
        return newhead;//而下一个将会被返回的结点仍是打头的结点。
    }
};

572 另一棵树的子树

解题思路

理解题意:只要依次走过root树的每个结点,将其与以subRoot为根的树进行深搜比较即可。
通过check依次遍历每个结点,其含义为:当前结点成功或者当前节点的左子树成功,或者当前结点的右子树成功都行。
然后进入dfs中依次匹配,只有当两个结点都为空了,说明能递归到这儿还没被return false 则return true;

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        /*
            1.从相同的根节点开始,递归
        */
        return check(root,subRoot);
    }
    bool check(TreeNode* root,TreeNode* subRoot){
        if(!root){
            return false;
        }
        return dfs(root,subRoot) || check(root->left,subRoot)||check(root->right,subRoot);
    }
    //匹配两个树是否完全相同
    bool dfs(TreeNode* root, TreeNode* subRoot){
        if(!root && !subRoot)return true;//都为空返回true
        if(!root || !subRoot||root->val != subRoot->val){//至多有一个为空,返回false;
            return false;
        }
        /*
            只有这一对结点的值相等不能说明这个结点的后代结点也都对应相等。
            只有对应结点判断后都不能走false,直到最后叶子结点之后,都为空了,才可以判断说这两个树至此都没有不同,则
            返回true.
        */
        // if(root && subRoot){
        //     return root->val == subRoot->val;
        // }
        return dfs(root->left,subRoot->left) && dfs(root->right,subRoot->right);
    }
};

112 路径总和

解题思路

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        return dfs(root,0,targetSum);
    }
    bool dfs(TreeNode* root,int sum,int targetSum){
        if(root==nullptr) return false;//首先要 判断是否为空,要不然sum已经被赋值为0了,可能遇到targetSum的第一个值为0,而root为空的情况。
        if(root->left == nullptr && root->right==nullptr) return (sum+root->val) == targetSum;
         //只有左右孩子都为空才可以进行判断。说明才到达了叶子结点。
        // int leftSum = 0,rightSum = 0;不能再声明了,会每次都被赋值 成0的,还是得放到函数参数中.
       return
       dfs(root->left,sum+root->val,targetSum) ||
        
        dfs(root->right,sum+root->val,targetSum);
         
    }
};

解题思路

首先就是要注意进位的问题,每次相加都是两个链表的对应结点值和进位count相加,
采取新建链表的形式,递归建立每个结点,以及各节点和之前结点的next联系。
只有当两个结点为空且进位为0,时才会返回nullptr。

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        return dfs(l1,l2,0);
    }
    ListNode* dfs(ListNode*l,ListNode* r,int count){
        if(!l&&!r&&!count)return nullptr;
        int sum = (l?l->val:0) + (r?r->val:0) + count;//必须要加括号,否则结果不对,加法运算符的优先级大于三目运算符
        count = sum /10;
        ListNode * node = new ListNode(sum%10);
        node->next = dfs(l?l->next:nullptr,r?r->next:nullptr,count);
        return node;
    }
};

95 不同的二叉搜索树II

解题思路

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<TreeNode*> generateTrees(int n) {
        if(!n){
            return {};
        }
        return generateTrees(1,n);
    }
    vector<TreeNode*> generateTrees(int start,int end){
        if(start > end){//等于是返回这一个结点的情况。
            return {nullptr};//空也一定要 返回,才会在左右孩子集合中 出现。
        }
        vector<TreeNode*> allTrees;
        for(int i = start;i<=end;i++){//从start到end都可以当一次根节点
            vector<TreeNode*> leftTrees = generateTrees(start,i-1);//注意左右孩子队列中的任何一个都可以当其左右孩子。
            vector<TreeNode*> rightTrees = generateTrees(i+1,end);
            //递归到左右孩子为空,,即上步两个generateTrees()返回两个nullptr。
            //下面currTree的左右孩子被设置为nullptr,而currTree为叶子结点,
            for(auto& left: leftTrees)
                for(auto& right: rightTrees){
                    TreeNode* currTree = new TreeNode(i);
                    currTree->left = left;
                    currTree->right = right;
                    allTrees.emplace_back(currTree);
                }
        }
        return allTrees;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值