重刷剑指offer
数组中重复的数字
题目描述
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重
复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
思路:
数组大小为n,数字范围为0~n-1,也就是说如果数组不重复,则排序后每个数组i上的元素就应该是i
为此,我们可以模拟这个排序的过程,如果i位置上的元素不为i,则把它与nums[i]位置的元素进行交换,这相当于把nums[i]放到他该去的地方。如果nums[i]位置的元素已经是i了,则这刚好就是重复的数字;否则将交换到i位置上的数字继续这个过程,如果交换过来的数等于i,则说明这个数放在了他应该放的地方,继续处理i+1上的数,如果仍然不等,则将这个换来的数放到他应该放的地方....最后,对于i位置来说,要么找到了值为i的元素,要么找到了重复的元素,是不可能出现无限循环的,因为无限循环要求换来的数字与i位置的数字相等,但这时候已经判定重复并跳出返回了。
class Solution { public: // Parameters: // numbers: an array of integers // length: the length of array numbers // duplication: (Output) the duplicated number in the array number // Return value: true if the input is valid, and there are some duplications in the array number // otherwise false bool duplicate(int numbers[], int length, int* duplication) { if(length<=1) return false; int p1=0; while(p1<length) { if(numbers[p1]!=p1) { while(numbers[p1]!=p1) { int right=numbers[numbers[p1]]; if(numbers[p1]==right) { *duplication=right; return true; } swap(numbers[numbers[p1]],numbers[p1]); } } p1++; } return false; } void swap(int& a,int& b) { int tmp=a; a=b; b=tmp; } };
二维数组中的查找
题目描述
class Solution { public: bool Find(int target, vector<vector<int> > array) { auto& nums=array; if(nums.empty()||nums[0].empty()) return false; int row=nums.size()-1; int col=0; while(row>=0&&col<nums[row].size()) { if(nums[row][col]==target) return true; else if(nums[row][col]<target) col++; else row--; } return false; } };
替换空格
题目描述
int pLast=len+count*2;
int pCur=len;
而不是
int pLast=len+count*2-1;
int pCur=len-1;
虽然这一种也能实现,但少了个'\0',需要自己在补一个。
class Solution { public: void replaceSpace(char *str,int length) { int len=length; int count=0; for(int i=0;i<len;i++) { if(str[i]==' ') count++; } int pLast=len+count*2; int pCur=len; while(pCur>=0&&pLast>pCur) { if(str[pCur]!=' ') { str[pLast]=str[pCur]; pLast--; } else { str[pLast--]='0'; str[pLast--]='2'; str[pLast--]='%'; } pCur--; } return ; } };
从尾到头打印链表
题目描述
class Solution { public: vector<int> printListFromTailToHead(ListNode* head) { vector<int> ans; if(!head) return ans; Core(ans,head); return ans; } void Core(vector<int>& in,ListNode* head) { if(!head) return; Core(in,head->next); in.push_back(head->val); } };
重建二叉树★★★
思路很清晰的题,但容易出错,多写几次注意下细节,特别是传参长度的处理。
题目描述
class Solution { public: TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) { if(pre.empty()||pre.size()!=vin.size()) return NULL; return reConstructCore(pre,vin,0,0,pre.size()); } TreeNode* reConstructCore(vector<int>& pre,vector<int>& vin,int pstart,int vstart,int len) { if(len<=0) return NULL; int tmp=pre[pstart]; int pos=0; for(;pos<len&&vin[pos+vstart]!=tmp;pos++); pos+=vstart; int left=pos-vstart; int right=len-left-1; TreeNode* root=new TreeNode(tmp); root->left=reConstructCore(pre,vin,pstart+1,vstart,left); root->right=reConstructCore(pre,vin,pstart+left+1,pos+1,right); return root; } };
二叉树的下一个结点★★★
要考虑的情况很多,值得好好看看,体味下二叉树的结构
题目描述
class Solution { public: TreeLinkNode* GetNext(TreeLinkNode* pNode) { if(!pNode) return NULL; return GetNextCore(pNode); } TreeLinkNode* GetNextCore(TreeLinkNode* node) { if(!node->next) { auto it=node->right; if(!it) return NULL; while(it->left) it=it->left; return it; } auto pLast=node->next; if(pLast->left==node) { if(node->right) { auto right=node->right; while(right->left) right=right->left; return right; } else return pLast; } else if(pLast->right==node) { if(node->right) { auto right=node->right; while(right->left) right=right->left; return right; } else { while(pLast->next&&pLast->next->right==pLast) pLast=pLast->next; if(pLast->next==NULL) return NULL; else return pLast->next; } } else return NULL; } };
这个分类讨论太多了,其实完全可以简化:
1).如果该节点存在右子树,则应该遍历右子树中的最左节点
2).如果不存在,则要找到某个节点,该节点是其父的左子节点(包括目前的这个节点)
这样就简化很多了
class Solution { public: TreeLinkNode* GetNext(TreeLinkNode* pNode) { if(!pNode) return NULL; auto right=pNode->right; if(right) { while(right->left) right=right->left; return right; } else { while(pNode->next&&pNode->next->right==pNode) pNode=pNode->next; if(pNode->next) return pNode->next; else return NULL; } } };
用两个栈实现队列
题目描述
思路:
栈的特点是先入后出,队列的特点是先入先出
现在给了两个栈,其实可以想象成这样一个情景:
Tail和Head相当于两个水管,水从tail中流入,从Head中流出,这样实际上就相当于实现了队列
我们在Tail中灌水,就相当于push进数,然后pop提出最先灌进去的数,则从Head中读出。
如果Head现在是空,也就是说没有元素,则把Tail里的数全部转到Head中,当然顺序要变化,这也就相当于上图里用个管子把两个容器相连,然后把Tail底部的水抽到Head中
每次push都push到Tail中。
class Solution { public: void push(int node) { stack2.push(node); } int pop() { if(!stack1.empty()) { auto ans=stack1.top(); stack1.pop(); return ans; } else { if(stack2.empty()) return INT_MIN; while(!stack2.empty()) { stack1.push(stack2.top()); stack2.pop(); } auto ans=stack1.top(); stack1.pop(); return ans; } } private: stack<int> stack1;//head stack<int> stack2;//tail };
用两个队列实现栈
两个队列:
某个队列pop到只剩一个元素,其他的元素PUSH到另一个队列。
一个队列:
push进后,将新元素前面的元素重新pop并push进队列。
矩形覆盖
题目描述
我们可以用 2*1 的小矩形横着或者竖着去覆盖更大的矩形。请问用 n 个 2*1 的小矩形无重叠地覆盖一个 2*n 的大矩形,总共有多少种方法?
思路:
矩形可以横着摆与竖着摆,竖着摆时只能组成2x1;而横着摆可以用2个组成一个2X2
因此2*n的矩形可以来自于:2*(n-1)的矩形加一个2X1,或来自于2*(n-2)的矩形加两个横着摆的2x1
class Solution { public: int rectCover(int number) { if(number<=0) return 0; if(number<2) return number; vector<int> dp(number,0); dp[0]=1; dp[1]=2; for(int i=2;i<dp.size();i++) dp[i]=dp[i-1]+dp[i-2]; return dp.back(); } };
旋转数组的最小数字★★★★★
题目描述
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
class Solution { public: int minNumberInRotateArray(vector<int> rotateArray) { auto& nums=rotateArray; if(nums.size()==0) return 0; int l=0;int h=nums.size()-1; int mid=(l+h)/2; while(l<h) { mid=(l+h)/2; if(nums[mid]>nums[h]) l=mid+1; else if(nums[mid]<nums[h]) h=mid; else h--; } return nums[h]; } };
剪绳子★★★
题目描述
把一根绳子剪成多段,并且使得每段的长度乘积最大。
思路:
切割绳子时,可以将它看做切成两半,然后每半部分再决定切不切
比如10,可以先切成4,6,由于已经切了一次了,因此4和6均可以选择继续切或者不切,这样就有四种情况,取其中最大值即可
class Solution { public: int integerBreak(int n) { vector<int> dp(n+1,0); dp[0]=1; dp[1]=1; for(int i=2;i<dp.size();i++) { for(int j=1;j<=i-j;j++) dp[i]=max(dp[i],max(dp[j],j)*max((i-j),dp[i-j])); } return dp.back(); } };
二进制中 1 的个数
题目描述
class Solution { public: int NumberOf1(int n) { int num=sizeof(n)*8; int flag=1; int count=0; while(flag) { if((flag&n)==flag) count++; flag=flag<<1; } return count; } };
2).n&(n-1)会使n最右边一个1变为0
这是因为,当n最右边的数为1时,与n-1相与可以让n的最后一位从1变为0
如果n最右边一位为0,则n-1会使n最优边1个1变为0,而是这个1右侧的0全变为1,再与n相与,则那个1及它右侧全变为0.
这样n&(n-1)将不断使右边的1变为0,直到n==0;
class Solution { public: int NumberOf1(int n) { int count=0; while(n) { count++; n&=n-1; } return count; } };
数值的整数次方★★★
题目描述
给定一个 double 类型的浮点数 base 和 int 类型的整数 exponent,求 base 的 exponent 次方。
思路:
如果每次只乘base则速度太慢,因此考虑每次进行平方,如果剩余的指数不足以平方,则递归剩余的指数,重复这个过程。
注意exponent为负数的情况,要先判断,最后用1.0去除
class Solution { public: double Power(double base, int exponent) { if(!base) return 0; if(!exponent) return 1; bool flag=false; if(exponent<0) flag=true;//判断exponent为负数的情况 exponent=abs(exponent); auto ans=PowerCore(base,exponent,base); if(flag) ans=1.0/ans; return ans; } double PowerCore(double num,int exponent,double base) { if(!exponent) return 1; if(exponent==1) return exponent*base; int count=2; while(count<=exponent) { num*=num; exponent-=count; count*=2; } return num*PowerCore(num,exponent,base); } };
打印从 1 到最大的 n 位数
题目描述
输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数即999。
思路:
模拟加法过程,当最低位满足10进1时,通过while一直进位。
pCur用于跟踪最高位。
class Solution { public: void display(int n) { if(!n) return; if(n==1) { for(int i=0;i<10;i++) cout<<i<<endl; return; } string str(n+1,'0'); int pCur=str.size()-1; while(str[0]!='1') { cout<<str.data()+pCur<<endl; if(str.back()=='9') { int p=str.size()-1; while(str[p]=='9') { str[p]='0'; p--; } if(pCur-p==1) pCur=p; str[p]+=1; } else str.back()+=1; } return; } };
删除链表中重复的结点★★★
题目描述
class Solution { public: ListNode* deleteDuplication(ListNode* pHead) { if(!pHead) return NULL; if(!pHead->next) return pHead; ListNode* head=new ListNode(100); head->next=pHead; ListNode* pCur=head; ListNode* pre=head->next; while(pre) { ListNode* next=pre->next; while(next&&next->val==pre->val) next=next->next; if(pre->next==next) { pCur=pre; pre=next; } else { pCur->next=next; pre=next; } } return head->next; } };
正则表达式匹配★★★★★
题目描述
请实现一个函数用来匹配包括 '.' 和 '*' 的正则表达式。模式中的字符 '.' 表示任意一个字符,而 '*' 表示它前面的字符可以出现任意次(包含 0 次)。
在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串 "aaa" 与模式 "a.a" 和 "ab*ac*a" 匹配,但是与"aa.a" 和 "ab*a" 均不匹配。
思路:
dp[i][j]表示主串0~i与模式串0~j是否匹配。
状态转移方程为:
1).s[i]==p[j]||[j]=='.':dp[i][j]=dp[i-1][j-1],即只要前i-1与前j-1相等,则匹配
2).s[i]!=p[j]:
a).p[j]!='*':此时p[j]与s[i]完全不等,则dp[i][j]=false;
b).p[j]='*':此时*可以使前面的字母为0个,1个或多个
当p[j-1]!=s[i]时,此时只能使他为0:dp[i][j]=dp[i][j-1];
当p[j-1]==s[i]时,此时可以使前面的字母为0个,1个或多个
为0个时:dp[i][j]=dp[i][j-1]
为1个时:dp[i][j]=dp[i-1][j-1]
为多个时:此时拿出一个前面的字母与s[i]匹配,因此主串还剩i-1个,但由于p[j]='*'且此时是会产生多个前面字母的情况,因此即使已经分出一个了,但还可能分出很多个,因此还是拿s的前i-1个与p的前j个来匹配,因为p[j]='*',相当于他可以无限的拿出来。
举个例子:
s:###bbb
p:###b*
现在*与b不等,我们令*产生多个b的情况,此时先产生一个b与s的b消除:
s:###bb
p:###b*
而此时p串仍然为###b*,这时在令*产生一个b:
s:###b
p:###b*
此时再令*使前面的b为0个:
s:###
p:###
这样就匹配了
相当于说*产生多个p让他分步一步步来,而不是一下生产2个b
因此此时dp[i][j]=dp[i-1][j]
也就是说先拿出一个b与主串的消掉,然后将问题转换为dp[i-1][j],如果剩下的i-1还有b,但这已经是dp[i-1][j]的问题了。
另外注意初始状态:
dp[0][i],当p[i]='*'时,此时应该与dp[0][i-2]一致,也就是隐去i前面的一个
比如
s:""
p".*"
此时*将.隐去,而相当于dp[0][0]=true
class Solution { public: bool match(char* str, char* pattern) { string str1(str); string str2(pattern); vector<vector<bool>> dp(str1.size()+1,vector<bool>(str2.size()+1,false)); dp[0][0]=true; if(str2[0]=='*') return false; for(int i=0;i<str2.size();i++) { if(str2[i]=='*') dp[0][i+1]=dp[0][i-1]; } for(int i=1;i<dp.size();i++) { for(int j=1;j<dp[i].size();j++) { if((str1[i-1]==str2[j-1])||(str2[j-1]=='.')) dp[i][j]=dp[i-1][j-1]; else if(str2[j-1]=='*') { if(j==1) return false; if(str2[j-2]==str1[i-1]||str2[j-2]=='.') dp[i][j]=dp[i][j-2]||dp[i-1][j-1]||dp[i-1][j]; else dp[i][j]=dp[i][j-2]; } } } return dp.back().back(); } };
表示数值的字符串
题目描述
思路:
以e/E为分界线将整个数分为两部分:
左部分的数字部分可以为整数或者小数,+-只能出现在0,只能有一个'.'
右部分的数字部分只能是整数,+-只能出现在e后面一个位置,不能有'.'
class Solution { public: bool isNumeric(char* string) { char * str=string; int p1=0; while(p1<strlen(str)&&str[p1]!='e'&&str[p1]!='E') p1++; return isLeft(str,p1-1)&&isRight(str,p1+1); } bool isLeft(char* str,int end) { if(end<0) return false; int pointnum=0; for(int i=0;i<=end;i++) { if((str[i]=='+'||str[i]=='-')) { if(i!=0) return false; continue; } if(str[i]=='.') { pointnum++; if(pointnum==2) return false; continue; } if(str[i]<'0'||str[i]>'9') return false; } return true; } bool isRight(char* str,int start) { if(start==strlen(str)) return false; if(start>strlen(str)) return true; int len=strlen(str); for(int i=start;i<len;i++) { if((str[i]=='+'||str[i]=='-')) { if(i!=start) return false; continue; } if(str[i]<'0'||str[i]>'9') return false; } return true; } };
调整数组顺序使奇数位于偶数前面★★★
题目描述
class Solution { public: void reOrderArray(vector<int> &array) { if(array.empty()) return; vector<int>& nums=array; for(int i=0;i<nums.size();i++) { int target=nums[i]; if(target&0x1) { int j=i; while(j>0&&!(array[j-1]&0x1))//当j==0或j前面是奇数时停止 { array[j]=array[j-1]; j--; } array[j]=target; } } return; } };
链表中倒数第k个结点
题目描述
class Solution { public: ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) { ListNode* pNext=pListHead; if(k<=0||!pListHead) return NULL; while(pNext&&k) { pNext=pNext->next; k--; } if(k!=0) return NULL; ListNode* pCur=pListHead; while(pNext) { pCur=pCur->next; pNext=pNext->next; } return pCur; } };
链表中环的入口结点
题目描述
class Solution { public: ListNode* EntryNodeOfLoop(ListNode* pHead) { if(!pHead) return NULL; ListNode* p1=pHead; ListNode* p2=pHead; while(p2&&p2->next) { p1=p1->next; p2=p2->next->next; if(p1==p2) break; } if(!p2||!p2->next) return NULL; p1=pHead; auto tmp=p2; do{ tmp=tmp->next; p1=p1->next; }while(tmp!=p2); auto pCur=pHead; while(pCur!=p1) { pCur=pCur->next; p1=p1->next; } return pCur; } };
反转链表
题目描述
头插法: class Solution { public: ListNode* ReverseList(ListNode* pHead) { if(!pHead) return NULL; ListNode* pCur=new ListNode(250); while(pHead) { auto tmp=pHead->next; pHead->next=pCur->next; pCur->next=pHead; pHead=tmp; } return pCur->next; } }; 三指针: class Solution { public: ListNode* ReverseList(ListNode* pHead) { if(!pHead) return NULL; if(!pHead->next) return pHead; ListNode* pre=NULL; ListNode* pCur=pHead; ListNode* pNext=pHead->next; while(pNext) { pNext=pCur->next; pCur->next=pre; pre=pCur; pCur=pNext; } return pre; } };
合并两个排序的链表
题目描述
class Solution { public: ListNode* Merge(ListNode* pHead1, ListNode* pHead2) { if(!pHead1) return pHead2; if(!pHead2) return pHead1; ListNode* pHead=new ListNode(-1); ListNode* pCur=pHead; while(pHead1&&pHead2) { if(pHead1->val<pHead2->val) { auto tmp=pHead1->next; pCur->next=pHead1; pHead1->next=NULL; pHead1=tmp; } else { auto tmp=pHead2->next; pCur->next=pHead2; pHead2->next=NULL; pHead2=tmp; } pCur=pCur->next; } if(pHead1) pCur->next=pHead1; if(pHead2) pCur->next=pHead2; return pHead->next; } };
树的子结构★★★
题目描述
class Solution { public: bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) { if(!pRoot2||!pRoot1) return false; return HasSubtreeCore(pRoot1,pRoot2); } bool HasSubtreeCore(TreeNode* p1,TreeNode* p2) { if(!p1&&p2) return false; if(!p2) return true; if(p1->val==p2->val &&HasSubtreeCore(p1->left,p2->left)//根相等且左右子树都是子结构 &&HasSubtreeCore(p1->right,p2->right)) return true; return HasSubtreeCore(p1->left,p2)||HasSubtreeCore(p1->right,p2); } };
二叉树的镜像
题目描述
class Solution { public: void Mirror(TreeNode *pRoot) { if(!pRoot) return; MirrorCore(pRoot); } void MirrorCore(TreeNode* root) { if(!root) return; MirrorCore(root->left); MirrorCore(root->right); auto tmp=root->right; root->right=root->left; root->left=tmp; return; } };
对称的二叉树★★★
题目描述
class Solution { public: bool isSymmetrical(TreeNode* pRoot) { if(!pRoot) return true; return isSymCore(pRoot->left,pRoot->right); } bool isSymCore(TreeNode* p1,TreeNode* p2) { if(!p1&&!p2) return true; if(p1&&!p2||p2&&!p1) return false; if(p1->val!=p2->val) return false; return isSymCore(p1->left,p2->right)&&isSymCore(p1->right,p2->left); } };
顺时针打印矩阵★★★★★
题目描述
class Solution { public: vector<int> printMatrix(vector<vector<int> > matrix) { if(matrix.empty()||matrix[0].empty()) return vector<int> (); int circle=0; int r_num=matrix.size(); int c_num=matrix[0].size(); vector<int> ans; while(r_num>0&&c_num>0) { if(r_num==1) { for(int i=0;i<c_num;i++) ans.push_back(matrix[circle][circle+i]); } else if(c_num==1) { for(int i=0;i<r_num;i++) ans.push_back(matrix[circle+i][circle]); } else { for(int i=0;i<c_num-1;i++) ans.push_back(matrix[circle][circle+i]); for(int i=0;i<r_num-1;i++) ans.push_back(matrix[circle+i][circle+c_num-1]); for(int i=0;i<c_num-1;i++) ans.push_back(matrix[circle+r_num-1][circle+c_num-1-i]); for(int i=0;i<r_num-1;i++) ans.push_back(matrix[circle+r_num-1-i][circle]); } circle++; r_num-=2; c_num-=2; } return ans; } };
包含min函数的栈★★★
题目描述
class Solution { public: void push(int value) { nums.push_back(value); if(nums.size()==1) { aux.push(0); return; } auto tmp=aux.top(); if(value<nums[tmp]) aux.push(nums.size()-1); } void pop() { if(nums.empty()) return; auto idx=nums.size()-1; nums.pop_back(); if(idx==aux.top()) aux.pop(); } int top() { if(nums.empty()) return INT_MIN; return nums.back(); } int min() { if(nums.empty()) return INT_MIN; return nums[aux.top()]; } private: vector<int> nums; stack<int> aux; };
栈的压入、弹出序列★★
题目描述
class Solution { public: bool IsPopOrder(vector<int> pushV,vector<int> popV) { if(pushV.size()!=popV.size()) return false; if(pushV.empty()) return true; int p1=0;int p2=0; stack<int> aux; while(p2<popV.size()) { while(p1<popV.size()&&(aux.empty()||aux.top()!=popV[p2]))//1 2 3 4 5 ;4 5 3 2 1 { aux.push(pushV[p1]); p1++; } if(p1>=pushV.size()&&aux.top()!=popV[p2]) { return false; } aux.pop(); p2++; } if(aux.empty()) return true; else return false; } };
从上往下打印二叉树
题目描述
思路:
层次遍历。。。
class Solution { public: vector<int> PrintFromTopToBottom(TreeNode* root) { if(!root) return vector<int>(); queue<TreeNode*> aux; aux.push(root); vector<int> ans; while(!aux.empty()) { ans.push_back(aux.front()->val); auto tmp=aux.front(); aux.pop(); if(tmp->left) aux.push(tmp->left); if(tmp->right) aux.push(tmp->right); } return ans; } };
把二叉树打印成多行
题目描述
class Solution { public: vector<vector<int> > Print(TreeNode* pRoot) { if(!pRoot) return vector<vector<int>>(); queue<TreeNode*> aux; int count=1; aux.push(pRoot); vector<vector<int>> ans; while(!aux.empty()) { int tmp=0; vector<int> in; while(count) { in.push_back(aux.front()->val); if(aux.front()->left) { aux.push(aux.front()->left); tmp++; } if(aux.front()->right) { aux.push(aux.front()->right); tmp++; } aux.pop(); count--; } count=tmp; ans.push_back(in); } return ans; } };
按之字形顺序打印二叉树★★★★
题目描述
class Solution { public: vector<vector<int> > Print(TreeNode* pRoot) { vector<vector<int>> ans; if(!pRoot) return ans; int count=1; queue<TreeNode*> aux; stack<TreeNode*> carry; aux.push(pRoot); int flag=1; while(!aux.empty()) { int tmp=0; vector<int> val; while(count) { val.push_back(aux.front()->val); auto first=(flag==1)?aux.front()->left:aux.front()->right; auto second=(flag==1)?aux.front()->right:aux.front()->left; if(first) { carry.push(first); tmp++; } if(second) { carry.push(second); tmp++; } count--; aux.pop(); } while(!carry.empty()) { aux.push(carry.top()); carry.pop(); } flag=-flag; count=tmp; ans.push_back(val); } return ans; } };
二叉搜索树的后序遍历序列★★★★
题目描述
class Solution { public: bool VerifySquenceOfBST(vector<int> sequence) { if(sequence.empty()) return false; return VerifyBSTCore(sequence,0,sequence.size()); } bool VerifyBSTCore(vector<int>& nums,int start,int len) { if(len<=1) return true; int val=nums[start+len-1]; int i=0; for(;i<len&&nums[start+i]<val;i++); int left=i; for(;i<len&&nums[start+i]>=val;i++); if(i!=len) return false; return VerifyBSTCore(nums,start,left)&&VerifyBSTCore(nums,left,len-left-1); } };
二叉树中和为某一值的路径
题目描述
class Solution { public: vector<vector<int> > FindPath(TreeNode* root,int expectNumber) { vector<vector<int>> ans; if(!root) return ans; vector<int> tmp; FindPathCore(ans,tmp,root,expectNumber); sort(ans.begin(),ans.end(),cmp); return ans; } private: static bool cmp(vector<int>& pre,vector<int>& next)//类中使用自定义排序cmp要使用静态方法 { return pre.size()>next.size(); } void FindPathCore(vector<vector<int>>& ans,vector<int>& tmp,TreeNode* node,int num) { if(!node->left&&!node->right) { if(!(num-node->val)) { tmp.push_back(node->val); ans.push_back(tmp); tmp.pop_back(); } return; } tmp.push_back(node->val); if(node->left) FindPathCore(ans,tmp,node->left,num-node->val); if(node->right) FindPathCore(ans,tmp,node->right,num-node->val); tmp.pop_back(); return; } };
复杂链表的复制★★★
题目描述
class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { if(!pHead) return NULL; //firsst RandomListNode* pCur=pHead; RandomListNode* head=new RandomListNode(1); RandomListNode* p=head; unordered_map<RandomListNode*,RandomListNode*> dict; while(pCur) { RandomListNode* node=new RandomListNode(pCur->label); dict[pCur]=node; p->next=node; p=node; pCur=pCur->next; } pCur=pHead; p=head->next; while(pCur) { if(pCur->random) p->random=dict[pCur->random]; else p->random=0; pCur=pCur->next; p=p->next; } return head->next; } };
2).剑指offer方法:将新建节点插入到原节点右边,这样node->next->random=node->random->next
但这样需要遍历三次链表,第一次将节点插入,第二次构建random,第三次分开链表。
class Solution { public: RandomListNode* Clone(RandomListNode* pHead) { if(!pHead) return NULL; RandomListNode* pCur=pHead; while(pCur) { RandomListNode* node=new RandomListNode(pCur->label); auto tmp=pCur->next; pCur->next=node; node->next=tmp; pCur=tmp; } pCur=pHead; auto ans=pCur->next; while(pCur&&pCur->next) { if(pCur->random) pCur->next->random=pCur->random->next; else if(pCur->next) pCur->next->random=0; pCur=pCur->next->next; } pCur=pHead; RandomListNode* pLast=NULL; while(pCur) { auto node=pCur->next; if(pLast) pLast->next=node; pLast=node; pCur->next=node->next; pCur=pCur->next; } return ans; } };
二叉搜索树与双向链表
题目描述
class Solution { public: TreeNode* Convert(TreeNode* pRootOfTree) { if(!pRootOfTree) return NULL; return ConvertCore(pRootOfTree,NULL); } private: TreeNode* ConvertCore(TreeNode* pCur,TreeNode* pLast) { if(!pCur) return NULL; auto l=ConvertCore(pCur->left,pCur); auto r=ConvertCore(pCur->right,pCur); if(l) l->right=pCur; pCur->left=l; if(r) r->left=pCur; pCur->right=r; if(!pLast) { while(pCur->left) pCur=pCur->left; return pCur; } if(pCur==pLast->left) { while(pCur->right) pCur=pCur->right; return pCur; } else { while(pCur->left) pCur=pCur->left; return pCur; } } };
序列化二叉树★★★
题目描述
class Solution { public: char* Serialize(TreeNode *root) { if(!root) return NULL; char* buf=new char[1000]; char* ans=buf; SerializeCore(root,ans); return buf; } TreeNode* Deserialize(char *str) { if(!str) return NULL; return DeserializeCore(str); } private: TreeNode* DeserializeCore(char*& str) { if(*str==0) return NULL; while(*str==',') str++; if(*str=='#') { str++; return NULL; } int num; char* buf=new char[100]; char* tmp=buf; while(*str!=',') *(buf++)=*(str++); *buf=0; sscanf(tmp,"%d",&num); TreeNode* node=new TreeNode(num); node->left=DeserializeCore(str); node->right=DeserializeCore(str); return node; } void SerializeCore(TreeNode* node,char*& str) { if(!node) { *(str++)=','; *(str++)='#'; *str=0; return; } char* buf=new char[100]; sprintf(buf,"%d",node->val); char* pCur=buf; *(str++)=','; while(*pCur) *(str++)=*(pCur++); *str=0; delete[] buf; SerializeCore(node->left,str); SerializeCore(node->right,str); return; } };
字符串的排列★★★
题目描述
class Solution { public: vector<string> Permutation(string str) { if(str.empty()) return vector<string>(); vector<string> ans; PermutationCore(str,0,ans); sort(ans.begin(),ans.end()); return ans; } private: void PermutationCore(string& str,int pos,vector<string>& ans) { if(pos>=str.size()) { ans.push_back(str); return; } for(int i=pos;i<str.size();i++) { if(i==pos||str[i]!=str[pos]) { swap(str[i],str[pos]); PermutationCore(str,pos+1,ans); swap(str[i],str[pos]); } } return; } };
数组中出现次数超过一半的数字
题目描述
class Solution { public: int MoreThanHalfNum_Solution(vector<int> numbers) { if(numbers.empty()) return 0; if(numbers.size()==1) return numbers.back(); int pos=Partition(numbers,0,numbers.size()-1); int target=numbers.size()/2+1; while(pos!=target) { if(pos<target) pos=Partition(numbers,pos+1,numbers.size()-1); else pos=Partition(numbers,0,pos-1); } int ans=0; for(int i=0;i<numbers.size();i++) { if(numbers[i]==numbers[target]) ans++; } if(ans<target) return 0; else return numbers[target]; } private: int Partition(vector<int>& nums,int start,int end) { if(start>=end) return start; int target=nums[start]; while(start<end) { while(start<end&&target<=nums[end]) end--; swap(nums[start],nums[end]); while(start<end&&target>=nums[end]) start++; swap(nums[start],nums[end]); } return start; } };
40. 最小的 K 个数
题目描述
class Solution { public: vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { if(k<=0) return vector<int>(); if(k>=input.size()) return input; int pos=Partition(input,0,input.size()-1); k--; while(pos!=k) { if(pos<k) pos=Partition(input,pos+1,input.size()-1); else pos=Partition(input,0,pos-1); } vector<int> ans; for(int i=0;i<=k;i++) ans.push_back(input[i]); return ans; } private: int Partition(vector<int>& nums,int start,int end) { if(start>=end) return start; auto target=nums[start]; while(start<end) { while(start<end&&nums[end]>=target) end--; swap(nums[start],nums[end]); while(start<end&&nums[start]<=target) start++; swap(nums[start],nums[end]); } return start; } };
堆排:
class Solution { public: vector<int> GetLeastNumbers_Solution(vector<int> input, int k) { if(k<=0||k>input.size()) return vector<int>(); for(int i=k/2-1;i>=0;i--) HeapAdjust(input,i,k-1); for(int i=k;i<input.size();i++) { if(input[i]<input[0]) { swap(input[i],input[0]); HeapAdjust(input,0,k-1); } } vector<int> ans; for(int i=0;i<k;i++) ans.push_back(input[i]); return ans; } private: void HeapAdjust(vector<int>& nums,int pos,int end) { auto target=nums[pos]; int i=2*pos+1; for(;i<=end;i=2*pos+1) { if(i<end&&nums[i+1]>nums[i]) i++; if(nums[i]<target) break; nums[pos]=nums[i]; pos=i; } nums[pos]=target; return; } };
41 数据流中的中位数★★★★★
题目描述
class Solution { public: void Insert(int num) { if(left.size()==right.size()) { if(right.empty()) { right.push_back(num); return; } if(num>=left[0]) { right.push_back(num); push_heap(right.begin(),right.end(),greater<int>()); return; } pop_heap(left.begin(),left.end(),less<int>()); auto top=left.back(); left.pop_back(); left.push_back(num); push_heap(left.begin(),left.end(),less<int>()); right.push_back(top); push_heap(right.begin(),right.end(),greater<int>()); return; } else if(left.size()<right.size()) { if(num<=right[0]) { left.push_back(num); push_heap(left.begin(),left.end(),less<int>()); return; } else { auto top=right[0]; pop_heap(right.begin(),right.end(),greater<int>()); right.pop_back(); right.push_back(num); push_heap(right.begin(),right.end(),greater<int>()); left.push_back(top); push_heap(left.begin(),left.end(),less<int>()); return; } } } double GetMedian() { int size=left.size()+right.size(); if(!size) return 0; if(size&0x1==1) return right[0]; else return (left[0]+right[0])/2.0; } private: vector<int> left; vector<int> right; };
字符流中第一个不重复的字符★★★
题目描述
class Solution { public: //Insert one char from stringstream Solution() { count=0; } void Insert(char ch) { if(dict.find(ch)!=dict.end()) dict[ch]=-1; else dict[ch]=(count++); } //return the first appearence once char in current stringstream char FirstAppearingOnce() { char ans='#'; int pos=INT_MAX; for(auto it=dict.begin();it!=dict.end();it++) { if(it->second!=-1&&it->second<pos) { ans=it->first; pos=it->second; } } return ans; } private: int count; unordered_map<char,int> dict; };
连续子数组的最大和
题目描述
给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
思路:
dp[i]表示以i结尾的连续子数组(并不一定是以0为首)的和的最大值,当dp[i]+dp[i-1]>0时,此时第i个数可与前面的数组成连续子数组;当小于等于0时,dp[i]=0。
class Solution { public: int FindGreatestSumOfSubArray(vector<int> array) { vector<int>& nums=array; if(nums.empty()) return 0; vector<int> dp(nums.size()+1,0); int resi=INT_MIN; for(int i=1;i<dp.size();i++) { int idx=i-1; if(nums[idx]>resi) resi=nums[idx]; if(dp[idx]+nums[idx]<=0) dp[i]=0; else dp[i]=dp[idx]+nums[idx]; } int max=INT_MIN; for(int i=1;i<dp.size();i++) { if(dp[i]>max) max=dp[i]; } if(resi<0) return resi; else return max; } };
整数中1出现的次数(从1到n整数中1出现的次数)
题目描述
从1 到 n 中1出现的次数
思路:
以21345为例:
分为1~1345和1346~21345
1346~21345中:
万位上的1从10000~19999共出现了10000次
然后统计其他四位上1出现的次数。
继续将1346~21345分为:
1346~11345和11346~21345
对于1346~11345来说
首先1出现在千位:
此时右边三位任选0~9(当出现其他三位均为0时,1000是不合法的,因为1000不在1346~11345间,但对于11000是合法的,也就是说当小于下界时,可以填加一个万位使其合法):共1000种
其次1出现在百位,其他三位任选0~9(0100也是不合法的,但当补上万位后就合法了),这时也有1000种
同理:1346~11345中共有4*1000=4000种
而在11346~21345中也一样
则最后1346~21345共有8000种
则对于1346~21345共有18000种
而1~1345可以递归这个过程
class Solution { public: int NumberOf1Between1AndN_Solution(int n) { char* buf=new char[50]; sprintf(buf,"%d",n); return NumberCore(buf); } private: int NumberCore(char* n) { if(!n||*n<='0'||*n>'9'||*n==0) return 0; int len=strlen(n); if(len==1) return 1; int first=0; if(*n>'1') first=pow((double)10,(double)(len-1)); else first=atoi(n+1)+1; int second=0; second=(*n-'0')*(len-1)*pow((double)10,(double)(len-2)); return first+second+NumberCore(n+1); } };