
《剑指Offer》
戎·码一生
自信来自实力,改变来自挑战。做一只生活小强。
展开
-
《剑指offer》:[5]查找两个链表的第一个公共结点
解决问题:输入两个链表头结点,找到链表中的第一个公共的结点。 方案一:蛮力法。能解决问题,但是像许多人说的那样,也只能这样了!具体方法是,用list2中的每个元素和list1中的每个元素进行比较,当得到第一个相等的元素的时候就是两个链表的第一个公共结点。假设list1和list2分别长M、N,则时间复杂度飚至O(M*N). 方案二:借助栈的方法。因为找公共结点,那么原创 2016-05-24 16:52:55 · 640 阅读 · 0 评论 -
《剑指offer》:[15]实现指数函数:x的y次方
“最不能容忍的功能错误,忽略边界情况。必须保证功能测试、边界测试、负面测试以及性能测试” --尹彦(Intel)问题:数值的整数次方实现double(double base,int exponent),求base的expo原创 2016-06-04 17:03:24 · 1378 阅读 · 0 评论 -
《剑指offer》:[17]调整数组顺序使奇数位于偶数面前
题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有偶数位于数组的后半部分。方案一:顺序查找。如果发现一个偶数,则将其移动到数组末尾,将其他的元素向前移动。记住第一个元素,当第二次查找到该元素的时候,就停止,此时,已将所有的偶数移动到了数组的后半段。由此可以看出,每次需要移动n-1个数数字,所以其时间复杂度为O(N^2)。这种方案我们也多次说过,原创 2016-06-05 19:51:08 · 587 阅读 · 0 评论 -
《剑指offer》:[36]数组中的逆序对
题目:在数组中的两个数字如果前面饿一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。例如在数组{7,5,6,4}中就有5对,{7,5},{7,6},{7,4},{5,4},{6,4}。方案一:最直接的方法就是顺序扫描每个数字,然后和后面的数字进行比较,如果前一个比后一个小,则说明它们是逆序的,如以上的5组都是逆序的。计数器+1;每个数字和后面比原创 2016-06-11 21:06:36 · 1205 阅读 · 0 评论 -
《剑指offer》:[35]第一次出现且只出现一次的字符
题目:在字符串中查找第一次出现且只出现一次的字符。如输入“ababkdcdycghis”,则输出‘k’。方案一:最直接的方法就是,从字符串的第一个字符开始,顺序扫描和后面的字符进行比较,如果没有发现重复的字符,则说明该字符是第一次出现。由于每个字符都需要和后面的O(N)字符进行比较,所以其时间复杂度为O(N^2)。方案二:时间复杂度为O(N)。由于题目和字符出现的次数有关,所以我们原创 2016-06-11 21:01:10 · 1371 阅读 · 0 评论 -
《剑指offer》:[34]丑数的判断与查找
题目:我们把只包含因子2,3,5的数称为丑数(Ugly Number)。求按从小到大的顺序的第1500个丑数。例如6,8都是丑数,但14不是,因为它包含因子7.习惯上我们把1当作第一个丑数。方案一:所谓一个数m是n的因子的意思是n能被m整除。那么根据丑数的定义,丑数只能被2,3,5整除,如果一个数能被2整除我们就连续除以2,如果能被3整除我们就连续除以3,如果能被5整除,我们就连续除以5。原创 2016-06-11 20:28:32 · 1023 阅读 · 0 评论 -
《剑指offer》:[2]O(1)时间删除链表结点
问题:给定一个单向的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。 因为单链表的最大弊病就是查找是单向的,只能向前不能后退!精神可嘉,但是带来了限制。比如一般我我们考虑删除链表的一个给定结点都是要从头结点遍历找到要删除的结点的前驱结点,然后才能正确的删除给定的结点,其查找的时间复杂度为O(N),能不能不进行查找使删除的效率为O(1)呢?答案是肯定的。下面来看一看!原创 2016-05-23 16:30:11 · 639 阅读 · 0 评论 -
《剑指offer》:[3]得到链表中倒数第K个结点
由于链表中不能随机得到一个结点的值,也不知道具体的第K个结点在什么位置,不像数组那样随机存取效率高,所以有时候我们需要知道第K个元素的值,这里我们讨论一下如何获得倒数第K个元素的值。 正向第K个元素很简单,用一趟遍历便可以得到。时间复杂度为O(N)。 那么倒数第K个元素,还需要遍历一次,其时间复杂度为:O(N)+O(N)=O(N)。遍历一遍,我们就知道了链表的长度原创 2016-05-23 17:23:07 · 783 阅读 · 0 评论 -
《剑指offer》:[4]合并两个单链表
合并两个链表,可以分为有序和无序的链表。 无序链表非常简单,将一个链表接在另一个链表的后面就可以了。 但是如果是有序的两个链表就设计到判断和一些细节,这里主要实现两个递增有序的链表。合并方案一:采用递归方式#include #include #include using namespace std;struct List{ int numbe原创 2016-05-24 15:29:28 · 793 阅读 · 0 评论 -
《剑指offer》:[6]两个栈实现一个队列的C++代码实现
问题:用两个栈实现一个队列,完成在队列尾部插入节点和在队列头部删除结点的功能。由于栈的特点是先进后出,要想实现队列,必须做到先进先出; 首先将数据输入到stack1中,这时候先进后出,再将stack1中的数据移动到stack2中,相当于将输入的数据的顺序颠倒,这样也就实现了队列的特点,先进先出。下面具体说一下队列为NULL,入队和出队的具体实现方法;(1)判断队列是否为NULL原创 2016-05-26 11:16:57 · 966 阅读 · 0 评论 -
《剑指offer》:[10]利用前序和中序构建二叉树
树是一种在实际编程中经常遇到的数据结构。它的逻辑比较简单,除了根节点之外每个节点只有一个父节点,根节点没有父节点。除了叶子结点外所有的结点都有一个或者多个子节点,子节点没有叶子节点。父节点与子节点之间用指针来连接。 但是我们经常用到的数据结构为:二叉树。所谓二叉树是树的一种特殊结构,在二叉树中,每个结点最多只能有两个结点。下面我们来看一下树的一些相关概念:参考书籍为:《数据结构与算原创 2016-06-02 21:09:14 · 879 阅读 · 2 评论 -
《剑指offer》:[38]数字在排序数组中出现的次数
“沟通、学习能力就是看面试者能否清晰、有条理地表达自己,是否会在自己所得到的信息不够的情况下主动发问澄清,能否在得到一些暗示之后迅速做出反应纠正错误” ---陈黎明(MSo原创 2016-06-19 15:53:23 · 1549 阅读 · 0 评论 -
《剑指offer》:[39-1]判断是否为平衡二叉树
题目:输入一棵二叉树的结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。上图中的二叉树就是一棵平衡二叉树。分析:有了求二叉树深度的思路后,我们很快就能找到求解该问题的方法,就是从根结点开始开始判断其左右子结点的深度之差是否为1。如果从根结点开始到叶子结点的每一个结点的左右子树的深度相差都不超过1,则说明该二叉树是平衡二叉树。但是其原创 2016-06-19 16:02:50 · 1614 阅读 · 0 评论 -
《剑指offer》:[12]递归与循环-斐波那契数列
如果我们需要重复的多次计算相同的问题,通常可以选择递归或者循环两种方法。递归是在一个函数的内部调用这个函数自身。而循环则是通过设置计算的初始值及终止条件,在一个范围内进行重复计算。递归的优点:代码简洁;缺点:(1)递归调用是函数自己调用自己,所以是有时间和空间的消耗的;每一次函数调用,都要在内存栈中分配空间以保存参数、返回地址和临时变量。而且往栈里压入和弹出都需要时间。原创 2016-06-03 16:23:34 · 668 阅读 · 0 评论 -
《剑指offer》:[48]不能被继承的类-单例模式
题目:不能被继承的类 不能继承,一般我们会对构造函数做手脚。不能继承,继承会发生什么,继承的类在创建对象的时候,会自动调用父类的构造函数,如果我们在这里限制让子类不能调用父类的构造和析构就是实现了不能继承,但是也不能影响自己的使用。方案一:思想:设置构造函数和析构函数为私有+新增两方法创建和销毁对象。原因:(1)把构造函数和析构函数设置为私有函数,这样可以防止子类调用构造函数和原创 2016-06-25 11:52:51 · 6935 阅读 · 0 评论 -
《剑指offer》:[1]反转一个单链表
“'神马’都是浮云,应聘技术岗位就是要踏实写程序。” ----田超(微软,SDE II) 这已经是第二遍看《剑指offer》这本书了,发现里面讲的还是比较基础,不能说讲的多么多么精湛高深,但是整本书确实有很多值得我们学习的技巧和方法,易错点。作为菜鸟程序猿一族的我深深的明白这些都是必须要读的书籍,因为它是打开程序猿世界的一把钥匙,是万丈高楼的地基,是开战前的厉兵秣马,是我想登原创 2016-05-23 15:36:51 · 1198 阅读 · 0 评论 -
《剑指offer》:[39]求解二叉树的深度
题目:输入一棵二叉树的根结点,求该树的深度。从根结点到叶子结点一次经过的结点(含根、也结点)形成树的一条路径,最长路径的长度为树的深度。例如下图中的二叉树,其深度根结点到叶子结点:1->2->5->7,该条路径的长度为4,所以该二叉树的深度为4 。方案:递归方法。时间复杂度大于O(N)。 在面试题25中,我们讨论了如何用容器来记录一个条路径及求路径的和的情况,但是该方法的代码量比较原创 2016-06-19 15:57:36 · 1541 阅读 · 0 评论 -
《剑指offer》:[31]连续子数组的最大和及子序列的值
题目:输入一个整形数组,数组里有整数也有负数。数组中一个或连续多个整数组成一个子数组。求所有子数组的和的最大值和其序列的值。要求时间复杂度为O(N)。例如输入数组为{1,-2,3,10,-4,7,2,5},最后输出的最大该子数组的和为18。方案一:最直观的方法就是列举出数组中所有的子数列,然后对应的每个子数列进行求和。最后再找出最大的一个。对于n个元素的数组,有n(n+1)/2 个子数列。原创 2016-06-10 19:05:03 · 1531 阅读 · 2 评论 -
《剑指offer》:[37]如何得到链表环的入口地址
题目:如何得到链表环的入口结点方案:分两步走:第一步:先要找到链表中的环,得到环的结点的个数。可以设置两个指针一个走的比较快,一个比较慢,那么如果链表中存在一个环,那么这两个指针一定会陷入这个环中,快的指针一定会遇到慢的指针,所以很快就能遇到。因为前面有详细讲过,这里不再多介绍。第二步:得到环的个数以后,我们照样可以设置两个指针。第一个指针先前进N(N为环中结点的个数)步,然后和第二个原创 2016-06-19 15:49:11 · 1682 阅读 · 0 评论 -
《剑指offer》:[42-1]左旋转字符串
题目二:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串尾部。请定义一个函数实现字符串左旋转功能。比如输入字符串"youareonly"和数字6,该函数将返回"onlyyouare"。由于有了面试【42】的经验和思路,我们可以这样来解决该问题。用三次翻转:第一步:把整个字符串分为两个部分,前N个要移动的字符和剩下的字符,先翻转前N个字符;"erauoyonly";第二步:再原创 2016-06-19 16:29:25 · 2049 阅读 · 0 评论 -
《剑指offer》:[42]翻转英文中单词顺序
题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。对字符串的操作,主要问题:一定要注意字符串为NULL和访问越界的情况!再就是找'\0'.例如输入字符串;"I love you.",经过翻转就变成:"you. love I"。看出来了吗,故意的,(不论语法)呵呵!方案一:两次翻转法。两次翻转法就是先对整个字符串进行翻转:".u原创 2016-06-19 16:27:05 · 2586 阅读 · 2 评论 -
《剑指offer》:[41-1]和为S的连续整数序列
输入一个正数S,打印出所有和为S的连续正数序列(至少含有两个数)。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出连续序列:1-5,4-6,7-8这三个序列.方案一:时间复杂度为O(N*N)。通过循环来求解。效率较低,不在多赘述。方案二:有了【41】的的经验方法后,我们可以用这样一种方法来得到连续整数序列。时间复杂度为O(N)。我们以S=9为例来分析其过程原创 2016-06-19 16:23:26 · 1423 阅读 · 0 评论 -
《剑指offer》:[41]数组中和为S的两个数
题目:输入一个递增排序的数组和一个数字S,在数组中查找两个数,是的它们的和正好是S。如果有多对数字的和等于S,输出其中的一对即可。例如输入数组{1,2,4,7,11,15}和数字15.由于4+11=15,因此输出4和11。方案一:时间复杂度为O(N*N)。顺序查找法,固定一个数,然后和剩余的N-1个数做和,看和是否为S;如没有,将固定的数下移一个,再与N-2个数字做和,看是否相等。很明显,原创 2016-06-19 16:19:56 · 2069 阅读 · 0 评论 -
《剑指offer》:[40]数组中只出现一次的数字
题目:一个整型数组里除了两个数字外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度为O(N),空间复杂度为O(1)。例如输入数组{2,4,3,6,3,2,5,5},因为只有4和6在这个数组里出现了一次,所以最后输出的是4,6。 分析:因为题目要求的时间复杂度和空间复杂度分别为:O(N)和O(1)。所以这个题目不能借助辅助空间,那么也就是要在一次遍历后就原创 2016-06-19 16:16:03 · 1542 阅读 · 0 评论 -
《剑指offer》:[7]两个队列实现栈的C++代码实现
问题:两个队列实现栈。 因为队列的特点是先进先出,而栈式先进后出。所以具体的实现步骤如下:(1)判断是否为NULL;如果queue1和queue2都为NULL,则该栈为NULL;(2)如果queue1不为NULL,而queue2为NULL;则queue1出队,进队到queue2,如果queue1的元素个数只剩一个的时候就出队输出,也就是出栈;反之亦然;(3)若果那个队列不为N原创 2016-05-26 11:21:02 · 1539 阅读 · 0 评论 -
《剑指offer》:[8]二维数组中的查找
解决问题:二维数组中的查找: 二维数组是一个比较常用的数据结构,主要由于其顺序存储,其下标引用的查找和访问的随机性优点尤其突出,使其在O(1)时间内就可以访问我们想要的位置数据。例如我们想要看第10个的数据内容,那么直接取a[9]就可以了,十分方便。但是它也有缺点,那就是插入和删除时效率较低,正因为其连续存储的数据结构,所以在每次插入和删除后都需要移动大量的数据。所以导致其效率比较原创 2016-05-30 15:20:55 · 607 阅读 · 0 评论 -
《剑指offer》:[9]字符串中替换空格
其实这个技巧可以使用于很多不同字符串的替换,不仅仅是空格的替换。可以是任意字母的替换。并且是N替换1。 例如:将字符串“This is my life!”中的空格替换为“%20”。 这个主要是因为在网络编程中,如果URL参数中含有特殊的字符,如空格,'#'等,可能导致服务器无法获得正确的参数值。我们需要将这些符号换成服务器识别的字符。转换规则为在‘%’的后面跟上ASCII码原创 2016-05-30 15:26:19 · 611 阅读 · 0 评论 -
《剑指offer》:[28]字符串的全排列问题
题目:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串:abc,acb,bac,bca,cab,cba.对于这样的题目,我可以将问题进行分解。把一个字符串看成两个部分。第一部分为它的第一个字符;第二部分为它的后面的所有字符。 首先求出所有可能在第一个位置的字符,即把第一个字符和后面的每个字符一次交换,得到所有可能在原创 2016-06-09 21:39:56 · 946 阅读 · 0 评论 -
《剑指offer》:[29]数组中出现数字超过一半的数字
对于一半的算法,如果能从额外空间消耗、平均时间复杂度和最差时间复杂度等方面分析问题,可以体现一个dev较好的编程素质和能力。-----刘景勇题目:数组中有一个数字出现的次数超过数组长度的一般,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2.方案一:先排序,后判断。因为数组没有排序,所以我们先原创 2016-06-09 21:45:50 · 813 阅读 · 0 评论 -
《剑指offer》:[30]最小的K个数问题
题目:输入N个整数,找出其中最小的k个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4.方案一:就是先对数组进行排序,然后输出前K个数字。时间复杂度为O(N*logN)方案二:根据[29]中数字超过一半的启发,我们可以用基于快速排序的思想,对其进行划分,时间复杂度为O(N)。找出前K小个元素,我们只需要利用Partion函数将小于X的前k个元素移动到X原创 2016-06-09 21:51:27 · 867 阅读 · 0 评论 -
《剑指offer》:[32]从1到n整数中1出现的次数
题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如输入12,从1到12共有1,10,11,12这四个数有1出现,且出现为5次。方案一:对每一个数字进行统计1的个数,然后相加。统计的方法就是对数取余法,看个位数上是否为1,。如果数大于10,则除10再取余数,看是否为1.该方法的缺点是:如果输入的n比较大,则计算量比较大。对于N个数,每个数有logN位,则其时间复杂度为原创 2016-06-10 19:11:42 · 887 阅读 · 0 评论 -
《剑指offer》:[33]把数组排成最小的数
题目:输入一个正整数数组,把数组里所有的数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这3个数字能排成的最小的数字是321323.这里由于是打印数组里所偶元素所能组成的最小的一个值,如果数组非常大,则有可能溢出,所以这是一个大数问题。大数问题的解决方案是数组或者字符串。这里我们将其转换为字符串。转规则:两个数字m和n能拼接成mn和nm原创 2016-06-10 19:14:16 · 681 阅读 · 0 评论 -
《剑指offer》:[50]树中两个结点的最低公共祖先结点
题目:树中两个结点的最低公共祖先该题目根据条件的不同,所使用的方案也不同。条件一:是二叉搜索树。 方案:这种情况相对来说是最简单的,如果是二叉搜索树,则树里的数据特点比较明显。左边的比根结点小,右边的比根结点大。所以其最低的公共结点就是第一个在这两个输入节点之间的结点。条件二:如果这棵树是一颗普通的树,可能连二叉树都不算,但是有指向父节点的指针。 方案:其实这个原创 2016-06-25 15:32:10 · 1286 阅读 · 0 评论 -
《剑指offer》:[49]把字符串转化成整数
题目:把字符串转换为整数,也就是实现atoi()。 类似还有itoa(),将整数数转化为字符串,相反的过程。此题虽然简单,但是就像高考一样,简单的题不一定能做对,能做对的不一定能得分。好吧,下面来看看一看应该注意的地方。易错点:1、判断字符串是否为NULL的情况(这是对字符串处理最基本得需要注意的地方)。2、如何区分字符串为NULL时返回的0还是字符'0'返回的0。原创 2016-06-25 15:24:13 · 2225 阅读 · 0 评论 -
《剑指offer》:[47]不用加减乘除做加法
题目:写一个函数,求两个整数的和,要求在函数体内不得使用+-*/四则运算。方案一:位运算。第一步:将数据转换为二进制,只将各位进行相加,不计算进位。第二步:做进位看进位的是多少;第三步:将第一步和第二部的结果相加。具体分析如下图:具体试下代码如下:#include using namespace std;int Add(int a,int b){ i原创 2016-06-25 11:42:36 · 1910 阅读 · 0 评论 -
《剑指offer》:[46]求1+2+3+...+n
题目:求1+2+3+4+.....+n,要求不能使用除法,for,while,if,else,switch,case等关键字及条件判断语句(A?B:C)。 看似一些不可能的问题,主要是考察我们的发散思维的能力,发散思维的特点是思维活动的多向性和变通性,也就是我们在思考问题时注重运用多思路、多方案、多途径第解决问题。像1+2+3+...+n的解决方法关键就在找到不用上述关键字如何实现递归原创 2016-06-25 11:38:50 · 1891 阅读 · 0 评论 -
《剑指offer》:[45]圆圈中最后剩下的数字(约瑟夫(Josephuse)环问题)
题目:0,1,2,3....N-1这N个数排成一个圆圈,从0开始每次从这个圆圈里删除第M个数字。求出这个圆圈里最后一个剩下的数字。例如0,1,2,3,4这五个数组成一个圆圈,从0开始每次删除第三个数,最后剩下的就是3.方案一:链表模拟环。这里我们将采用链表的数据结构来描述和解决问题。很明显其时间复杂度为O(M*N),空间复杂度为O(N),(M为删除的第几个元素);具体分析过程如下;原创 2016-06-25 11:33:54 · 2063 阅读 · 0 评论 -
《剑指offer》:[44]扑克牌的顺子
题目:从扑克牌里随机抽出5张牌,判断是不是一个顺子,即这五张牌是不是连续的。2-10为数字本身,A为1,J为11,Q为12,K为13,而大、小王可以看成是任意的数字。 分析:这里我们需要将扑克牌的背景抽象成计算机语言。首先,因为扑克牌也是数字,所以我们并不陌生,可以把5张牌看成由5个数字组成的数组。大小王看成是任意的数字,我们可以用0来表示,这样我们就用整形的数字表示了所有的牌。这样简原创 2016-06-25 11:28:48 · 1519 阅读 · 0 评论 -
《剑指offer》:[27]二叉搜索树与双向链表的转化过程
题目:输入一课二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。因为树的结构和循环链表的结构十分类似,所以使它们之间的转换成为了可能。具体方法:原先指向左子结点的指针调整为链表中指向前一节点的指针;原先指向右子结点的指针调整为链表中指向后一个结点的指针。因为要求转换之后的链表时排好序的,所以我们可以借助中序遍历。当遍历的时候我原创 2016-06-09 21:36:39 · 723 阅读 · 0 评论 -
《剑指offer》:[26]复杂链表的复制
题目;请实现函数ComplexListNode *Clone(ComplexListNode *pHead),复制一个复杂链表。在复杂链表中,每一个结点除了有一个m_pNext指针指向下一个结点外,还有一个m_pString指向链表中的任意结点或者NULL。复杂链表的结构如下:struct ComplexList{int data;ComplexList *pNext;Co原创 2016-06-09 21:27:17 · 686 阅读 · 0 评论