1、 二叉树的先序遍历可以理解为深度搜索,首先搜索到最左叶子节点并可以得到路径所有节点的值,再在遍历过程中会对树整体从左到右每一个叶子节点的路径(根节点到叶子节点的所有节点)进行搜索(叶子节点不一定在同一层),相当于深度搜索;
2、 vector实现stack,push_back()相当于压栈,pop_back()相当于弹出栈顶元素,这样一来既可以实现栈的功能(得到搜索路径,且首元素为根节点,即栈底,符合该题输出要求),也可以反向输出栈的元素(从底到顶),想了一下好像双端队列也可以实现这个功能。
1、核心思路就是当两节点有公共的离根节点最远的祖先时,在这两个节点的搜索路径上(分别表示为pathP和pathQ),这个祖先之前的搜索路径是相同的,也就是路径pathP和pathQ最前面是完全一样的,当出现第一个不一样的路径节点时,前一个节点就是最近公共祖先(也即离根节点最远的公共祖先);
2、那么解题思路就和1差不多了,先通过二叉树的遍历算法求取两个节点的路径,然后比较路径,路径可以用vector来存储,便于比较;
3、写的过程中碰到一个BUG,如果没有用result数组来就地存下寻找到的路径的话,会因为函数递归的问题,上层递归函数由于存在最后一行代码path.pop_back()
把原本保存好的地址给弹出,导致程序只会记录根节点。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
// 二叉树node中搜索key的路径,并保存至path中
// 函数需要一个参数result来接收当时的结果,否则在递归调用的过程中虽然当时path是路径结果,但是其上层调用会pop_back()掉一些元素
void searchPath(TreeNode* node, TreeNode* key, vector<TreeNode*> &path, vector<TreeNode*> &result, int &flag)
{
// 找到节点或者到了叶子节点就返回
if(!node || flag){
return;
}
// 先序遍历搜索路径
// 路径压栈,搜索根节点到节点key的路径
path.push_back(node);
if(node == key){
flag = 1;
result = path;
return;
}
searchPath(node->left, key, path, result, flag);
searchPath(node->right, key, path, result, flag);
path.pop_back();
}
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
// 存储两个节点的搜索路径
vector<TreeNode*> pathP, resultP;
vector<TreeNode*> pathQ, resultQ;
int finP = 0, finQ = 0;
searchPath(root, p, pathP, resultP, finP);
searchPath(root, q, pathQ, resultQ, finQ);
TreeNode* publicNode = NULL;
for(int i = 0, n=min(resultQ.size(), resultP.size()); i<n; i++){
if(resultP[i]==resultQ[i])
publicNode = resultQ[i];
else
break;
}
return publicNode;
}
};
1、题目有点长,其实意思还是挺清晰,总结来看就是对一个点求8邻域内的值为1元素总和(1为活细胞),然后根据当前元素判断是要将该元素置1还是置0;
2、常规解法很容易想,就相当于图像的卷积,每个邻域求出结果然后开一个新的数组存储结果(否则在原数组更新会有问题,因为要求同时更新),最后再把值赋给原数组;
3、主要记录一下这个8邻域的查询思想吧,因为要判断数组下标是否越界,一开始是想只用两个嵌套for循环来循环行和列并用if来判断索引是否越界,后来写着写着发现情况好复杂,要判断row>=0/row
!(i==1&&j==1)
这个条件,目的是为了防止读取到的是中心元素(也就是需要修改的元素)。
4、题目提示可以采用原地算法(直接原数组操作)来解,想了一会儿想不出,看到题解好像是说可以用位操作来解,还是我太菜了o(╥﹏╥)o
class Solution {
public:
void gameOfLife(vector<vector<int>>& board) {
vector<vector<int>> res(board);
int neighbors[3] = {1, 0, -1};
int rows = board.size(), cols = board[0].size();
for(int row = 0; row<rows; row++){
for(int col = 0; col<cols; col++){
// 对每个细胞进行查询,相当于卷积
int count = 0;
for(int i = 0; i<3; i++){
for(int j=0; j<3; j++){
int dr = row + neighbors[i];
int dc = col + neighbors[j];
// 防止数组越界
if(dr>=0 && dr<rows && dc>=0 && dc<cols && !(i==1&&j==1) && board[dr][dc]==1)
count++;
}
}
// 根据规则判别
if(board[row][col]==1){
if(count<2) res[row][col]=0;
else if(count==2 || count==3) res[row][col]=1;
else res[row][col]=0;
}
else{
if(3==count) res[row][col]=1;
else res[row][col]=0;
}
}
}
board = res;
}
};
实现了递归法和非递归法,非递归法利用了栈,主要是理清中序遍历的逻辑顺序。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
// 递归解法
/*vector inorderTraversal(TreeNode* root) {
vector res;
inorder(res, root);
return res;
}
void inorder(vector &res, TreeNode* node){
if(node==nullptr) return;
inorder(res, node->left);
res.push_back(node->val);
inorder(res, node->right);
}*/
// 非递归解法
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> sinorder;
TreeNode* p=root;
// 当栈中还有元素或者p不为空时,继续循环
while(p!=nullptr || !sinorder.empty()){
// p为空的时候就要退出到上一个节点并输出
// 然后把右子节点压入路径
if(p==nullptr){
// 按照栈的顺序输出
p=sinorder.top();
sinorder.pop();
res.push_back(p->val);
// 输出完后压入右子节点
p=p->right;
}
// p不为空时就继续向左子节点深入
else {
sinorder.push(p);
p=p->left;
}
}
return res;
}
};