剑指offer总结
来源:互联网 发布:linux 共享打印机 编辑:程序博客网 时间:2024/05/20 09:11
1、实现Singleton模式
2、二维数组中的查找:每行从左到右递增,每列从上到下递增,输入一个数,判断数组中是否存在该数
1 2 8 9
2 4 9 12
4 7 10 13
6 8 11 15
如输入7:
小于第4列的9,则不可能在第4列;column--
小于第3列的8,则不可能在第3列;column--
大于第二列的2,则row++;
始终比较右上角的数,相等则返回。(每次查找都会剔除一行或者一列)
3、替换空格:
(移动重复,想办法减少重复,只移动一次!)
遍历一遍字符串char[],得知空格数目,就可知道替换后的字符串长度,用双指针p1 p2来从后往前移动字串
p1在p2的前面,指针同步移动(copy字符过去),但是p1遇到空格,p2就往前2步直到p2遇上p1,空格替换完毕
4、从尾到头部打印链表:(先询问是否可以改变链表结构)
1、不改变:遍历链表,值入栈,遍历结束再值出栈
2、改变:用头插法重建链表,再顺序遍历链表
5、根据前序和中序重建二叉树:Java代码
6、用2个栈实现队列:Java代码
7、旋转数组求最小:
8、求斐波那契数列第n项
递归;直接用公式O(1);递推O(n) 类似双指针 把已经得到的数列项保存起来
9、求二进制中的1的个数:
最优解法:(1100&1011=1000 能去掉最右边的1)
intNumber(int n ){
int count=0;
while(n){
count++;
n=(n-1)&n;
}
}
常规解法:
while(flag){
if(n&flag){
count++;
flag=flag<<1;
}
}
10、数值的整数次方:
要考虑负数(利用正数来求),0,正数
double f(double base,unsigned int e){
if(e==0)return 1;
if(e==1)return base;
double res=f(base,e>>1);
res*=res;
if(e&1==1)res*=base;
return res;
}//细节
12、打印1-n的大数(转化为字符)
13、删除节点O(1) 值覆盖p.data=p.next.data;p.next=p.next.next;
14、调整数组使得奇数位于偶数前面(双指针一前一后 判断奇数p&1==1?)
15、链表中的倒数第k个节点(双指针 注意边界)
16、反转链表 (1)双指针 头插法(2)三个指针pPrev pNode pNext 直接反转链表
17、合并2个排序的链表:
ListNode* Merge(ListNode* pHead1,ListNode* pHead2){
if(pHead1==null)return pHead2;
else if (pHead2==null)return pHead1;
ListNode* pMergedHead=null;
if(pHead1->Value<pHead2->Value){
pMergeHead=pHead1;
pMergeHead->next=Merge(pHead->next,pHead2);
}
else {
pMergeHead=pHead2;
pMergeHead->next=Merge(pHead1,pHead->next);
}
return pMergeHead;
}
18、判断树B是否是树A的子结构
struct BinaryTree{
int Value;
BinaryTree* left;
BinaryTree* right;
};
bool HasSubtee(BinaryTreeNode* pRoot1,BinaryTree* pRoot2){
bool result==false;
if(pRoot1!=null&&pRoot2!=null){
result=DoesTree1HaveTree2(pRoot1,pRoot2);
if(!result)
result=HasSubutree(pRoot1->left,pRoot2);
if(!result)
result=HasSubtree(pRoot1->right,pRoot2);
}
return result;
}
bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2){
if(pRoot2==null)return true;
if(pRoot1==null)return false;
if(pRoot1->Value!=pRoot2->Value)return false;
return DoesTree1HaveTree2(pRoot1->left,pRoot->left)&&DoesTree1HaveTree2(pRoot1-
>right,pRoot2->right);
}
19、二叉树的镜像:
void MirrorRecursively(BinaryTreeNode* pNode){
if((pNode==null)||(pNode->left==null&&pNode->right))return;
//先写递归代码,再添加退出条件
BinaryTreeNode* pTemp=pNode->left;
pNode->left=pNode->right;
pNode-right=pTemp;
if(pNode->left)MirrorRecursively(pNode->left);
if(pNode-right)MirrorRecursively(pNode-right);
}
20、顺时针打印矩阵
21、包含min函数的栈
2个栈,一个数据栈,一个辅助栈,辅助栈中栈顶始终数据栈的最小元素,若进栈元素大于最小值,则重复加
入
最小值到辅助栈中,因为它是当前最小,若小于最小值,则加入该最小值到辅助栈中(2个栈元素数量始终一致)
22、栈的压入弹出序列(判断第二个序列是否是第一个序列的弹出序列)
如果第二个序列中当前要判断的元素刚好与栈顶元素相等,则直接pop出来,如果不等,则将第一个序列的
后面还没有入栈的元素入栈,直到将与之相等的元素入栈为止,如果第一个序列的所有的元素都入栈了,还没有
找到与之相等的元素,则说明第二个序列不是第一个序列的弹出序列
23、从上往下打印二叉树 队列,逐层遍历
24、二叉搜索树的后续遍历序列
25、二叉树中和为某一值的路径: 栈 先序遍历
26、复杂链表的复制:
(1)A->A'->B->B'...(另一指针A->B)
(2)关键是A'->other=A->other-next;
(3)链表拆分 得到copy的链表
27、二叉搜索树与双向链表 (空)
28、字符串的排列:全排列
29、求数组中出现超过一半的数
(1)基于partition函数的O(n)算法,同快排的partition。会改变数组中数字的位置
(2)在遍历数组的时候,保存2个数字,一个是数组中的数,一个是次数,遍历到下一个数字时,如果和记
录的数字相等,次数+1;如果不同则次数-1;如果次数为0,则保存下一个数字,次数置为1。O(n)
30、最小的k个数
(1)partition函数划分,O(n)
(2)用最大堆作为装这k个数的容器(也可以用红黑树这种数据结构),每次取出最大的数,遍历完n个数后,得到最小的k个数。O(nlogk)
(可以先判断k>n/2则求前n-k大)
31、求连续子数组的最大和 动态规划
32、从1到n整数中1出现的次数????
33、把数组排成最小的数(用字符串表示数字,解决大数问题??)
34、丑数?
(1)逐个判断该整数是不是丑数
(2)创建数组保存已经找到的丑数???
35、第一次只出现一次的字符:
(1)扫描一遍字符串 int a[26]; a[字符-'a']++ hash的思想
(2)再次扫描字符串 输出第一个满足 a[字符-'a']==1的字符
36、数组中的逆序对:在数组中的2个数字如果前面一个数字大于后面的数字,则这2个数字组成一个逆序对
(1)暴力解法O(n^2){7 6 5}中有(7,6)(7,5)(6,5)
(2)归并的思想??O(nlogn)
37、2个链表的第一个公共子节点
最高效的解法:遍历链表得到长度m n 大的减小的=a,双指针 长的先走a步,再一起走,逐个判断节点
是否是同一个。O(m+n)
38、数字在排序数组中出现的顺序,二分法O(logn) 一般解法O(n)
39、求二叉树的深度 递归代码最简
拓展:判断一棵树是否是平衡树(任一节点的左右子树的高度差不大于1)后序遍历每个节点只访问一次?
40、数组中只出现一次的数字(有2个这样的数):要求时间O(n) 空间O(1)
(异或:相同数字异或为0,任一数异或0为本身)
假若数组中只有一个数只出现一次,数组中数字逐个异或的结果就是只出现一次的数字;
现在就要想办法,把这2个只出现一次的数分到2个子数组中,就能得到结果。
4异或6=100异或110=010 差别就是在第二个bit位上,所以我们可以把所有数字按这个原则分成2组
4和6一定会被分到不同的组中,相同的数字会被分到同一组中。
41、一个递增排序的数组和一个数s,在数组中查找2个数的和正好是s,输出任一对即可
一般解法是暴力O(n^2) 双指针-首尾指针的解法是O(n)
拓展:打印和为s的连续正数序列 15=1+2+3+4+5=4+5+6=7+8 打印(1 2 3 4 5)(4 5 6)(7 8 )
先形成清晰的解题思路,才能开始写代码;借助上题双指针的思路
最开始:small big 指向1 2 和为3<9 big增大 123 和为6<9 增大big 1234 10>9 增大small
2 3 4 =9 打印 再增大big 2 3 4 5 和14>9 减小small。。。找到4 5 =9
(循环退出条件:small<middle)其中middle=(1+sum)/2;
42、翻转字符串"I am a student."->"student. a am I"
2次翻转 先整个reverse再单个单词reverse
拓展:左旋字符串:输入abcde 2 输出cdeab
先ab->ba cde-> edc 即abcde->baedc
baedc再reverse得到cdeab(注意边界 null)
43、n个色子的点数?
44、扑克牌的顺子?
45、圆圈中剩下的数字:
题目:0 1 2 3 ...n-1这n个数字排成一圈,从0开始每次从这个圆圈中删除第m个数字,求这个圆圈最后剩
下哪个数字?
有名的约瑟夫环问题
46、?求1+2+3+...+n要求不能乘除法、for while if else swith case 条件判断语句
47、不用加减乘除做加法
48、不能被继承的类 java中用final C++中没有,可以把构造函数设为私有
49、字符串转换为整数(自己想好特殊的测试用例)
50、树中2个结点的最低公共祖先(问清楚需求,也许对方是故意漏掉条件考你的思路)
2、二维数组中的查找:每行从左到右递增,每列从上到下递增,输入一个数,判断数组中是否存在该数
1 2 8 9
2 4 9 12
4 7 10 13
6 8 11 15
如输入7:
小于第4列的9,则不可能在第4列;column--
小于第3列的8,则不可能在第3列;column--
大于第二列的2,则row++;
始终比较右上角的数,相等则返回。(每次查找都会剔除一行或者一列)
3、替换空格:
(移动重复,想办法减少重复,只移动一次!)
遍历一遍字符串char[],得知空格数目,就可知道替换后的字符串长度,用双指针p1 p2来从后往前移动字串
p1在p2的前面,指针同步移动(copy字符过去),但是p1遇到空格,p2就往前2步直到p2遇上p1,空格替换完毕
4、从尾到头部打印链表:(先询问是否可以改变链表结构)
1、不改变:遍历链表,值入栈,遍历结束再值出栈
2、改变:用头插法重建链表,再顺序遍历链表
5、根据前序和中序重建二叉树:Java代码
6、用2个栈实现队列:Java代码
7、旋转数组求最小:
8、求斐波那契数列第n项
递归;直接用公式O(1);递推O(n) 类似双指针 把已经得到的数列项保存起来
9、求二进制中的1的个数:
最优解法:(1100&1011=1000 能去掉最右边的1)
intNumber(int n ){
int count=0;
while(n){
count++;
n=(n-1)&n;
}
}
常规解法:
while(flag){
if(n&flag){
count++;
flag=flag<<1;
}
}
10、数值的整数次方:
要考虑负数(利用正数来求),0,正数
double f(double base,unsigned int e){
if(e==0)return 1;
if(e==1)return base;
double res=f(base,e>>1);
res*=res;
if(e&1==1)res*=base;
return res;
}//细节
12、打印1-n的大数(转化为字符)
13、删除节点O(1) 值覆盖p.data=p.next.data;p.next=p.next.next;
14、调整数组使得奇数位于偶数前面(双指针一前一后 判断奇数p&1==1?)
15、链表中的倒数第k个节点(双指针 注意边界)
16、反转链表 (1)双指针 头插法(2)三个指针pPrev pNode pNext 直接反转链表
17、合并2个排序的链表:
ListNode* Merge(ListNode* pHead1,ListNode* pHead2){
if(pHead1==null)return pHead2;
else if (pHead2==null)return pHead1;
ListNode* pMergedHead=null;
if(pHead1->Value<pHead2->Value){
pMergeHead=pHead1;
pMergeHead->next=Merge(pHead->next,pHead2);
}
else {
pMergeHead=pHead2;
pMergeHead->next=Merge(pHead1,pHead->next);
}
return pMergeHead;
}
18、判断树B是否是树A的子结构
struct BinaryTree{
int Value;
BinaryTree* left;
BinaryTree* right;
};
bool HasSubtee(BinaryTreeNode* pRoot1,BinaryTree* pRoot2){
bool result==false;
if(pRoot1!=null&&pRoot2!=null){
result=DoesTree1HaveTree2(pRoot1,pRoot2);
if(!result)
result=HasSubutree(pRoot1->left,pRoot2);
if(!result)
result=HasSubtree(pRoot1->right,pRoot2);
}
return result;
}
bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2){
if(pRoot2==null)return true;
if(pRoot1==null)return false;
if(pRoot1->Value!=pRoot2->Value)return false;
return DoesTree1HaveTree2(pRoot1->left,pRoot->left)&&DoesTree1HaveTree2(pRoot1-
>right,pRoot2->right);
}
19、二叉树的镜像:
void MirrorRecursively(BinaryTreeNode* pNode){
if((pNode==null)||(pNode->left==null&&pNode->right))return;
//先写递归代码,再添加退出条件
BinaryTreeNode* pTemp=pNode->left;
pNode->left=pNode->right;
pNode-right=pTemp;
if(pNode->left)MirrorRecursively(pNode->left);
if(pNode-right)MirrorRecursively(pNode-right);
}
20、顺时针打印矩阵
21、包含min函数的栈
2个栈,一个数据栈,一个辅助栈,辅助栈中栈顶始终数据栈的最小元素,若进栈元素大于最小值,则重复加
入
最小值到辅助栈中,因为它是当前最小,若小于最小值,则加入该最小值到辅助栈中(2个栈元素数量始终一致)
22、栈的压入弹出序列(判断第二个序列是否是第一个序列的弹出序列)
如果第二个序列中当前要判断的元素刚好与栈顶元素相等,则直接pop出来,如果不等,则将第一个序列的
后面还没有入栈的元素入栈,直到将与之相等的元素入栈为止,如果第一个序列的所有的元素都入栈了,还没有
找到与之相等的元素,则说明第二个序列不是第一个序列的弹出序列
23、从上往下打印二叉树 队列,逐层遍历
24、二叉搜索树的后续遍历序列
25、二叉树中和为某一值的路径: 栈 先序遍历
26、复杂链表的复制:
(1)A->A'->B->B'...(另一指针A->B)
(2)关键是A'->other=A->other-next;
(3)链表拆分 得到copy的链表
27、二叉搜索树与双向链表 (空)
28、字符串的排列:全排列
29、求数组中出现超过一半的数
(1)基于partition函数的O(n)算法,同快排的partition。会改变数组中数字的位置
(2)在遍历数组的时候,保存2个数字,一个是数组中的数,一个是次数,遍历到下一个数字时,如果和记
录的数字相等,次数+1;如果不同则次数-1;如果次数为0,则保存下一个数字,次数置为1。O(n)
30、最小的k个数
(1)partition函数划分,O(n)
(2)用最大堆作为装这k个数的容器(也可以用红黑树这种数据结构),每次取出最大的数,遍历完n个数后,得到最小的k个数。O(nlogk)
(可以先判断k>n/2则求前n-k大)
31、求连续子数组的最大和 动态规划
32、从1到n整数中1出现的次数????
33、把数组排成最小的数(用字符串表示数字,解决大数问题??)
34、丑数?
(1)逐个判断该整数是不是丑数
(2)创建数组保存已经找到的丑数???
35、第一次只出现一次的字符:
(1)扫描一遍字符串 int a[26]; a[字符-'a']++ hash的思想
(2)再次扫描字符串 输出第一个满足 a[字符-'a']==1的字符
36、数组中的逆序对:在数组中的2个数字如果前面一个数字大于后面的数字,则这2个数字组成一个逆序对
(1)暴力解法O(n^2){7 6 5}中有(7,6)(7,5)(6,5)
(2)归并的思想??O(nlogn)
37、2个链表的第一个公共子节点
最高效的解法:遍历链表得到长度m n 大的减小的=a,双指针 长的先走a步,再一起走,逐个判断节点
是否是同一个。O(m+n)
38、数字在排序数组中出现的顺序,二分法O(logn) 一般解法O(n)
39、求二叉树的深度 递归代码最简
拓展:判断一棵树是否是平衡树(任一节点的左右子树的高度差不大于1)后序遍历每个节点只访问一次?
40、数组中只出现一次的数字(有2个这样的数):要求时间O(n) 空间O(1)
(异或:相同数字异或为0,任一数异或0为本身)
假若数组中只有一个数只出现一次,数组中数字逐个异或的结果就是只出现一次的数字;
现在就要想办法,把这2个只出现一次的数分到2个子数组中,就能得到结果。
4异或6=100异或110=010 差别就是在第二个bit位上,所以我们可以把所有数字按这个原则分成2组
4和6一定会被分到不同的组中,相同的数字会被分到同一组中。
41、一个递增排序的数组和一个数s,在数组中查找2个数的和正好是s,输出任一对即可
一般解法是暴力O(n^2) 双指针-首尾指针的解法是O(n)
拓展:打印和为s的连续正数序列 15=1+2+3+4+5=4+5+6=7+8 打印(1 2 3 4 5)(4 5 6)(7 8 )
先形成清晰的解题思路,才能开始写代码;借助上题双指针的思路
最开始:small big 指向1 2 和为3<9 big增大 123 和为6<9 增大big 1234 10>9 增大small
2 3 4 =9 打印 再增大big 2 3 4 5 和14>9 减小small。。。找到4 5 =9
(循环退出条件:small<middle)其中middle=(1+sum)/2;
42、翻转字符串"I am a student."->"student. a am I"
2次翻转 先整个reverse再单个单词reverse
拓展:左旋字符串:输入abcde 2 输出cdeab
先ab->ba cde-> edc 即abcde->baedc
baedc再reverse得到cdeab(注意边界 null)
43、n个色子的点数?
44、扑克牌的顺子?
45、圆圈中剩下的数字:
题目:0 1 2 3 ...n-1这n个数字排成一圈,从0开始每次从这个圆圈中删除第m个数字,求这个圆圈最后剩
下哪个数字?
有名的约瑟夫环问题
46、?求1+2+3+...+n要求不能乘除法、for while if else swith case 条件判断语句
47、不用加减乘除做加法
48、不能被继承的类 java中用final C++中没有,可以把构造函数设为私有
49、字符串转换为整数(自己想好特殊的测试用例)
50、树中2个结点的最低公共祖先(问清楚需求,也许对方是故意漏掉条件考你的思路)
0 0
- 剑指Offer试题总结
- 剑指offer阅读总结
- 剑指offer总结
- 剑指Offer总结
- 剑指offer总结
- 《剑指offer》简略总结
- 剑指offer面试题总结
- 剑指offer---读后总结
- 剑指offer刷题总结
- 剑指offer总结——1
- 剑指Offer之面试位运算总结
- 剑指Offer试题总结(二)
- 《剑指offer》第2章总结
- 剑指offer重要题目整理总结
- [转]剑指offer面试题总结
- 剑指offer-第三题方法总结
- 剑指offer第四题方法总结
- 剑指offer-第12题方法总结
- OAuth-维基百科(一)
- 用VIM编写C/C++程序
- c++获取系统信息
- SizeClass和AutoLayout教程1
- android获取手机IMSI号
- 剑指offer总结
- 队列的链式存储
- hdu 1010 dfs+奇偶剪枝
- Hibernate事务与并发问题处理(乐观锁与悲观锁)
- 剑指offer面试题2.3.1——数组和指针的区别
- Beaglebone Black的启动
- “iOS 推送通知”详解:从创建到设置到运行
- Gradle 操纵文件
- android usb挂载分析---vold处理FrameWork层发出的消息