LeetCode刷题总结(C语言版)_递归类

编程总结

每每刷完一道题后,其思想和精妙之处没有地方记录,本篇博客用以记录刷题过程中的遇到的算法和技巧

104)二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
3
/
9 20
/
15 7
返回它的最大深度 3

int maxDepth(struct TreeNode *root) {
    if (root == NULL) {
        return 0;
    } else { // 递归调用
        return 1 + max(maxDepth(root->left), maxDepth(root->right));
    }
}

递归需要两个条件:
1)递归终止条件
2)递归过程
在这里插入图片描述
递归的递与归。
在这里插入图片描述
递归有分递和归,切记别忘了归,下面列举刚才二叉树深度遍历的例子来说明:

上面利用二叉树深度递归的结果打印输出:
1)先传入root 节点
2)逗号表达式,先遍历right,传入右节点的根节点 right
3)根节点访问,先遍历右节点 right_r,传入右节点 right_r
4) right_r->right 为null,return 0
5) right_r->left 为null,return 0,至此,右节点遍历完成了,开始 “归” 的过程,depth = (1 + max(0 + 0)) ==>> 1. (两个0,就是return返回来的0).
6)遍历左节点 right_l, 同理,左右节点都为null, 所以,depth = (1 + max(0 + 0)) ==>> 1.
7)right_r 和 right_l 点都遍历完成了,depth = (1 + max(1 + 1)) ==>> 2. right 节点遍历完成。
8)接着遍历 left 节点,depth = (1 + max(0 + 0)) ==>> 1.
9)最后 depth = (1 + max(1 + 2)) ==>> 3.
递即先递到右节点的叶子节点,然后由叶子节点逐层由下往上归回来到 root 节点。有点像后序遍历,先右再左。

int maxDepth(struct TreeNode *root) {
    if (root == NULL) {
		printf("root is NULL\n");
        return 0;  
    } else {
		printf("root is %s, depth is %d\n", root->val, depth);
		depth = (1 + max(maxDepth(root->left), maxDepth(root->right)));
        return depth;
    }
}

在这里插入图片描述

98. 验证二叉搜索树
给定一个二叉树,判断其是否是一个有效的二叉搜索树。
假设一个二叉搜索树具有如下特征:
节点的左子树只包含小于当前节点的数。
节点的右子树只包含大于当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。

1)找到最大和最小的值
2)左节点大于min 同时小于根节点
3)右节点小于max 同时大于根节点

112)路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,

          5
         / \
        4   8
       /   / \
      11  13  4
     /  \      \
    7    2      1
bool hasPathSum(struct TreeNode *root, int sum) {
    // 注意:题意要求是根节点到叶子节点的访问,不能只有根节点达到sum
    if (root == NULL) {
        return false; // 异常情况
    }
    // 遍历到叶子节点了
    if (root->left == NULL && root->right == NULL) {
        if (sum-root->val == 0) { // root 是叶子节点,所以应该判断 sum - root->val
            return true;
        } else {
            return false;
        }
    }
    if (hasPathSum(root->left, sum-root->val) == 1) {
        return true;
    }
    if (hasPathSum(root->right, sum-root->val) == 1) {
        return true;
    }

    return false;
}

235. 二叉搜索树的最近公共祖先
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。

struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
    
    if (root == NULL || q == NULL || p == NULL) {
        return NULL;
    }
	// 右边大于根节点
    if (p->val > root->val && q->val > root->val) {
        return lowestCommonAncestor(root->right, p ,q);
    }
	// 左边小于根节点
    if (p->val < root->val && q->val < root->val) {
        return lowestCommonAncestor(root->left, p ,q);
    }
    // 分布在两边,则是root节点为最近公共祖先
    return root;
}

/---------------------------------------------------------------------------------/
贪心算法

455. 分发饼干
– 将最大的饼干给最贪心的小朋友吃
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
输入: [1,2,3], [1,1]
输出: 1
解释:
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。

// use qsort to sort this nums array
int int_cmp(const void *arr1, const void *arr2)
{
    int *arr1_tmp = (int *)arr1;
    int *arr2_tmp = (int *)arr2;
    return (*arr2_tmp - *arr1_tmp);   // 大到小的顺序
}

int findContentChildren(int *g, int gSize, int *s, int sSize) {
    // 1. 排序
    qsort(g, gSize, sizeof(int), int_cmp);
    qsort(s, sSize, sizeof(int), int_cmp);

    int si = 0; // 饼干尺寸 
    int gi = 0; // 小朋友的贪心值
    int res = 0;
    while (gi < gSize && si < sSize) { // 先将最大的饼干给最贪心的小朋友
        if (s[si] >= g[gi]) {
            res++;
            si++;
            gi++;
        } else {
            gi++;
        }
    }

    return res;
}

