天池训练营链接
对称二叉树
1.递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool helper(TreeNode* p, TreeNode* q){
if(!p && !q) return true;//无左无右
if((!p && q )||(!q && p)) return false;//只有左或只有右
return (p->val==q->val) && helper(p->left,q->right) && helper(p->right, q->left);
}
bool isSymmetric(TreeNode* root) {
return helper(root->left, root->right);
}
};
2.迭代
队列处理,把对称位置的节点成对放入队列,再每次弹出两个来比较
从下往上用栈,从上往下用队列
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool helper(TreeNode* u, TreeNode* v){
queue<TreeNode*> q;
q.push(u); q.push(v);
while(!q.empty()){
u=q.front(); q.pop();
v=q.front(); q.pop();
if(!u && !v) continue;
if(!u || !v) return false;
if(u->val != v->val) return false;
q.push(u->left); q.push(v->right);
q.push(u->right); q.push(v->left);
}
return true;
}
bool isSymmetric(TreeNode* root) {
return helper(root, root);
}
};
二叉树的中序遍历
这个是基本题,要做到的是递归不出错且快,迭代不出错且快,Morris也要熟练掌握。之前的百度一面是链表和数组,字节一面是二叉树,注意一下。
这种基本题建议背了。
题解链接
1.递归,给的函数有返回v,所以要新建一个没返回值的,来遍历。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void helper(TreeNode* root, vector<int> &v){
if(!root){
return;
}
helper(root->left, v);
v.push_back(root->val);
helper(root->right, v);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> v;
helper(root, v);
return v;
}
};
2.栈
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> v;
stack<TreeNode*> stk;
while(root!=nullptr || !stk.empty()){
while(root!=nullptr){
stk.push(root);
root=root->left;
}//左子全进栈
root=stk.top();
stk.pop();
v.push_back(root->val);
root=root->right;//左子都处理完了,本身也处理过了才会到右子
}
return v;
}
};
3.Morris
核心就是往下遍历的时候把中序遍历访问root的前一个节点指向root
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> v;
TreeNode* pre=nullptr;
while(root != nullptr){
if (root->left != nullptr){
pre=root->left;
while(pre->right != nullptr && pre->right != root){
pre=pre->right;//找最右,但不能过root
}
//pre指向left的最右子节点,是中序里面root的前一个节点
if(pre->right == nullptr){//没换成root,就给连上root
pre->right = root;
root = root->left;//换成root后root往下遍历
}
//if(pre->right==root){//左子树已经访问完了,断开链接
else{//right指向root的情况,表示左边已经访问完了
v.push_back(root->val);
pre->right = nullptr;
root = root->right;
}
}
else{
v.push_back(root->val);
root=root->right;
}
}
return v;
}
};
二叉搜索树中第K小的元素
中序遍历+排序,O(nlogn),空间O(n)
class Solution {
public:
void dfs(TreeNode* root, vector<int> &v){
if(!root) return;
dfs(root->left, v);
v.push_back(root->val);
dfs(root->right, v);
}//中序遍历
int kthSmallest(TreeNode* root, int k) {
vector<int> v;
dfs(root, v);
sort(v.begin(), v.end());
return v[k-1];
}
};
中序遍历,O(H+k),H是树高,空间O(H)
class Solution {
public:
int kthSmallest(TreeNode* root, int k) {
//中序遍历k次,就是第k小的数
stack<TreeNode*> stk;
while(root!=nullptr || !stk.empty()){
while(root!=nullptr){
stk.push(root);
root=root->left;
}
root=stk.top(); stk.pop();
//注意这里,要把root弹出来再判断root,否则可能没root会报错
k--;
if(k==0){
return root->val;//可以写break,最后return
}
root=root->right;
}
return 0;
}
};
二分查找
先写个递归二分
class Solution {
public:
int bi_search(int left, int right, int target, vector<int>& nums){
if(left>right) return -1;
int mid=(left+right)/2;
if(nums[mid] < target) return bi_search(mid+1,right,target,nums);
if(nums[mid] > target) return bi_search(left,mid-1,target,nums);
else return mid;
}
int search(vector<int>& nums, int target) {
return bi_search(0, nums.size()-1, target, nums);
}
};
官方题解用的迭代二分
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0,right=nums.size()-1;
while(left <= right){//这里注意用等于
int mid=left+(right-left)/2;
//这里(left+right)/2也行,但是慢一点
if(nums[mid]==target){
return mid;
}
else if(nums[mid]>target){
right=mid-1;
}
else{
left=mid+1;
}
}
return -1;
}
};
搜索旋转排序数组
class Solution {
public:
int search(vector<int>& nums, int target) {
//二分以后,一边是升序,一边是旋转,第一个数大于最后一个数就是旋转,否则就是升序,每次丢一半
//只能判断升序那一半
int left=0, right=nums.size()-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]==target) return mid;
else if(nums[left]>nums[mid]){
//左半边是旋转
if(target<nums[mid] || target>nums[right]){
right=mid-1;//-1,+1必须有,这样每次判断把mid去掉,能确保推进,不陷入无限循环
}
else{
left=mid+1;
}
}
else {//右半边是旋转
if(target<nums[left] || target>nums[mid]){
left=mid+1;
}
else{
right=mid-1;
}
}
}
return -1;
}
};