代码随想录算法训练营第十八天|513.找树左下角的值 112. 路径总和 113. 路径总和II 106.从中序与后序遍历序列构造二叉树 105.从前序与中序遍历序列构造二叉树

目录

LeeCode 513.找树左下角的值

Leecode  112. 路径总和

Leecode  113. 路径总和II

LeeCode 106.从中序与后序遍历序列构造二叉树

LeeCode 105.从前序与中序遍历序列构造二叉树

总结


LeeCode 513.找树左下角的值

513. 找树左下角的值 - 力扣(LeetCode)

思路:通过递归找到最深的叶子节点,其所在位置就是最后一行,使用前序遍历优先左边搜索,保证找到的节点是最左边的节点。

递归法

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
    	traversal(root, 0);
		return result; 
    }
    int maxDepth = INT_MIN;
    int result;
    void traversal(TreeNode* root, int depth) {
    	if (root->left == NULL && root->right == NULL) {
    		if (depth > maxDepth) {
    			maxDepth = depth;
    			result = root->val;
			}
			return;
		}
		if (root->left) {
			depth++;
			traversal(root->left, depth);
			depth--;
		}
		if (root->right) {
			depth++;
			traversal(root->right, depth);
			depth--;
		}
		return;
	}
};

迭代法:使用层次遍历,只需要记录最后一层第一个节点,即为所求。

class Solution {
public:
    int findBottomLeftValue(TreeNode* root) {
    	queue<TreeNode*> que;
    	if (root != NULL) que.push(root);
    	int result = 0;
    	while (!que.empty()) {
    		int size = que.size();
    		for (int i = 0; i < size; i++) {
    			TreeNode* node = que.front();
    			que.pop();
    			if (i == 0) result = node->val;
    			if (node->left) que.push(node->left);
    			if (node->right) que.push(node->right);
			}
		}
    return result;
    }
};

Leecode  112. 路径总和

112. 路径总和 - 力扣(LeetCode)

思路:遍历从根节点到叶子节点的路径计算总和是否为目标和。

细节

1.递归函数需要在找到目标路径后结束,故需要返回值,可以用bool类型表示。

2.判断路径上的节点和是否为目标值,累加起来代码比较复杂,可以通过递减,当 count==0 且到叶子节点时,说明找到了目标和。

3. count == 0 且没到叶子节点 这个条件,不能判断为 false,因为节点的值可以为负,可能这条路径接下来的节点和为0。(如果加了这个条件,会有3个测试样例过不了)

class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
    	if (root == NULL) return false;
		return traversal(root, targetSum - root->val); 
    }
private:
	bool traversal(TreeNode* cur, int count) {
		if (!cur->left && !cur->right && count == 0) return true;
		if (!cur->left && !cur->right) return false;
		if (cur->left) {
			count -= cur->left->val;
			if (traversal(cur->left, count)) return true;
			count += cur->left->val;
		}
		if (cur->right) {
			count -= cur->right->val;
			if (traversal(cur->right, count)) return true;
			count += cur->right->val;
 		}
 		return false;
	}
};

Leecode  113. 路径总和II

113. 路径总和 II - 力扣(LeetCode)

思路:遍历整棵树,找到所有满足条件的路径,故递归函数不需要返回值。

class Solution {
private:
	vector<vector<int>> result;
	vector<int> path;
	void traversal(treenode* cur, int count) {
		if (!cur->left && !cur->right && count == 0) {
			result.push_back(path);
			return;
		}
		if (!cur->left && !cur->right) return;
		if (cur->left) {
			path.push_back(cur->left->val);
			count -= cur->left->val;
			traversal(cur->left, count);
			count += cur->left->val;
			path.pop_back();
		}
		if (cur->right) {
			path.push_back(cur->right->val);
			count -= cur->right->val;
			traversal(cur->right, count);
			count += cur->right->val;
			path.pop_back();
		}
		return;
	}
public:
    vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
    	result.clear();
    	path.clear();
    	if (root == NULL) return result;
    	path.push_back(root->val);
    	traversal(root, targetSum - root->val);
    	return result;
    }
};

LeeCode 106.从中序与后序遍历序列构造二叉树

106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

思路:以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。

步骤:

  • 一:如果数组大小为零的话,说明是空节点了。

  • 二:如果不为空,那么取后序数组最后一个元素作为节点元素。

  • 三:找到后序数组最后一个元素在中序数组的位置,作为切割点

  • 四:切割中序数组,切成中序左数组和中序右数组 

  • 五:切割后序数组,切成后序左数组和后序右数组

  • 六:递归处理左区间和右区间

class Solution {
private:
	TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd,
vector<int>& postorder, int postorderBegin, int postorderEnd) {
		if (postorderBegin == postorderEnd) return NULL;
		
		int rootValue = postorder[postorderEnd - 1];
		TreeNode* root = new TreeNode(rootValue);
		
		if (postorderEnd - postorderBegin == 1) return root;
		
		int delimiterIndex;
		for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd;delimiterIndex++){
			if (inorder[delimiterIndex] == rootValue) break;
		}
		
		int leftInorderBegin = inorderBegin;
		int leftInorderEnd = delimiterIndex;
		
		int rightInorderBegin = delimiterIndex + 1;
		int rightInorderEnd = inorderEnd;
		
		int leftPostorderBegin = postorderBegin;
		int leftPostorderEnd = postorderBegin + delimiterIndex - inorderBegin;
		
		int rightPostorderBegin = postorderBegin + delimiterIndex - inorderBegin;
		int rightPostorderEnd = postorderEnd - 1;
		
		root->left = traversal(inorder, leftInorderBegin, leftInorderEnd, postorder, leftPostorderBegin, leftPostorderEnd);
		root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
		
		return root;
	}
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
    	if (inorder.size() == 0 || postorder.size() == 0) return NULL;
    	return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};

LeeCode 105.从前序与中序遍历序列构造二叉树

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

思路:跟上题一致

class Solution {
private:
	TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
		if (preorderBegin == preorderEnd)  return NULL;
		
		int rootValue = preorder[preorderBegin];
		TreeNode* root = new TreeNode(rootValue);
		
		if (preorderEnd - preorderBegin == 1) return root;
		
		int delimiterIndex;
		for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
			if(inorder[delimiterIndex] == rootValue) break;
		}
		
		int leftInorderBegin = inorderBegin;
		int leftInorderEnd = delimiterIndex;
		int rightInorderBegin = delimiterIndex + 1;
		int rightInorderEnd = inorderEnd;
		
		int leftPreorderBegin = preorderBegin + 1;
		int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin;
		int rightPreorderBegin = preorderBegin + 1 + delimiterIndex - inorderBegin;
		int rightPreorderEnd = preorderEnd;
		
		root->left = traversal(inorder, leftInorderBegin, leftInorderEnd, preorder, leftPreorderBegin, leftPreorderEnd);
		root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, preorder, rightPreorderBegin, rightPreorderEnd);
		
		return root;
	} 
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    	if (inorder.size() == 0 || preorder.size() == 0)  return NULL;
    	return traversal(inorder, 0 , inorder.size(), preorder, 0, preorder.size());
    }
};

总结

1.唯一确定一棵二叉树:前序+中序 / 中序+后序 

2.递归函数返回值情况分析:

若需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。

若需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 

若需要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径时就要及时返回。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值