144. 二叉树的前序遍历
给定一个二叉树,返回它的 前序 遍历。
示例:
输入: [1,null,2,3]
1

2
/
3
输出: [1,2,3]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
};
void iterator(struct TreeNode* root, int *arr, int *returnSize) {
	if (root == NULL) {
		return;
	}
	//val
	*(arr + *(returnSize)) = root->val;
	*(returnSize) = *(returnSize)+1;
	iterator(root->left, arr, returnSize);
	iterator(root->right, arr, returnSize);
}

int* preorderTraversal(struct TreeNode* root, int *returnSize) {
	int *arr = (int *)malloc(sizeof(int) * 1000);
	*(returnSize) = 0;
	if (root == NULL) {
		return arr;
	}
	iterator(root, arr, returnSize);
	return arr;
}

int main() {
	struct TreeNode *root;
	struct TreeNode *root_r;
	struct TreeNode *root_second_l;
	int *returnSize = NULL;
	returnSize = (int *)malloc(4);

	root = (struct TreeNode *)malloc(sizeof(struct TreeNode));
	root->right = (struct TreeNode *)malloc(sizeof(struct TreeNode));
	root_r = (struct TreeNode *)malloc(2*sizeof(struct TreeNode));
	root_r->left = (struct TreeNode *)malloc(2 * sizeof(struct TreeNode));
	root_second_l = (struct TreeNode *)malloc(sizeof(struct TreeNode));

	root->val = 1;
	root_r->val = 2;
	root_second_l->val = 3;
	root_r = root->right;
	root_second_l = root_r->left;
	preorderTraversal(root, returnSize);
	return 0;
}

二叉树的遍历:
前序/中序/后序:
给定一个二叉树,返回它的 前序 遍历。
示例:
在这里插入图片描述

void iterator(struct TreeNode *root, int *arr, int *returnSize) {
	if (root == NULL) { // 递归终止条件是递归到NULL叶子节点
		return;
	}
	*(arr + *(returnSize)) = root->val;    // 存储根节点值到 *arr
	*(returnSize) = *(returnSize) + 1;     // count++
	iterator(root->left, arr, returnSize);
	iterator(root->right, arr, returnSize);
}
int *preorderTraversal(struct TreeNode* root, int *returnSize) {
	int *arr = (int *)malloc(sizeof(int) * 1000);
	*(returnSize) = 0;
	if (root == NULL) { // 异常判断
		return arr;
	}
	iterator(root, arr, returnSize); // 进入递归
	return arr;
}

遍历顺序: 1 -> null -> 2 ->3->null(3’left)->null(3’right)->null(2’right)->结束

中序遍历的区别是赋值代码段的位置

void iterator(struct TreeNode *root, int *arr, int *returnSize) {
	if (root == NULL) { // 递归终止条件是递归到NULL叶子节点
		return;
	}
	iterator(root->left, arr, returnSize);
	*(arr + *(returnSize)) = root->val;    // 赋值断码段 -- 存储根节点值到 *arr
	*(returnSize) = *(returnSize)+1;       // 赋值断码段 -- count++
	iterator(root->right, arr, returnSize);
}
int *inorderTraversal(struct TreeNode* root, int *returnSize) {
	int *arr = (int *)malloc(sizeof(int) * 1000);
	*(returnSize) = 0;
	if (root == NULL) { // 异常判断
		return arr;
	}
	iterator(root, arr, returnSize); // 进入递归
	return arr;
}

遍历顺序: null(1’left) -> 1 ->2->3->null(3’left)->null(3’right)->null(2’right)->结束

后序遍历:

void iterator(struct TreeNode *root, int *arr, int *returnSize) {
	if (root == NULL) { // 递归终止条件是递归到NULL叶子节点
		return;
	}
	iterator(root->left, arr, returnSize);
	iterator(root->right, arr, returnSize);
	*(arr + *(returnSize)) = root->val;    // 赋值断码段 -- 存储根节点值到 *arr
	*(returnSize) = *(returnSize)+1;       // 赋值断码段 -- count++
}

int *postorderTraversal(struct TreeNode* root, int *returnSize) {
	int *arr = (int *)malloc(sizeof(int) * 1000);
	*(returnSize) = 0;
	if (root == NULL) { // 异常判断
		return arr;
	}
	iterator(root, arr, returnSize); // 进入递归
	return arr;
}

遍历顺序: null(1’left)->2->3->null(3’left) -> null(3’right) ->Output:3->null(2’right)->Output:2->Output:1->结束

发布了19 篇原创文章 · 获赞 32 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/wangwangmoon_light/article/details/104226645