105. Construct Binary Tree from Preorder and Inorder Traversal105. Construct Binary Tree from Preorder and Inorder Traversal
题意:根据前序遍历和中序遍历来构造二叉树
我的思路
要用递归造树,要同时递归左子树和右子树,造树需要左边边界和右边边界
build函数有树的跟指针,前序的有左边边界和右边边界,中序的左边边界和右边边界
如果l>r return;因为是先序遍历,所以左子树是先序的第一个,先构造了;
不会做不会做
标答
上面标粗的部分是正确的,构造就在递归的时候构造,不用把树的根作为指针放到参数里面
之后就是搞清楚pl,pr和ir,il就可以了【做着做着居然做出来了!!】
例子:前序[3,0,9,4,6,2,5,7,8,1]
中序[4,9,6,0,2,3,5,8,7,1]
显而易见,左子树的pl是pl+1;左子树的il是il;左子树的ir是pos-1;
显而易见,右子树的pr=pr;右子树的il是pos+1;右子树的ir是ir
左子树是[ il,pos-1]的长度,所以pr=pl+1+pos-1-li=pl+pos-li;
右子树是[pos+1,ir]的长度,所以pl=左子树的pr+1=pl+pos-li+1
=pr-(ir-pos-1)=pr-ir+pos+1
代码 Runtime 30 ms Beats 34.48% Memory 25.9 MB Beats 73.83%
class Solution {
public:TreeNode*build(vector<int>& preorder, vector<int>& inorder,int pl,int pr,int il,int ir){if(il>ir)return NULL;TreeNode *root=new TreeNode(preorder[pl]);int pos;//为了找到il和irfor(int i=il;i<=ir;i++)if(inorder[i]==preorder[pl]){pos=i;break;}root->left=build(preorder,inorder,pl+1,pl+pos-il,il,pos-1);root->right=build(preorder,inorder,pr-ir+pos+1,pr,pos+1,ir);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {int n=preorder.size()-1;TreeNode *root=NULL;return build(preorder,inorder,0,n,0,n);}
};
标答优化 map
题目中有这样一条preorder
and inorder
consist of unique values.
所以可以用map来减少中序查找的时间消耗
传递参数的时候可以省略前序序号的传递,或者说只需要一个pl就可以了,传递的时候函数参数为il和ir
代码 Runtime13 ms Beats 79.95% Memory26.3 MB Beats 58.43%
class Solution {
public:unordered_map<int,int>mp;int pre=0;TreeNode* build(vector<int>& preorder,int l,int r){if (l>r) return NULL;int mid=preorder[pre++];TreeNode * root=new TreeNode(mid);int pos=mp[mid];root->left=build(preorder,l,pos-1);root->right=build(preorder,pos+1,r);return root;}TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {int n=inorder.size()-1;for(int i=0;i<=n;i++) mp[inorder[i]]=i;//中序序列的这个数字排在第几个序号return build(preorder,0,n);}
};
114. Flatten Binary Tree to Linked List
题意:
我的思路
先序索引,但我不会写;看了答案后至少有一点是对的,就是先递归,两个递归后在做事情
标答 递归
分为4种情况:1只有左边的,2只有右边的,3都没有的,4都有的
首先是第一种情况,假设现在root是1这个结点【56当它不存在】,234按照道理都已经建好了;只需要root->right=root->left; root->left=NULL;就可以了
第二种情况,假设节点是5,6按道理都建好了,其实5放着不动就好了
第三种情况就先不管
第四种情况,假设节点是2,34按道理都建好了,首先要把右子树空出来,right=root->right; root->right=root->left;root->left=NULL; 这时候还需要处理原来在右子树上的结点。因为原先左子树上的都是处理好的链表,所以只要找到原先左子树上的最后一个节点,把这最后一个节点连上去就可以了
代码 递归 Runtime 5 ms Beats 59.24% Memory 12.7 MB Beats 30.44%
class Solution {
public:void flatten(TreeNode* root) {if(root==NULL)return;flatten(root->left);flatten(root->right);if(root->left){TreeNode* right=root->right;root->right=root->left;root->left=NULL;while(root->right)root=root->right;root->right=right;}}
};
标答 循环
首先如果root是空的话就返回;如果当前指针有左指针,先将pre指向左指针指向的位置;pre来到左指正的最右边,左指针的最右边指向当前指针的右边,再把原来右指针指向左指针的位置,左指针置为空;如下图所示,总之就是一点一点挪过去
代码 Runtime 3 ms Beats 88.18% Memory12.7 MB Beats 61.31%
class Solution {
public:void flatten(TreeNode* root) {if(root == NULL) return;TreeNode *curr = root;while(curr){if(curr->left){TreeNode *pre = curr->left;while(pre->right) pre = pre->right;pre->right = curr->right;curr->right = curr->left;curr->left = NULL;}curr = curr->right;}}
};
标答 优化
注意这里是先递归右边,相当于(我一开始想的)先到右边的尽头,之后那前一个来接上的想法【最后没写出来】
注意这里递归的顺序,学着点!!
先递归到6,这时6的右指针是prev也就是空,左指针是空,prev是6
接下来是5,5的右指针是prev也就是6,左指针是空,prev是5
接下来是4,4的右指针是prev也就是5,左指针是空,prev是4
接下来是3,3的右指针是prev也就是4,左指针是空,prev是3
……
于是就完成了
代码 Runtime 0 ms Beats 100% Memory12.7 MB Beats 30.44%
class Solution {
public:
TreeNode* prev = NULL; void flatten(TreeNode* root) {if(!root) return;flatten(root->right);flatten(root->left);root->right = prev;root->left = NULL;prev = root;}
};
118. Pascal's Triangle
题意:
我的思路
用动态规划(?),第x层有x个数字,dp[x][0]=1,dp[x][x-1]=0,dp[x][i]=dp[x-1][i-1]+dp[x-1][i]
代码 Runtime 4 ms Beats 29.4% Memory 6.9 MB Beats 18.4%
class Solution {
public:vector<vector<int>> generate(int num) {if(num==1)return {{1}};if(num==2)return {{1},{1,1}};vector<vector<int>> ans={{1},{1,1}};int temp=0;for(int x=3;x<=num;x++){//一共num层vector<int> sol;sol.push_back(1);for(int i=1;i<x-1;i++){temp=ans[x-2][i-1]+ans[x-2][i];sol.push_back(temp);}sol.push_back(1);ans.push_back(sol);}return ans;}
};
标答 优化
简而言之,就是用一维数组代替了二维数组,实现了相加提速
代码 Runtime 0 ms Beats 100% Memory 6.7 MB Beats 78.55%
class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>>ans;ans.push_back({1});for(int i=0;i<numRows-1;i++){vector<int> tem=ans.back();//{1}vector<int> v(tem.size()+1);//开空间for(int i=0;i<=tem.size();i++){if(i==0){v[i]=tem[0];continue;//1}if(i==tem.size())//1v[i]=tem[tem.size()-1];elsev[i]=tem[i-1]+tem[i];}ans.push_back(v);}return ans;}
};
121. Best Time to Buy and Sell Stock
题意:给出每天袜子的价格,只能选一天买袜子,只能选一天卖袜子,求利润最大
我的思路
用vector或者deque模拟单调栈?当要弹出一个大的数字的时候,就求一下栈尾和栈顶的的差,或者双指针也可以
代码 双指针 Runtime 66 ms Beats 99.76% Memory 93.4 MB Beats 11.73%
不加取消同步在66.7%左右,感觉都差不多,都是找个最小的,然后当前的减去现在最小的,最后在"当前的"里面找最大的
class Solution {
public:int maxProfit(vector<int>& p) {int l=0,r=0,n=p.size();int profit=0;for(r=1;r<n;r++){profit=max(profit,p[r-1]-p[l]);if(p[r]<p[l])l=r;}profit=max(profit,p[r-1]-p[l]);return profit;}
};
124. Binary Tree Maximum Path Sum
题意:树上路径和最大
我的思路
学过,好像有两种做法?一种dp一种dfs大概?
下面是用dfs做的:
那就每个结点都遍历一遍,每个节点的数字就是 sum=左边的和加上右边的和,ans=max(ans, sum);返回的时候返回两条子树和最大的那个,如果和是负的那就返回0
代码 Runtime 17 ms Beats 85.76% Memory27.7 MB Beats 52.24%
class Solution {
public:int ans=-9999;int maxP(TreeNode* root) {int l=0;int r=0;int sum=0;if(root->left!=NULL) l=maxP(root->left);if(root->right!=NULL) r=maxP(root->right);sum=l+r+(root->val);ans=max(ans,sum);return max(max(l,r)+(root->val),0);}int maxPathSum(TreeNode* root) {maxP(root);return ans;}
};
128. Longest Consecutive Sequence
题意:输出最长连续序列的长度
我的思路
初步设想快排+遍历,但是他会有相同的数字;那就用map
代码 Runtime 147 ms Beats 60.73% Memory 68.8 MB Beats 26.14%
class Solution {
public:int longestConsecutive(vector<int>& nums) {ios::sync_with_stdio(false);cin.tie(0);if(nums.size()==0)return 0;map<long long,int>mp;int maxx=1;long long pre=-9999999999;int cnt=0;for(int i=0;i<nums.size();i++)mp[nums[i]]++;for(auto q:mp){if(cnt!=0&&q.first!=pre+1){maxx=max(maxx,cnt); cnt=0;}pre=q.first;cnt++;}maxx=max(maxx,cnt);return maxx;}
};
标答 排序
我的2n比不上nlogn,好吧;其实和初步设想差不多,就是相同的数字的时候不加就可以了
首先先排序,之后
代码 Runtime 35 ms Beats 99.79% Memory43.2 MB Beats 99.65%
class Solution {
public:int longestConsecutive(vector<int>& nums){ios_base::sync_with_stdio(false);cin.tie(NULL);int n=nums.size();if(n==0)return 0;int maxx=0;int cnt=1;sort(nums.begin(),nums.end());for(int i=1;i<n;i++){if(nums[i]-nums[i-1]==1)cnt++;else if(nums[i]!=nums[i-1]){maxx=max(maxx,cnt);cnt=1;}}maxx=max(maxx,cnt);return maxx;}
};
131. Palindrome Partitioning
题意:给一个字符串,返回所有是回文串的子串
我的思路
初步设想的遍历+回文串判断,但是这个返回的答案很dfs
那就试试用dfs做吧;不会做不会做
但是瞄了一眼标答 还是自己写了
代码 Runtime 75 ms Beats 94.39% Memory 49.3 MB Beats 82.17%
class Solution {
public:bool jud(string s){int n=s.size();for(int i=0;i<n/2;i++){if(s[i]!=s[n-i-1])return 0;}return 1;}void dfs(vector<vector<string>> &result,vector<string> &sol,int id,string &s){if(id==s.size()){result.push_back(sol);return;}for(int len=1;len+id<=s.size();len++){string temp=s.substr(id,len);if(jud(temp)){sol.push_back(temp);dfs(result,sol,id+len,s);sol.pop_back();}}}vector<vector<string>> partition(string s) {if(s.size()==0)return {{}};vector<vector<string>> result;vector<string> sol;dfs(result,sol,0,s);return result;}
};
136. Single Number
题意:给一个数组,找出只出现一次的数字
我的思路
用map存一遍,在找一遍
代码 Runtime17 ms Beats 59.59% Memory20.1 MB Beats 9.40%
class Solution {
public:int singleNumber(vector<int>& nums) {ios::sync_with_stdio(false);cin.tie(0);unordered_map<int,int>mp;for(int i=0;i<nums.size();i++)mp[nums[i]]++;for(auto q:mp)if(q.second==1)return q.first;return 0;}
};
标答 位运算
首先是异或算法的一些规律
从上图就可以看到,如果是两个一样的数字,那么它就会变成0;如果是不一样的数字,那么它就会留下来
代码 Runtime11 ms Beats 92.56% Memory 17 MB Beats 33.22%
class Solution {
public:int singleNumber(vector<int>& nums) {int x = 0;for(int i=0; i<nums.size(); i++)x=x^nums[i];return x;}
};
138. Copy List with Random Pointer
题意:复制一个一摸一样的链表
我的思路
只会链表的顺序复制,如果是随机的,那要有个map,左边是原地址,右边是现地址;
代码 Runtime 3 ms Beats 97.9% Memory11.3 MB Beats 32.3%
class Solution {
public:Node* copyRandomList(Node* head) {unordered_map<Node*,Node*>mp;if(head==NULL)return NULL;Node* root=new Node(head->val);Node* q=root;Node* cr=NULL;mp[head]=root;for(Node* p=head->next;p!=NULL;p=p->next){cr=new Node(p->val);q->next=cr;q=q->next;mp[p]=cr;}q=root;for(Node* p=head;p!=NULL;p=p->next){Node* qv=p->random;q->random=mp[qv];q=q->next;}return root;}
};
标答 不用map的做法
如果head是空,返回空;
copy_merge函数复制顺序的链表,其中curr是原链表的当前节点,next是原链表的下一个节点,copy是专门创造新结点的指针,curr指向新生的结点,copy指向原来下一个节点;其返回结果如图所示
handle_random函数如下如所示,简单来说就是复制的结点就是原节点的next,所以容易能找到;这样就可以原来的节点的random指向哪个,复制的节点就指向那个节点的next
最后detach函数把复制的结点全部都串在一起,原来的结点也要指回原来的结点
代码 Runtime 7 ms Beats 73.26% Memory 11.2 MB Beats 87.73%
class Solution {
public:void copy_merge(Node* head){Node* curr=head; Node* next=head->next;while(curr!=NULL){Node* copy=new Node(curr->val);curr->next=copy; copy->next=next;curr=next;if(next!=NULL) next=next->next;}}void handle_random(Node* head){Node* curr=head;while(curr!=NULL){if(curr->random!=NULL) curr->next->random=curr->random->next;curr=curr->next->next;}}Node* detach(Node* head){Node* curr=head; Node* dummy=new Node(-1); Node* tail=dummy;while(curr!=NULL){tail->next=curr->next; tail=tail->next;curr->next=tail->next; curr=curr->next;}return dummy->next;}Node* copyRandomList(Node* head) {if(head==NULL) return head;copy_merge(head); handle_random(head);return detach(head);}
};
139. Word Break
题意:给你字典,问能不能用字典里的词拼接成字符串s
我的思路
用dfs吗?但是dfs先分成所有可能性,再用字典判断也太费时间了吧
不会做,看看答案