今天下午没去实验室做毕设,一个人跑到图书馆刷题去了。气温微凉,外面下着点小雨,是我非常喜欢的天气。
LC108,109 Convert Sorted Array / Sorted List to BST
LC108 将有序的数组转化为BST,LC109 将有序的单链表转化为BST。第一个比较简单,用二分和递归的方法,找到mid作为root,将两侧的子数组循环调用构造BST的递归函数。LC109的思路差不多,维护一个指向当前链表位置的变量list,用递归调用的方法先生成左侧数组的BST,函数返回后list应当指向该子数组右侧的第一个元素。然后创建root,再将list向后推一个,继续调用BST生成函数。代码:
int listLen(ListNode* head) {
ListNode* runner = head;
int i = 0;
while (runner) {
runner = runner->next;
i++;
}
return i;
}
TreeNode* getBST(ListNode*& list, int len) {
if (len == 0) {
return NULL;
}
TreeNode* root = new TreeNode(0);
root->left = getBST(list, len / 2);
root->val = list->val;
list = list->next;
root->right = getBST(list, len - len / 2 - 1);
return root;
}
TreeNode* sortedListToBST(ListNode* head) {
return getBST(head, listLen(head));
}
函数具体执行的过程中,len = 1时用第一个链表元素new一个TreeNode,之后len = 2,new一个新的TreeNode,第一个元素的TreeNode成为了它的左孩子,并且getBST(list, len-len/2-1)生成一个右孩子(可能为空)。向BST添加节点的顺序是链表从左往右的顺序进行的。
LC110 Balanced Binary Tree
判断二叉树是否为平衡二叉树。递归的方法,depth函数返回子树的高度。判断时,先判断子树中有没有出现不平衡,用返回值-1表示,出现直接返回-1. 如果子树中一切正常,判断左右子树的返回值(树的高度)的差值,大于1则破坏平衡条件,返回-1. 代码:
int depth(TreeNode* root) {
if (root == NULL) {
return 0;
}
int leftDepth = depth(root->left);
int rightDepth = depth(root->right);
if (leftDepth == -1 || rightDepth == -1 || abs(leftDepth - rightDepth) > 1) {
return -1;
}
return max(leftDepth,rightDepth) + 1;
}
bool isBalanced(TreeNode* root) {
if (depth(root) == -1) {
return false;
}
return true;
}
LC111 Minimum Depth of Binary Tree
二叉树的最浅深度。用BSF实现,效率应该会比DFS更高。BSF用Queue实现,在push root时顺带push一个NULL用来标志一层的末尾。用计数器记录当前深度,当出现某个节点的左右子树均为空的情况,说明发现了一个最浅的节点,此时返回当前深度。代码:
int minDepth(TreeNode* root) {
if (root == NULL) {
return 0;
}
queue<TreeNode*> q;
q.push(root);
q.push(NULL);
int depth = 0;
while (!q.empty()) {
TreeNode* thisNode = q.front();
q.pop();
if (thisNode == NULL) {
if (!q.empty()) {
q.push(NULL);
}
depth++;
}
else{
if (thisNode->left == NULL && thisNode->right == NULL) {
break;
}
if (thisNode->left) {
q.push(thisNode->left);
}
if (thisNode->right) {
q.push(thisNode->right);
}
}
}
return depth + 1;
}
LC112,113 Path Sum I / II
判断和寻找存在的从root到leaf的路径使得路径上的节点的和等于某个特定值。递归实现,参数中有一个sum表示当前剩下的sum,每次向下的试探都用sum减当前节点的val作为下一层的sum。当试探到树的最底层且sum==0时说明找到了所求路径。注意树中的value可以小于零,所以不要写sum<0就判断不存在的逻辑。
bool hasPathSum(TreeNode* root, int sum) {
if (root == NULL) {
return false;
}
sum -= root->val;
if (sum == 0 && root->left == NULL && root->right == NULL) {
return true;
}
return (root->left && hasPathSum(root->left, sum)) || (root->right && hasPathSum(root->right, sum));
}
void tryPath(TreeNode* root, int sum, vector<vector<int>>& res, vector<int>& cur) {
sum -= root->val;
cur.push_back(root->val);
if (sum == 0 && !root->left && !root->right) {
res.push_back(cur);
return;
}
if (root->left) {
tryPath(root->left, sum, res, cur);
cur.pop_back();
}
if (root->right) {
tryPath(root->right, sum, res, cur);
cur.pop_back();
}
}
vector<vector<int>> pathSum(TreeNode* root, int sum) {
vector<vector<int>> res;
if (root == NULL) {
return res;
}
vector<int> cur;
tryPath(root, sum, res, cur);
return res;
}
Given a binary tree, flatten it to a linked list in-place.
For example, given the following tree:
1 / \ 2 5 / \ \ 3 4 6
The flattened tree should look like:
1 \ 2 \ 3 \ 4 \ 5 \ 6
把一个二叉树转化为每个节点(除叶节点)都只有右孩子的最长的树。根据题意,所要得到的新的树应该是按照原来树的先序遍历顺序得到的。在生成新的树的时候,遍历原来的树时从最后的节点开始遍历,这样每次都拿得到的新的子树拼接到节点的右孩子上,例如上面的例子里面,先遍历到节点6,再遍历节点5,再把6放置在5的右孩子。同理,遍历的顺序是6-5-4-3-2-1,得出结论:按照从右到左的顺序-后序遍历二叉树。递归的写满足这样条件的遍历顺序,先flatten(root->right), then flatten(root->left), 最后处理root。处理方式:将之前得到的子树prevNode放到root的右孩子上,将root的左孩子置空,最后将root赋给prevNode供下一次函数拼接。其实把这样的调用顺序用前几天刚学过的stack frame写出来,就会发现这就是利用函数调用的机制里面的压栈出栈的实现方式代替其他时候我们青睐的栈实现的先/中/后序遍历。