剑指offer
sunflower_Yolanda
积极乐观的程序媛
展开
-
实现Singleton模式
题目:设计一个类,我们只能生产该类的一个实例。C#版本:思路一:只适用于单线程环境public sealed class Singleton1{ private Singleton1(){}//构造函数设为私有函数以禁止他人创建实例 private static Singleton1 instance = null;//静态实例 public static Singleto原创 2015-09-15 16:53:40 · 369 阅读 · 0 评论 -
把数组排成最小的数
题目:输入一个正整数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。原创 2015-09-30 19:05:06 · 283 阅读 · 0 评论 -
和为s的两个数字VS和为s的连续整数序列
题目1:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。方法:双指针。如果和小于s,向后移;大于s,向前移。时间复杂度O(n)bool FindNumbersWithSum(int data[], int length, int sum, int* num1, int* num2){ bool found = fals原创 2015-10-07 22:13:30 · 360 阅读 · 0 评论 -
数组中只出现一次的数字
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次,请写程序找到这个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。方法:从头到尾一次异或数组中的每一个数字,则得到的数字为两个只出现一次的数字的异或。在结果数字中找到第一个为1的位置,记为第n位。以第n位是不是1为标准把原数组中的数字分成两个子数组,则把出现了两次的相同数字分到同一组,每个子数组都只包含一个只出现一次的数字原创 2015-10-07 21:13:34 · 351 阅读 · 0 评论 -
二叉树的深度
题目1:输入一颗二叉树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。方法:递归int TreeDepth(BinaryTreeNode* pRoot){ if (pRoot == NULL){ return 0; } int nLeft = TreeDepth(pRoot->m_pLeft);原创 2015-10-07 21:07:26 · 374 阅读 · 0 评论 -
丑数
题目:我们把只包含2、3和5的数称作丑数。求按从小到达的顺序的第1500个丑数。例如6、8都是丑数,但14不是,因为它包含因子7.习惯上把1当做第一个丑数。方法1:如果一个数能被2整除,我们把它连续除以2;如果能被3整除,就连续除以3;如果能被5整除,就除以连续5.如果最后得到的是1,则这个数就是丑数,否则不是。bool IsUgly(int number){ while (number %原创 2015-10-07 14:14:34 · 379 阅读 · 0 评论 -
两个链表的第一个公共结点
题目:输入两个链表,找出他们的第一个公共结点。方法1:分别把两个链表的节点放入两个栈里,这样两个链表的尾结点就位于两个栈的栈顶,接下来比较两个栈顶的结点是否相同。如果相同,则把栈顶弹出接着比较下一个栈顶,直到找到最后一个相同的结点。时间和空间复杂度都是O(m+n)。方法2:先遍历两个链表得到它们的长度,因此直到哪个链表比较长,以及长链表比短链表多几个结点。在第二次遍历的时候,在较长的链表上先走若干步原创 2015-10-07 16:53:18 · 532 阅读 · 0 评论 -
链表
struct ListNode{ int m_nValue; ListNode* m_pNext;}题目一:在链表的末尾添加一个节点void AddToTail(ListNode** pHead, int value){ ListNode* pNew = new ListNode(); pNew->m_nValue = value; pNew->m_pNe原创 2015-09-16 08:24:26 · 421 阅读 · 0 评论 -
用两个栈实现队列
题目:用两个栈实现一个队列,队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入结点和在队列头部删除结点的功能。template <typename T> class CQueue{ public : CQueue(void); ~CQueue(void); void appendTail(cons原创 2015-09-16 14:45:56 · 352 阅读 · 0 评论 -
重建二叉树
题目:输入某二叉树的前序遍历和中序遍历结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 例子:输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出的二叉树如下图: 方法:前序遍历序列的第一个数字1是根节点的值。扫描中序遍历序列,能确定根节点的值的位置。根据中序遍历特点,在根节点的值1前面的3个数字都是左子树结点原创 2015-09-16 11:08:19 · 379 阅读 · 0 评论 -
第一个只出现一次的字符
题目:在字符串中找出第一个只出现一次的字符。如输入“abaccdeff”则输出’b’。 方法:用哈希表(包含256个字符的辅助数组),扫描两遍。char FirstNotRepeatingChar(char* pString){ if (pString == NULL){ return '\0'; } const int tableSize = 256;原创 2015-10-07 15:44:09 · 386 阅读 · 0 评论 -
数组中的逆序对
题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。方法:先把数组分隔成子数组,先统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目。在统计逆序对过程中,需要对数组进行归并排序。整个过程如下: 合并子数组并统计逆序对过程如下int InversePairs(int* data, int leng原创 2015-10-07 16:41:49 · 416 阅读 · 0 评论 -
数字在排序数组中出现的次数
题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}\{1,2,3,3,3,3,4,5\}和数字3,由于3在这个数组中出现了4次,因此输出4。方法:用二分查找法找到数组第一个和最后一个kint GetFirstK(int* data, int length, int k, int start, int end){ if (start > end){原创 2015-10-07 19:19:35 · 371 阅读 · 0 评论 -
不能被继承的类
题目:用C++设计一个不能被继承的类。方法1:把构造函数设为私有函数。使用静态函数获得类型的实例。缺点:只能得到位于堆上的实例,而得不到位于栈上的实例。class SealedClass1 { public: static SealedClass1* GetInstance(){ return new SealedClass1(); }原创 2015-10-08 15:53:42 · 401 阅读 · 0 评论 -
翻转单词顺序 VS 左旋转字符串
题目1:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变,标点符号和普通字母一样处理。 例如输入”I am a student.”, 则输出”student. a am I”。方法:第一步翻转句子中所有的字符,第二步翻转每个单词中字符的顺序。void Reverse(char* pBegin, char* pEnd){ if (pBegin == NULL || pEnd ==原创 2015-10-07 22:50:35 · 400 阅读 · 0 评论 -
n个骰子的点数
题目:把那个骰子仍在地上,所有骰子朝上一面的点数之和为s。输入n,打印出s的所有可能的值出现的概率。方法1:基于递归求骰子点数。n个骰子的所有点数的排列数为6n6^n。需要统计出每一个点数出现的次数,然后把每个点数出现的次数除以6n6^n就能求出每个点数出现的概率。int g_maxValue = 6;void PrintProbability(int number){ if (number原创 2015-10-07 23:15:13 · 330 阅读 · 0 评论 -
不用加减乘除做加法
题目:写一个函数,求两个整数之和,要求在函数体内不得使用+,-,×\times,÷\div 四则运算符号。方法:两数异或并左移一位,知道不产生进位为止int Add(int num1, int num2){ int sum, carry; do{ sum = num1 ^ num2; carry = (num1 & num2) << 1;原创 2015-10-08 15:41:54 · 349 阅读 · 0 评论 -
斐波那契数列(有疑问)
题目:写一个函数,输入n,求Fibonacci数列的第n项。 f(n)=⎧⎩⎨⎪⎪0,1,f(n−1)+f(n−2),nnn=0,=1,>1.\begin{equation}\notagf(n)=\left\{\begin{aligned}&0,&n&= 0,\\&1,&n&=1,\\&f(n - 1) + f(n - 2),&n&>1.\end{aligned}\right.原创 2015-09-18 22:03:56 · 540 阅读 · 0 评论 -
扑克牌的顺子
题目:从扑克牌中随机抽取5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王可以看成任意数字。方法:首先把数组排序,再统计数组中0的个数,最后统计排序之后的数组中相邻数字之间的空缺总数。如果空缺的总数小于或者等于0的个数,则这个数组就是连续的,反之不连续。如果数组中的非0数字重复出现,也是不连续的。bool IsContinuous原创 2015-10-08 10:14:42 · 481 阅读 · 0 评论 -
数组中重复的数字(没理解)
题目:在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的。请找出数组中任意一个重复的数字。方法1:排序。方法2:哈希表。方法3:原创 2015-10-08 16:12:41 · 373 阅读 · 0 评论 -
求1+2+...+n(不太理解)
题目:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。方法1:利用构造函数。定义一个类型,接着创建n个该类型的实例,则这个类型的构造函数将确定会被调用n次,将与累加相关的代码放到构造函数里。class Temp { public: Temp() { ++N; Sum += N; }原创 2015-10-08 11:59:01 · 673 阅读 · 0 评论 -
圆圈中最后剩下的数字(不太理解方法2)
题目:0,1,…,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。(约瑟夫环问题)方法1:用环形链表(std::list)模拟,每当迭代器(Iterator)扫描到链表末尾的时候,把迭代器移到链表的头部,这就相当于按照顺序在一个圆圈里遍历。时间复杂度O(mn),空间复杂度O(n)。int LastRemaining(unsigned int原创 2015-10-08 11:18:16 · 623 阅读 · 0 评论 -
赋值运算符函数
题目:如下为类型CMyString的声明,请为该类型添加赋值运算符函数。class CMyString{ public: CMyString(char* pData = NULL); CMyString(const CMyString& str); ~CMyString(void); private: char* m_p原创 2015-09-15 12:09:47 · 577 阅读 · 0 评论 -
替换空格
题目:请实现一个函数,把字符串中的每个空格替换成“%20”。例如输入“We are happy.”,则输出”We%20are%20happy.”。思路一:从头到尾扫描字符串,每一次碰到空格字符的时候做替换。把1个字符替换成3个字符,并把空格后面所有的字符都后移两个字节。时间复杂度O(n2)O(n^2)。 思路二:先遍历一次字符串,统计出空格总数,则替换后字符串长度等于原来的长度加上2乘以空格数目。原创 2015-09-15 17:40:50 · 373 阅读 · 0 评论 -
反转链表
题目:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的投结点。struct ListNode{ int m_nKey; ListNode* m_pNext;}方法1:定义3个指针,分别指向当前遍历到的结点、它的前一个结点及后一个结点。ListNode* ReverseList(ListNode* pHead){ ListNode* pReversedHead原创 2015-09-28 09:23:44 · 310 阅读 · 0 评论 -
二叉搜索树与双向链表
题目:输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。 方法:中序遍历,当转换到根结点(值为10)时,它的左子树已经转换成一个排序的链表了,并且处在链表中最后一个结点是当前值最大的结点。把值为8的结点和根结点链接起来,此时链表中的最后一个结点就是10了。接着去遍历转换右子树,并把根结点和右子树中最小的结点链接起来。递归转换左子树和右原创 2015-09-28 15:47:14 · 314 阅读 · 0 评论 -
合并两个排序的链表
题目:输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序。struct ListNode{ int m_nValue; ListNode* m_pNext;}ListNode* Merge(ListNode* pHead1, ListNode* pHead2){ if (pHead1 == NULL){ return pHead2;原创 2015-09-28 09:55:24 · 388 阅读 · 0 评论 -
二叉树中和为某一值的路径
题目:输入一颗二叉树和一个整数,打印出二叉树种结点值的和为输入整数的所有路径。void FindPath(BinaryTreeNode* pRoot, int expectedSum){ if (pRoot == NULL){ return; } std::vector<int> path; int currentSum = 0; FindPat原创 2015-09-28 15:15:50 · 331 阅读 · 0 评论 -
调整数组顺序使奇数位于偶数前面
题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。方法:双指针法把第一个指针指向数组的第一个数字,第二个指针指向最后一个数字向后移动第一个指针直至它指向偶数2,此时第二个指针指向奇数5,不需要移动交换两个指针指向的数字向后移动第一个指针直至它指向偶数4,向前移动第二个指针直至它指向奇数3。由于第二个指针移动到了第一个指针原创 2015-09-26 16:31:40 · 595 阅读 · 0 评论 -
数值的整数次方
题目:实现函数doublePower(doublebase,intexponent)double \;Power(double\;base,\;int\;exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。题目陷阱:输入的指数小于1底数为零判断小树(float,double)类型是否相等,只要判断差的绝对值是否在一个很小的范围内。方法1原创 2015-09-25 11:35:20 · 352 阅读 · 0 评论 -
打印1到最大的n位数
题目:输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数即999。陷阱:用int或long表示整数时的溢出方法1:用字符串解决大数问题。void PrintToMaxOfNDigits(int n){ if (n <= 0){ return; } char *number = new char[n + 1];原创 2015-09-26 14:19:51 · 487 阅读 · 0 评论 -
二进制中1的个数
题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。位运算基础:左移操作:m<<nm<<n表示把m左移n位。左移n位的时候,最左边的n位将被丢弃,同时在最右边补上n个0。如:00001010<<2=0010100000001010 <<2=00101000,10001010<<3=010100001000101原创 2015-09-25 10:01:11 · 298 阅读 · 0 评论 -
链表中倒数第k个节点
题目:输入一个链表,输出该链表中倒数第k个结点。struct ListNode{ int m_nValue; ListNode* m_pNext;}方法:定义两个指针。第一个指针从链表的头指针开始遍历向前走k-1,第二个指针保持不动;从第k步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在k-1,当第一个(走在前面的)指针到达链表的尾结点时,第二个指针(走在后原创 2015-09-26 16:53:35 · 339 阅读 · 0 评论 -
二叉树的镜像
题目:请完成一个函数,输入一个二叉树,该函数输出它的镜像。struct BinaryTreeNode{ int m_nValue; BinaryTreeNode* m_pLeft; BinaryTreeNode* m_pRight;}方法:前序遍历这棵树的每个结点,如果遍历到的结点有子结点,就交换它的两个子结点。当交换完所有非叶子结点的左右子结点后,就得到了树的镜像。voi原创 2015-09-28 10:57:36 · 349 阅读 · 0 评论 -
包含min函数的栈
题目:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min函数。在该栈中,调用min、push及pop的时间复杂度都是O(1)。template <typename T> void StackWithMin<T>::push(const T& value){ m_data.push(value); if (m_min.size() == 0 || value < m_mi原创 2015-09-28 11:32:35 · 339 阅读 · 0 评论 -
从上往下打印二叉树
题目:从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。struct BinaryTreeNode{ int m_nValue; BinaryTreeNode* m_pLeft; BinaryTreeNode* m_pRight;}void PrintFromTopToBottom(BinaryTreeNode* pTreeRoot){ if (!原创 2015-09-28 11:57:28 · 288 阅读 · 0 评论 -
二维数组中的查找
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。方法:首先选取数组中右上角的数字。如果该数字等于要查找的数字,查找过程结束;如果该数字大于要查找的数字,剔除这个数字所在的列(向左移);如果该数字小于要查找的数字,剔除这个数字所在的行(向下移)。如下所示: bool Find(原创 2015-09-15 17:11:46 · 328 阅读 · 0 评论 -
从1到n整数中1出现的次数(有疑问)
题目:输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组的和的最大值。原创 2015-09-28 23:45:57 · 464 阅读 · 0 评论 -
最小的k个数
题目:输入n个整数,找出其中最小的k个数。方法1:O(n)的算法,只有当我们可以修改输入的数组时可用。基于Partition函数,如果基于数组的第k个数字来调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。void GetLeastNumbers(int* input, int n, int* output, int k){ if (input =原创 2015-09-28 22:33:09 · 343 阅读 · 0 评论 -
树的子结构
题目:输入两颗二叉树A和B,判断B是不是A的子结构。struct BinaryTreeNode{ int m_nValue; BinaryTreeNode* m_pLeft; BinaryTreeNode* m_pRight;};方法:第一步在树A中找到和B的根结点的值一样的结点R,第二步再判断A中以R为根结点的字数是不是包含和树B一样的结构。bool HasSubtree原创 2015-09-28 10:14:50 · 394 阅读 · 0 评论