重刷剑指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);
}
};
浙公网安备 33010602011771号