所有的题型目录在下面的链接
LeetCode相关典型题解合集(两百多道题)
一、递归
104. 二叉树的最大深度
class Solution {
public:
//递归写法
int maxDepth(TreeNode* root) {
if(root==NULL){
return 0;
}
int l=maxDepth(root->left)+1;
int r=maxDepth(root->right)+1;
return l>r?l:r;
}
};
110.平衡二叉树
class Solution {
public:
int GetHeight(TreeNode *node){//求某一个节点的高度
if(node==nullptr){
return 0;
}
int left=GetHeight(node->left)+1;
int right=GetHeight(node->right)+1;
return max(left,right);
}
bool isBalanced(TreeNode* root) {
//1、自顶向下的解法
if(root==nullptr){
return true;
}
if(abs(GetHeight(root->left)-GetHeight(root->right))>1){
return false;
}
return isBalanced(root->left)&&isBalanced(root->right);
}
};
543.二叉树的直径
class Solution {
public:
int max=0;
int diameterOfBinaryTree(TreeNode* root) {
//自己的办法,思路:跟深度有关。每个节点左右子树高度和的最大值
if(root!=nullptr){
deep(root);
return max;
}
return 0;
}
int deep(TreeNode *node){
if(node==nullptr){
return 0;
}
int l=deep(node->left);
int r=deep(node->right);
if(l+r>max){
max=l+r;
}
return l>r?l+1:r+1;
}
};
226.翻转二叉树
class Solution {
public:
TreeNode *temp=new TreeNode();
TreeNode* invertTree(TreeNode* root) {
//递归法,后序遍历
if(root==nullptr){
return nullptr;
}
invertTree(root->left);
invertTree(root->right);
temp=root->left;
root->left=root->right;
root->right=temp;
return root;
}
};
617.合并二叉树
class Solution {
public:
TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
if(t1==nullptr){
return t2;
}
if(t2==nullptr){
return t1;
}
t1->val+=t2->val;
//记住,这个递归函数的返回值是节点,所以下面的可以这样理解:
//t1的左节点返回的是什么,具体要看上面两个if的判断
//比如t1为空,则说明1树的节点没东西,就两种情况:2树对应的节点有或者没,都可以返回t2的节点
t1->left=mergeTrees(t1->left,t2->left);
t1->right=mergeTrees(t1->right,t2->right);
return t1;
}
};
112. 路径总和(判断路径和是否等于一个数)
class Solution {
public:
bool hasPathSum(TreeNode* root, int sum) {
if(root==nullptr){
return false;
}
if(root->left==nullptr&&root->right==nullptr){
return root->val==sum;
}
//如果要返回的是节点本身,而不是长度等变量,就是左子树||右子树,
return hasPathSum(root->left,sum-root->val)||hasPathSum(root->right,sum-root->val);
}
};
437. 统计路径和等于一个数的路径数量
class Solution {
public:
//最简单的递归算法,可以改进很多
int count=0;
int pathSum(TreeNode* root, int sum) {
if(root==nullptr){
return 0;
}
countPath(root,sum);
pathSum(root->left,sum);
pathSum(root->right,sum);
return count;
}
void countPath(TreeNode *node,int sum){
if(node==nullptr){
return ;
}
sum-=node->val;
if(sum==0){
count++;
}
countPath(node->left,sum);
countPath(node->right,sum);
}
};
572. 另一个数的子树
class Solution {
public:
bool isSubtree(TreeNode* s, TreeNode* t) {
if(s==nullptr){
return false;
}
return isEqual(s,t)||isSubtree(s->left,t)||isSubtree(s->right,t);
}
bool isEqual(TreeNode *l,TreeNode*r){
if(l==nullptr&&r==nullptr){
return true;
}
if(l==nullptr||r==nullptr){
return false;
}
if(l->val!=r->val){
return false;
}
//如果左子树相等还要看右子树是否相等才能判断是否是相等
return isEqual(l->left,r->left)&&isEqual(l->right,r->right);
}
};
101. 树的对称
class Solution {
public:
bool isSymmetric(TreeNode* root) {
return isEqual(root,root);
}
bool isEqual(TreeNode *l,TreeNode *r){
//子节点要么都不为空,要么都为空
if(l==nullptr&&r==nullptr){
return true;
}
if(l==nullptr||r==nullptr){
return false;
}
return (l->val==r->val)&&isEqual(l->left,r->right)&&isEqual(l->right,r->left);
}
};
111. 最小路径(最小深度)
class Solution {
public:
int minDepth(TreeNode* root) {
//这个方法时间终极爆炸!
if(root==nullptr){
return 0;
}
int l=minDepth(root->left)+1;
int r=minDepth(root->right)+1;
if(l==1||r==1){
return l>r?l:r;
}else{
return l<r?l:r;
}
}
};
404. 统计左叶子节点的和
class Solution {
public:
int sum=0;
int sumOfLeftLeaves(TreeNode* root) {
//递归,简单的方法
if(root==nullptr){
return 0;
}
//判断是否是左叶子的方法
if(root->left!=nullptr&&root->left->left==nullptr&&root->left->right==nullptr){
sum+=root->left->val;
}
sumOfLeftLeaves(root->left);
sumOfLeftLeaves(root->right);
return sum;
}
};
687. 相同节点值的最大路径长度
class Solution {
public:
//递归的写法,一共是两种情况
//1、左右子树依次递归下去
//2、一个子树的节点和根都相同
int max=0;
int longestUnivaluePath(TreeNode* root) {
GetMax(root);
return max;
}
int GetMax(TreeNode *node){
if(node==nullptr){
return 0;
}
/*int intervalMax=0;
int left=GetMax(node->left);
int right=GetMax(node->right);
//1种情况
if(node->left!=nullptr&&node->left->val==node->val){
intervalMax=left+1;
}
if(node->right!=nullptr&&node->right->val==node->val){
intervalMax=intervalMax>left?intervalMax:right+1;
}
int max=max>intervalMax?max:intervalMax;
//2
if(node->left!=nullptr&&node->right!=nullptr&&node->left->val==node->val&&node->right->val==node->val){
max=max>(left+right+2)?max:left+right+2;
}
return intervalMax;*/
int intLeft=0;
int intRight=0;
int left=GetMax(node->left);
int right=GetMax(node->right);
if(node->left!=nullptr&&node->val==node->left->val){
intLeft=left+1;
}
if(node->right!=nullptr&&node->val==node->right->val){
intRight=right+1;
}
max=max>intRight+intLeft?max:intRight+intLeft;
return intLeft>intRight?intLeft:intRight;
}
};
337. 间隔遍历(打家劫舍三)
class Solution {
public:
//本质上就是间隔遍历
//把问题直接简化成两个部分:①偷父节点②不偷父节点
int rob(TreeNode* root) {
if(root==nullptr){
return 0;
}
if(root->left==nullptr&&root->right==nullptr){
return root->val;
}
//偷父节点的
int cash1=root->val;
int cash2=0;
if(root->left!=nullptr){
cash1+=rob(root->left->left)+rob(root->left->right);
}
if(root->right!=nullptr){
cash1+=rob(root->right->left)+rob(root->right->right);
}
//不偷父节点
cash2+=rob(root->left)+rob(root->right);
return cash1>cash2?cash1:cash2;
}
};
671. 找出二叉树中第二小的节点
class Solution {
public:
int findSecondMinimumValue(TreeNode* root) {
//①暴力破解
/*vector<int> sequence;
construct_vector(root,sequence);
sort(sequence.begin(),sequence.end(),less<int>());
int min=sequence.front();
int sec_min=0;
if(sequence.empty()==true||sequence.size()==1){
return -1;
}else{
for(int i=0;i<sequence.size();i++){
if(sequence[i]>min){
sec_min=sequence[i];
break;
}
}
}
if(sec_min==0){
return -1;
}
return sec_min;*/
/*************************************************************************************/
//根据这颗树的特点来做
//注意!这道题的最小节点肯定是根节点,但是第二小的结点不确定,自己想一下就知道了,所以必须遍历所有的结点。
return get_val(root,root->val);
}
int get_val(TreeNode *root,int n){
if(root==nullptr){
return -1;
}
if(root->val>n){
return root->val;
}
int left=get_val(root->left,n);
int right=get_val(root->right,n);
if(left>n&&right>n){
return left>right?right:left;
}
return left>right?left:right;
}
void construct_vector(TreeNode *root,vector<int> &vec){
if(root){
construct_vector(root->left,vec);
vec.push_back(root->val);
construct_vector(root->right,vec);
}
}
};
第二种方法
1.没有必要记录最小的值,因为最小的一定是根结点。 2.递归找到比根结点大的值时可以立即返回,不用再遍历当前节点下面的子节点,因为子节点的值不可能比它小。
class Solution {
public:
int firstbigger(TreeNode* root, int val) {
if (!root) return -1;
if (root -> val > val) return root -> val;
int left = firstbigger(root -> left, val);
int right = firstbigger(root -> right, val);
if (left < 0) return right;
if (right < 0) return left;
return min(left, right);
}
int findSecondMinimumValue(TreeNode* root) {
return firstbigger(root, root -> val);
}
};
二、层序遍历
637.二叉树每层节点的平均数
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
queue<TreeNode*> q;
vector<double> ves;
q.push(root);
double total=0;
if(root==NULL){
return ves;
}
while(!q.empty()){
int length =q.size();
total=0;
for(int i=0;i<length;i++){
TreeNode *p=q.front();
total+=p->val;
q.pop();
if(p->left!=NULL){
q.push(p->left);
}
if(p->right!=NULL){
q.push(p->right);
}
}
ves.push_back(total/length);
}
return ves;
}
};
513. 找到树左下角的值
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> q;
vector<int> vec;
q.push(root);
int temp;
while(!q.empty()){
int length=q.size();
if(!vec.empty()){
vec.clear();
}
for(int i=0;i<length;i++){
TreeNode *p=q.front();
vec.push_back(p->val);
q.pop();
if(p->left!=NULL){
q.push(p->left);
}
if(p->right!=NULL){
q.push(p->right);
}
}
}
return vec.front();
}
};
三、前中后序遍历(非递归)
144. 非递归实现二叉树的前序遍历
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> sequence;
stack<TreeNode* > s;
while(root||!s.empty()){
while(root){
sequence.push_back(root->val);
s.push(root);
root=root->left;
}
if(!s.empty()){
root=s.top();
s.pop();
root=root->right;
}
}
return sequence;
}
};
94. 非递归实现二叉树的中序遍历
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> sequence;
stack<TreeNode*> s;
while(root||!s.empty()){
while(root){
s.push(root);
root=root->left;
}
if(!s.empty()){
root=s.top();
sequence.push_back(root->val);
s.pop();
root=root->right;
}
}
return sequence;
}
};
145. 非递归实现二叉树的后序遍历
高频面试题!
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> sequence;
stack<TreeNode*> s;
//用来记录上一个节点
TreeNode *pre=nullptr;
while(root||!s.empty()){
while(root){
s.push(root);
root=root->left;
}
root=s.top();
//防止此节点的右孩子重复访问
if(!root->right||root->right==pre){
sequence.push_back(root->val);
s.pop();
pre=root;
root=nullptr;
}else{
root=root->right;
}
}
return sequence;
}
};
四、BST(二叉搜索树)
669. 修剪二叉查找树
class Solution {
public:
TreeNode* trimBST(TreeNode* root, int low, int high) {
if(root==nullptr){
return root;
}
//如果根节点的值小于low,则说明看右子树的了,因为左子树的孩子节点都比根节点小
else if(root->val<low){
return trimBST(root->right,low,high);
}
//跟上面同理
else if(root->val>high){
return trimBST(root->left,low,high);
}
root->left=trimBST(root->left,low,high);
root->right=trimBST(root->right,low,high);
return root;
}
};
230. 二叉搜索树中第K小的元素
class Solution {
public:
int m;
int count=0;
int kthSmallest(TreeNode* root, int k) {
if(root){
kthSmallest(root->left,k);
count++;
if(count==k){
m=root->val;
}
kthSmallest(root->right,k);
}
return m;
}
};
235. 二叉搜索树的最近公共祖先
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root){
if(root->val<p->val&&root->val<q->val){
root=root->right;
}
else if(root->val>p->val&&root->val>q->val){
root=root->left;
}
else{
return root;
}
}
return NULL;
}
};
236. 二叉树的最近公共祖先
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==NULL){
return root;
}
if(root==p||root==q){
return root;
}
TreeNode *left=lowestCommonAncestor(root->left,p,q);
TreeNode *right=lowestCommonAncestor(root->right,p,q);
if(left==nullptr&&root==nullptr){
return nullptr;
}
if(left==nullptr){
return right;
}
if(right==nullptr){
return left;
}
if(left!=nullptr&&right!=nullptr){
return root;
}
return nullptr;
}
};
108. 将有序数组转换为二叉搜索树
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return constructBST(nums,0,nums.size());
}
TreeNode *constructBST(vector<int>& nums,int l,int r){
if(l>=r){
return NULL;
}
int mid=(l+r)/2;
TreeNode *root=new TreeNode(nums[mid]);
root->left=constructBST(nums,l,mid);
root->right=constructBST(nums,mid+1,r);
return root;
}
};
109. 有序链表转换二叉搜索树
class Solution {
public:
TreeNode* sortedListToBST(ListNode* head) {
if(!head){
return nullptr;
}
else if(!head->next){
return new TreeNode(head->val);
}
ListNode *pre=head;
ListNode *p=head;
ListNode *q=head;
while(q!=nullptr&&q->next!=nullptr){
p=p->next;
q=q->next->next;
}
while(pre->next!=p){
pre=pre->next;
}
pre->next=nullptr;
TreeNode *root=new TreeNode(p->val);
root->left=sortedListToBST(head);
root->right=sortedListToBST(p->next);
return root;
}
};
653. 在二叉查找树中寻找两个节点,使它们的和为一个给定值
class Solution {
public:
vector<int> sequence;
bool findTarget(TreeNode* root, int k) {
mid_order(root,sequence);
int l=0;
int r=sequence.size()-1;
while(l<r){
if(sequence[l]+sequence[r]>k){
r--;
}
else if(sequence[l]+sequence[r]<k){
l++;
}else if(sequence[l]+sequence[r]==k){
return true;
}
}
return false;
}
void mid_order(TreeNode *root,vector<int> &vec){
if(root){
mid_order(root->left,vec);
vec.push_back(root->val);
mid_order(root->right,vec);
}
}
};
530. 在二叉查找树中查找两个节点之差的最小绝对值
class Solution {
public:
vector<int> sequence;
int getMinimumDifference(TreeNode* root) {
mid_order(root,sequence);
int min=abs(sequence[1]-sequence[0]);
//注意是中序遍历是有序递增的!
for(int i=0;i<sequence.size()-1;i++){
/*for(int j=0;j<sequence.size();j++){
if(i!=j&&abs(sequence[i]-sequence[j])<min){
min=abs(sequence[i]-sequence[j]);
}
}*/
if(abs(sequence[i]-sequence[i+1])<min){
min=abs(sequence[i]-sequence[i+1]);
}
}
return min;
}
void mid_order(TreeNode *root,vector<int>& vec){
if(root){
mid_order(root->left,vec);
vec.push_back(root->val);
mid_order(root->right,vec);
}
}
};
501. 寻找二叉查找树中出现次数最多的值
class Solution {
public:
//最麻烦的,开辟额外空间的写法,用一个vector存储中序遍历的值,一个返回众数的值
vector<int> sequence;
vector<int> findMode(TreeNode* root) {
vector<int> res;
int count=1;
int max_count=1;
int order;
mid_order(root,sequence);
if(root==nullptr){
return {};
}
for(int i=0;i<sequence.size()-1;i++){
if(sequence[i]==sequence[i+1]){
count++;
}else{
count=1;
}
if(count>max_count){
max_count=count;
order=i;
res.clear();
res.push_back(sequence[order]);
}
else if(count==max_count){
max_count=count;
order=i;
res.push_back(sequence[order]);
}
}
//注意如果数组都不相同,返回空vector,return {}
if(max_count==1){
return sequence;
}
return res;
}
void mid_order(TreeNode*root,vector<int> &vec){
if(root){
mid_order(root->left,vec);
vec.push_back(root->val);
mid_order(root->right,vec);
}
}
};
五、trie(前缀树或字典树)
Trie,又称前缀树或字典树,用于判断字符串是否存在或者是否具有某种字符串前缀。
208. 实现一个 Trie
677. 实现一个 Trie,用来求前缀和
总结
提示。