18.重建二叉树
输入一棵二叉树前序遍历和中序遍历的结果,请重建该二叉树。
class Solution {
public:
map mp;
TreeNode* buildTree(vector& preorder, vector& inorder) {
int n=inorder.size();
for(int i=0;i& preorder,vector& inorder,int pl,int pr,int il,int ir){
if(pl>pr) return NULL;
TreeNode* root=new TreeNode(preorder[pl]);
int l=mp[preorder[pl]]-il;
root->left=dfs(preorder,inorder,pl+1,pl+l,il,l+il-1);//长度是l,但是左右是闭区间,右边区间减去一
root->right=dfs(preorder,inorder,pl+1+l,pr,l+1+il,ir);
return root;
}
};
19.二叉树的下一个节点
中序遍历的下一个节点,如果有右儿子,则找右儿子的最左侧节点,没有右儿子,找这个点的父节点,直到找到某个点是它父节点的左儿子。O(h)
class Solution {
public:
TreeNode* inorderSuccessor(TreeNode* p) {
if(p->right){
p=p->right;
while(p->left) p=p->left;
return p;
}
while(p->father&&p==p->father->right) p=p->father;
return p->father;
}
};
23.矩阵中的路径
就是在矩阵中找字符串,dfs很基础的题目,我竟然也不会写了??
class Solution {
public:
bool hasPath(vector>& matrix, string str) {
//if(matrix[0].size()==0||matrix.size()==0) return false;
for(int i=0;i>& matrix,string &str,int i,int j,int id){
if(matrix[i][j]!=str[id]) return false;
if(id==str.size()-1) return true;
char c=matrix[i][j];
matrix[i][j]='*';
int dx[5]={0,-1,0,1},dy[5]={1,0,-1,0};
for(int k=0;k<4;k++){
int a=i+dx[k],b=j+dy[k];
//一定要注意先写区间的判断条件,再写是否为标记的,会报段错误
if(a>=0&&a=0&&b
27.数值的整数次方
快速幂也不会写了,负数可以写成unsigned int再取负号,就不会越界。
class Solution {
public:
double Power(double base, int exponent) {
unsigned int n=exponent;
double ans=1;
//cout<>=1;
base=base*base;
}
if(exponent<0) ans=1.0/ans;
return ans;
}
};
29.删除链表中重复的元素
处理头结点,设置两个指针,p指向上一段的最后一个结点,q用来寻找接下来一段相同数字的后一个结点。如果这段长度等于一,则p可以指向这个段,后移一位;大于一,可以将p->next指向q结点,继续判断下一段,这样就可以直接把中间相同的都删掉,只用next指向即可。
见到这种题,先想指针应该怎么指
p上一段的最后一个节点,因为p所指的都要,p->next是下一段,可能被选,前提是长度等于1;
q一整段相同数字的下一个节点,因为p可以直接指向,上一段已经都相同,直接处理掉,q永远指向新的段。
class Solution {
public:
ListNode* deleteDuplication(ListNode* head) {
if(head==NULL) return NULL;
ListNode *pre=new ListNode(-1);
pre->next=head;
ListNode *p=pre,*q=head;
while(p->next){
while(q&&p->next->val==q->val) q=q->next;
if(p->next->next==q) p=p->next;
else p->next=q;
}
return pre->next;
}
};
35.反转链表
可以头插法,指针全指向前面,递归res函数一点和后面一段。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL) return NULL;
ListNode *pre=new ListNode(-1);
pre->next=head;
ListNode *p=pre->next,*r=pre->next;
while(p){
if(r->next) r=r->next;
else r=NULL;
if(p==pre->next) p->next=NULL;
else p->next=pre->next;
pre->next=p;
p=r;
}
return pre->next;
}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *prev = nullptr;
ListNode *cur = head;
while (cur)
{
ListNode *next = cur->next;
cur->next = prev;
prev = cur, cur = next;
}
return prev;
}
};
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if (!head || !head->next) return head;
ListNode *tail = reverseList(head->next);
head->next->next = head;
head->next = nullptr;
return tail;
}
};
37.树的子结构
我们同时从根节点开始遍历两棵子树:
如果树B中的节点为空,则表示当前分支是匹配的,返回true;
如果树A中的节点为空,但树B中的节点不为空,则说明不匹配,返回false;
如果两个节点都不为空,但数值不同,则说明不匹配,返回false;
否则说明当前这个点是匹配的,然后递归判断左子树和右子树是否分别匹配即可;
//贴个y总的代码
class Solution {
public:
bool hasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) {
if (!pRoot1 || !pRoot2) return false;
if (isSame(pRoot1, pRoot2)) return true;
return hasSubtree(pRoot1->left, pRoot2) || hasSubtree(pRoot1->right, pRoot2);
}
bool isSame(TreeNode* pRoot1, TreeNode* pRoot2) {
if (!pRoot2) return true;
if (!pRoot1 || pRoot1->val != pRoot2->val) return false;
return isSame(pRoot1->left, pRoot2->left) && isSame(pRoot1->right, pRoot2->right);
}
};
38.二叉树的镜像
swap可以交换二叉树的两个指针哦
class Solution {
public:
void mirror(TreeNode* root) {
if(!root) return ;
swap(root->left,root->right);
mirror(root->left);
mirror(root->right);
}
};
39.对称的二叉树
用栈模拟递归,对根节点的左子树,我们用中序遍历;对根节点的右子树,我们用反中序遍历。
则两个子树互为镜像,当且仅当同时遍历两课子树时,对应节点的值相等。
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if (!root) return true;
stack left, right;
TreeNode *lc = root->left;
TreeNode *rc = root->right;
while(lc || rc || left.size()){
while (lc && rc){
left.push(lc), right.push(rc);
lc = lc->left, rc = rc->right;
}
if (lc || rc) return false;
lc = left.top(), rc = right.top();
left.pop(), right.pop();
if (lc->val != rc->val) return false;
lc = lc->right, rc = rc->left;
}
return true;
}
};
41.分行从上到下打印二叉树
每行的结尾多设置一个null记录。
class Solution {
public:
vector> printFromTopToBottom(TreeNode* root) {
vector> res;
vector cur;
if (!root) return res;
queue q;
q.push(root);
q.push(NULL);
while (q.size()) {
auto t = q.front();
q.pop();
if(t){
cur.push_back(t->val);
if (t->left) q.push(t->left);
if (t->right) q.push(t->right);
}
else{
//一定要注意这里需要判断q是否为空,如果不判断的话,就一直在加null,会报内存超限的错。
if(q.size()) q.push(NULL);
res.push_back(cur);
cur.clear();
}
}
return res;
}
};
53.最小的k个数
优先队列默认是大顶堆,小顶堆用greater。
//大顶堆
priority_queue,less >que;
//小顶堆
priority_queue,greater >que;
class Solution {
public:
vector getLeastNumbers_Solution(vector input, int k) {
vector res;
priority_queue heap;
for(auto x : input)
{
heap.push(x);
if(heap.size() > k) heap.pop();
}
while(heap.size())
{
//cout<
55.连续子数组的最大和
class Solution {
public:
int maxSubArray(vector& nums) {
int sum = 0, maxv = 0xcfcfcfcf; //求最大值,max初始化为负无穷
for (int i = 0; i < nums.size(); i ++ ) //遍历数组
{
sum += nums[i];
maxv = max(maxv, sum); //一边累加sum一边更新最大值
if (sum < 0) sum = 0; //当sum小于0,则丢弃重开
//这里你可能会问为什么sum小于0就丢弃,如果数组里所有的数都是负数呢?
//答:若数组中全是负数,那么最大值就是最小的那一个负数,因为负数越累加越小。
}
return maxv;
}
};
75.和为s的两个数
最后return要用大括号扩住
class Solution {
public:
vector findNumbersWithSum(vector& nums, int target)
{
unordered_map hash;//创建哈希表
for (int i = 0; i < nums.size(); ++i) {
if(hash[target - nums[i]] == 0)//如果哈希表中没有target - nums[i]
hash[nums[i]]++;//nums[i]出现次数加1
else//如果哈希表中有target - nums[i]
return {nums[i], target - nums[i]};//返回答案
}
return {};
}
};
79.滑动窗口的最大值
单调队列,双端队列,维护队列单调递减,把队列后面小于当前值的元素都删掉。
多画图想想,如果不是删末尾的将导致不知道中间的最大值是啥。
class Solution {
public:
vector maxInWindows(vector& nums, int k) {
deque q;
vector ans;
for(int i=0;i=k)) q.pop_front();
while(q.size()&&nums[q.back()]<=nums[i]) q.pop_back();
q.push_back(i);
if(i>=k-1) ans.push_back(nums[q.front()]);
}
return ans;
}
};
66.两个链表的公共结点
很神奇的思想,一定要记住,a+c+b和b+c+a。
class Solution {
public:
ListNode *findFirstCommonNode(ListNode *headA, ListNode *headB) {
ListNode *p=headA,*q=headB;
while(q!=p){
if(p) p=p->next;
else p=headB;
if(q) q=q->next;
else q=headA;
}
return p;
}
};
46.二叉搜索树的后序遍历
直接判断该序列能否构成一个二叉搜索树即可,最后一个节点为根节点,然后找左边的都比它小,右边的都比它大,符合条件即可。
class Solution {
public:
bool verifySequenceOfBST(vector sequence) {
if(sequence.size()==0) return true;
return dfs(0,sequence.size()-1,sequence);
}
bool dfs(int l,int r,vector sequence){
if(l>=r) return true;
int x=sequence[r],k=l;
while(k
51.数字排列
先把数字按照大小顺序排列,dfs枚举每个数字一次,填到空白的位置上,记录一个pre,如果两个数字相同,则是上个数的位置下标+1,如果不相同,则为0。
class Solution {
public:
vector> ans;
vector path;
vector st;
vector> permutation(vector& nums) {
//path.resize(nums.size());
//st.resize(nums.size());
path=vector(nums.size(),0);
st=vector(nums.size(),false);
sort(nums.begin(),nums.end());
dfs(nums,0,0);//pre上个相同数字的位置,确保不重复
return ans;
}
void dfs(vector& nums,int u,int pre){
if(u==nums.size()){
ans.push_back(path);
return ;
}
for(int i=pre;i
88. 树中两个结点的最低公共祖先
分别在某结点的左右子树上找p,q,如果p,q分别在左右子树上,则root就是最近公共祖先;如果两个都在同一侧继续遍历这一侧。时间复杂度是o(n)
递归:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(!root)
return NULL;
if(root==p||root==q)
return root;
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(left&&right)
return root;
if(left==NULL)
return right;
else
return left;
}
};
非递归:
class Solution {
public:
int findPath(TreeNode*root, TreeNode* p, vector&path){
if(!root)
return 0;
if(root->val==p->val){
path.push_back(root);
return 1;
}
int l = findPath(root->left,p,path);
int r = findPath(root->right,p,path);
if(l==1||r==1)
path.push_back(root);
return l==1||r==1;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vectorpath1,path2;
findPath(root,p,path1);
findPath(root,q,path2);
if(path1.empty()||path2.empty())
return NULL;
TreeNode* res =NULL;
for(int i = 0;i=path1.size()||i>=path2.size())
break;
if(path1[path1.size()-1-i]==path2[path2.size()-1-i])
res = path1[path1.size()-1-i];
else
break;
}
return res;
}
};
72. 平衡二叉树
递归左右高度,然后用一个ans记录正确与否
class Solution {
public:
bool ans=true;
int h(TreeNode* root){
if(!root) return 0;
int l=h(root->left);
int r=h(root->right);
if(abs(l-r)>1) ans=false;
return max(l,r)+1;
}
bool isBalanced(TreeNode* root) {
h(root);
return ans;
}
};
64. 字符流中第一个只出现一次的字符
很巧妙的一个题,利用队列维护位置的单调性;
队列和双指针都是经常用到的优化时间的工具;用map记录出现次数,用队列维护位置的单调性。
当进入一个字符,出现字符次数大于一了,就从队头开始删除重复出现元素
查找时,直接返回队头。
class Solution{
public:
unordered_map mp;
queue q;
//Insert one char from stringstream
void insert(char ch){
if(++mp[ch]>1){
while(!q.empty()&&mp[q.front()]>1) q.pop();
}
else{
q.push(ch);
}
}
//return the first appearence once char in current stringstream
char firstAppearingOnce(){
if(q.empty()) return '#';
else return q.front();
}
};
65.数组中的逆序对
递归里面运行完两个mergeSort后,start~mid 和 mid+1~end都是有序的,且两个内部的逆序对都已经算过了,只需要算当前状态的逆序对就行了,不会重复的。
利用归并排序计算,两个数组合并,如果出现第二个数组里的某一个数字大于第一个数组里的当前数字,res+=第一个数组i以后的全部。
class Solution {
public:
vector temp;
int inversePairs(vector& nums) {
return merge(nums,0,nums.size()-1);
}
int merge(vector& nums,int l,int r){
if(l>=r) return 0;
int i=l,mid=(l+r)/2;
int j=mid+1;
int res=merge(nums,l,mid)+merge(nums,mid+1,r);
temp.clear();
while(i<=mid&&j<=r){
if(nums[i]<=nums[j]){
temp.push_back(nums[i++]);
}
else{
temp.push_back(nums[j++]);
res+=mid-i+1;
}
}
while(i<=mid) temp.push_back(nums[i++]);
while(j<=r) temp.push_back(nums[j++]);
j=0;
for(int i=l;i<=r;i++){
nums[i]=temp[j++];
//cout<