1.10 LeetCode总结(基本算法)_递归算法

编程总结

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

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;
    }
}

在这里插入图片描述

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;
    }
	// 如果节点 p 和节点 q 都在右子树上,那么以右孩子为根节点继续 1 的操作
    if ((p->val > root->val) && (q->val > root->val)) {
        return lowestCommonAncestor(root->right, p ,q);
    }
	// 如果节点 p 和节点 q 都在左子树上,那么以左孩子为根节点继续 1 的操作
    if ((p->val < root->val) && (q->val < root->val)) {
        return lowestCommonAncestor(root->left, p ,q);
    }
    // 分布在两边,则已经找到节点是root节点为最近公共祖先

    return root;
}

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;
	}
	*(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->结束

79. 单词搜索

给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
在这里插入图片描述

bool visited[1000][1000] = { 0 };

bool searchWord(char **board, int boardSize, int *boardColSize, char *word, int index, int startx, int starty) {
	bool result = 0;

	if ((startx < 0 || startx >= boardSize || starty < 0 || starty >= (*boardColSize))) {
		return false;
	}
	if (visited[startx][starty] == 1) {
		return false;
	}
	if (board[startx][starty] != word[index]) { // 此时已经说明 [0, strlen(word)-1] 相等,因为 index 的范围就是 [0, strlen(word)-1]
		return false;
	}
	if (index + 1 == strlen(word)) {
		return true;
	}

	visited[startx][starty] = 1;  // 从四个方向寻找
	result = searchWord(board, boardSize, boardColSize, word, index + 1, startx - 1, starty) ||
	searchWord(board, boardSize, boardColSize, word, index + 1, startx, starty + 1) ||
	searchWord(board, boardSize, boardColSize, word, index + 1, startx + 1, starty) ||
	searchWord(board, boardSize, boardColSize, word, index + 1, startx, starty - 1);
	visited[startx][starty] = 0;

	return result;
}

bool exist(char **board, int boardSize, int *boardColSize, char *word) {
	for (int v = 0; v < 1000; v++) {
		memset(visited[v], 0, sizeof(visited[0]));
	}
	for (int i = 0; i < boardSize; i++) {
		for (int j = 0; j < *boardColSize; j++) {
			if (searchWord(board, boardSize, boardColSize, word, 0, i, j)) {
				return true;
			}
		}
	}

	return false;
}

101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

对称二叉树就是要求: L.right == R.left && L.left == R.right

bool isSymmetric(struct TreeNode *root) {
	bool res = false;
	if (root == NULL) {
		return true;
	}

	return isSymTree(root->left, root->right);
}

bool isSymTree(struct TreeNode *root_left, struct TreeNode *root_right)
{
	bool res = false;
	// 递归终止条件
	if (root_left == NULL && root_right == NULL) {
		return true;
	}
	else if (root_left == NULL || root_right == NULL) { // 注意root没有左或者右节点时,为False
		return false;
	}
	if (root_left->val  != root_right->val) {
		return false;
	}
	res = isSymTree(root_left->left, root_right->right) && isSymTree(root_left->right, root_right->left);
	
	return res;
}

108. 将有序数组转换成二叉搜索树

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值