
剑指offer
文章平均质量分 63
凌澜星空
这个作者很懒,什么都没留下…
展开
-
剑指offer代码解析——面试题31连续子数组的最大和
题目:输入一个整型数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所有子数组和的最大值。要求时间复杂度为O(n)分析:统计连续子数组的最大值最直观的方法就是遍历数组n次,每次以a[i]作为子数组的起点,然后将a[i]后面的数字依次纳入数组中,计算最大值。这种方式的时间复杂度为O(n^2),显然不符合要求。下面我们根据数组自身的特点来统计连续子数组原创 2016-03-16 10:51:57 · 780 阅读 · 0 评论 -
剑指offer代码解析——面试题14调整数组顺序使奇数在偶数之前
本题详细解析都已在代码中注释了/** * 题目:输入一个数组,要求将奇数放在数组的前半段,偶数放在数组的后半段 * @author 大闲人柴毛毛 */public class Reorder { /** * 分析:本题只要求前半段为奇数,后半段为偶数,没有要求有序, * 因此可以采用快速排序中一趟排序的思想: * 使用两个指针i、j,i指向头、j指向尾,分别向后、向前扫原创 2016-03-13 13:02:19 · 579 阅读 · 0 评论 -
剑指offer代码分析——面试题13在O(1)内删除链表结点
本题详细的思路都已在代码中注释/** * 给一个单链表,头指针为first,请用O(1)时间删除其中节点p * @author chibozhou */public class DeleteNode { /** * 分析: * 删除单链表中的某一节点常规做法是: * 从头开始扫描单链表,找到p节点的前一个节点q,然后做以下操作: * q.next = p.next原创 2016-03-13 09:43:39 · 775 阅读 · 0 评论 -
剑指offer代码解析——面试题15求链表中倒数第K个结点
算法的分析过程均在代码注释中:/** * 题目:输入一个单链表,输出该链表从后往前的第k个数。 * PS:从后往前数时从1开始计数。 * @author 柴毛毛大闲人 */public class TailK { /** * 分析:要寻找倒数第k个数,很自然想到的方法是:从末尾向前找第k个数。 * 然而这种方法面临两个问题:1.我们无法直到单链表的末尾在哪儿,2.我们无原创 2016-03-13 20:32:10 · 638 阅读 · 0 评论 -
剑指offer代码解析——面试题17合并两个排序的链表
分析:我们把两个单链表分为a1、a2,每次从a2中取出头结点,然后在a1中寻找插入点插入,重复上述操作直到a2中结点被取光为止。原创 2016-03-14 10:55:49 · 665 阅读 · 0 评论 -
剑指offer代码解析——面试题16反转单链表
分析:本题是要将链表“反转”,而不是反向输出,这点要特别注意。 反转需要改变链表的结构,使所有指针都指向相反方向;而反向输出不需要改变链表结构,只需反向输出即可。对于反向问题可使用栈来实现,可参见我的博客《剑指offer——面试题5》,这里不再赘述。下面来解决反转问题。 反转单链表其实就是将链表中的指针指向相反方向,若a1和a2是单链表中两个相邻的结点,未反转前的状态是:a1.next = a2,现在进行反转:a2.next = a1. 此时,虽然a2指向了a1,但链表出现了“断裂”,a2和它的后继结点发生原创 2016-03-14 09:54:33 · 693 阅读 · 0 评论 -
剑指offer代码解析——面试题19二叉树的镜像
分析:所谓“镜像”就是从镜子里看到的样子。我们可以画一棵二叉树,然后画出该二叉树的镜像。画完图之后我们会发现,所谓“二叉树的镜像”就是把二叉树中所有子树的左孩子和右孩子进行交换。因此需要遍历二叉树所有的结点,在遍历的同时交换非叶子结点的左右子树。遍历我们可以使用先序遍历,首先判断当前根结点是否为叶子结点,若非叶子结点,则交换左右孩子,然后再分别对左右孩子进行相同的操作。 首先,我们需要原创 2016-03-14 14:47:04 · 741 阅读 · 0 评论 -
剑指offer代码解析——面试题21包含min函数的栈
分析:要获取栈的最小值,我们首先想到的思路就是使用一个全局变量记录最小值,当元素进栈时和该全局变量进行比较,若小于该全局变量,则更新最小值。这种方法有个致命的缺陷:如果这个最小值出栈了,那么当前栈的最小值该如何确定? 解决办法:我们可以再创建一个栈b,栈b的高度始终与栈a保持一致,栈顶元素保存当前栈a的最小值。 入栈:当元素入栈a后,该元素与栈b的栈顶元素进行比较,若小于栈原创 2016-03-14 19:19:25 · 796 阅读 · 0 评论 -
剑指 offer代码解析——面试题37两个链表的第一个公共结点
题目:输入两个链表,找出他们的第一个公共结点。分析:本题最直观的思路就是:顺序遍历第一个链表,每遍历第一个结点的时候,再顺序遍历第二个链表,寻找相同的结点。假设两个链表的长度分别为n和m,那么这种方法的时间复杂度为O(n*m)。下面我们寻找更为高效的方法。原创 2016-03-25 13:12:21 · 830 阅读 · 1 评论 -
剑指offer代码解析——面试题22栈的压入、弹出序列
题目:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为栈的弹出顺序。 栈的特点是不管入栈还是出栈,都只能对栈顶元素进行操作。一个序列如果依次入栈,再依次出栈的话,序列将会被逆序输出。但如果在入栈的过程中随机停止入栈操作,紧接着随机出栈n个元素,这样出栈顺序将会千变万化。本题就是要求判断某一个数组是否属于指定入栈序列的出栈序列。通过上述分析,最直观的方法就是穷举法,将一个入栈序列的所有出栈序列均罗列出来,然后判断这些序列中是否含有指定的出栈序列。由于穷举法需要大量的时间、空间原创 2016-03-15 15:51:37 · 989 阅读 · 0 评论 -
剑指offer代码解析——面试题23从上往下打印二叉树
分析:学过数据结构便可知,本题实则为宽度优先遍历二叉树。在数据结构中,深度优先遍历一棵二叉树有三种方式:先序遍历、中序遍历、后序遍历。他们均可采用递归,代码非常简洁。而宽度优先遍历二叉树可采用迭代,并借助一个辅助的队列来存储尚未遍历的结点,下面是详细过程。原创 2016-03-15 15:54:04 · 739 阅读 · 0 评论 -
剑指offer代码解析——面试题24二叉搜索树的后序遍历序列
题目:输入一个整数数组,判断该数组书不是某二叉搜索数的后序遍历的结果。如果是返回true,否则返回false。假设输入的数组的任意两个数字都互不重复。分析:看过题目后本题最直观的思路就是通过后序遍历序列还原这棵二叉树,然后判断该二叉树是否为二叉搜索树。然而学过数据结构就会知道,如果给一棵二叉树的中序遍历和后序遍历序列,就能唯一确定一棵二叉树。但本题只给了后序遍历序列,因此无法唯一确定这棵树。那么,我们能否通过后序遍历序列把所有可能的二叉树都罗列出来,然后从中寻找是否有二叉搜索树存在。这种穷举的方法需要时间原创 2016-03-15 15:57:32 · 690 阅读 · 0 评论 -
剑指offer代码解析——面试题25二叉树中和为某一值的路径
题目:输入一棵二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。分析:要找出路径之和为指定整数的路径,就需要遍历二叉树的所有路径。此外,由于路径是指根结点到叶子结点的线段,因此我们想到采用深度优先的方式遍历二叉树。深度优先算法又分为:先序遍历、中序遍历、后序遍历,其中先序遍历符合我们的要求。首先需要创建一个栈,用来保存当前路径的结点。采用先序遍历算法遍历结点时,先将途中经过的结点均存入栈中,然后判断当前结点是否为叶子结点,若不是叶子结点的话,则递归遍历该结点的左孩子和右孩子;若是叶子结点的原创 2016-03-15 16:57:46 · 605 阅读 · 0 评论 -
剑指 offer代码解析——面试题34丑数
题目:我们把只包含因子2、3、5的数称为丑数。求从小到大顺序第1500个丑数。习惯上把1称为第一个丑数。分析:所谓“只包含因子2、3、5”其实就是只能由2、3、5相乘得到的数称为丑数。根据上述特性,丑数的生产过程如下:从1开始,分别乘以2、乘以3、乘以5,得到三个新的丑数2、3、5; 然后再把这三个新的丑数再分别乘以2、乘以3、乘以5,得到9个丑数4、6、10、6、9、15、10、15、25;循环上述操作,就能源源不断地生产丑数。原创 2016-03-24 09:04:25 · 1483 阅读 · 1 评论 -
剑指 offer代码解析——面试题35第一个只出现一次的字符
题目:在字符数组中找出第一个只出现一次的字符。分析:本题最直观的思路是从头到尾扫描数组,假设当前扫描的字符为a[i],若尚未统计a[i]出现的次数的话,则从a[i]开始,向后统计a[i]出现的次数。这种方式需要扫描数组n次,且每次还需要进行n次扫描统计a[i]出现的次数,因此时间复杂度为O(n^2)。是否有更高效的方法呢?原创 2016-03-24 08:57:50 · 898 阅读 · 2 评论 -
剑指offer代码解析——面试题25二叉树中和为某一值的路径
题目:输入一棵二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。PS:从根结点开始,一直到叶子结点形式一条路径。分析:要找出路径之和为指定整数的路径,就需要遍历二叉树的所有路径。此外,由于路径是指根结点到叶子结点的线段,因此我们想到采用深度优先的方式遍历二叉树。深度优先算法又分为:先序遍历、中序遍历、后序遍历,其中先序遍历符合我们的要求。原创 2016-03-16 10:58:33 · 811 阅读 · 0 评论 -
剑指 offer代码解析——面试题29数组中出线次数超过一半的数字
题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。分析:本题最直观的思路就是分别统计数组中每个数出现的次数,然后求出最大值,判断是否超过数组长度的一半。这种方法的时间复杂度为O(n^2),在面试中,第一反应想到的方法往往不是最佳答案,下面我们来寻求更加高效的方式。一个数出现的次数如果超过数组长度的一半,那么可以得出以下结论:1.如果把超原创 2016-03-16 18:29:35 · 862 阅读 · 0 评论 -
剑指offer面试题7——用两个栈实现队列
package offer7;import common.Stack;/** * 用两个栈实现一个队列 * @author chibozhou */public class Queue { //队列当前大小 private int curSize; //队列最大容量 private int maxSize; //两个栈 private Stack stack1; pr原创 2016-03-05 18:17:15 · 1312 阅读 · 2 评论 -
剑指offer——快速排序
快速排序是目前所有排序中性能较好的一种算法,最好情况和平均情况下时间复杂度均为O(nlogn),最坏的情况下时间复杂度为O(n^2)。快速排序采用递归,用空间换取时间。由于使用了递归,因此需要额外的存储空间。 快速排序由三个函数构成,分别为QuickSort(int[] arr)、QuickSort(int[] arr,int start,int end)、partition(i原创 2016-03-06 15:45:32 · 2571 阅读 · 1 评论 -
剑指offer——年龄排序问题
题目:对某公司所有员工的年龄进行排序,要求时间复杂度为O(n)分析: 在已有的排序算法中,性能最好的是快速排序,但是他在最好的情况下时间复杂度只能达到O(nlogn),无法满足本题的要求。但是我们可以从“年龄”这一特殊条件入手。 年龄具有显著的特征,那就是这些数值都分布在0-99之间。由于待排序的数值均在0-99这个固定区间内,因此我们可以用一个长度为100原创 2016-03-06 16:17:41 · 2240 阅读 · 0 评论 -
剑指 offer——面试题8求旋转数组的最小值
题目:将一个非递减序列的某一处切一刀,再把前半段序列放到后半段序列的后面,这样组成的新序列叫做“旋转数组”。要求获取一个旋转数组的最小值。这本质上是一个求最值的问题,最简单的方法就是顺序遍历数组,从中找出最小值,该方法的时间复杂度为O(n)。但这种方法会被面试官鄙视的,所以我们寻找更为高效的办法。这道题给的数组是一个“旋转数组”,旋转数组是将一个非递减数组切成两个数组后重新组装而成的,旋转原创 2016-03-07 10:25:28 · 959 阅读 · 0 评论 -
剑指 offer代码解析——面试题39二叉树的深度
题目:输入一颗二叉树的根结点,求该树的深度。从根结点到叶结点一次经过的结点形成树的一条路径,最长路径的长度为树的深度。分析:本题是一道典型的“分治法”。要求一棵二叉树的高度,我们可以将问题分解,先分别求左右子树的高度,然后取较大值加一即为整棵二叉树的高度。接下来按照这种思路继续求左右子树的高度,直到子树为叶子结点时,此时树(即叶子结点)的高度为1。/** * 题目原创 2016-03-31 18:59:25 · 1030 阅读 · 0 评论 -
剑指offer——面试题9计算斐波纳切第n个数
/** * 计算斐波纳切数列的第n个值 * @author chibozhou * */public class Fibonacci { /** * 分析:斐波纳切数列的第n个数的值是其前两个数之和, * 因此要计算第n个数就需要计算其前两个数, * 以此类推,直到计算出第0个数为止, * 因此可以使用递归。 */ /** * 采用递归的方法 */原创 2016-03-08 20:24:19 · 2406 阅读 · 0 评论 -
剑指offer——面试题10输入一个十进制整数,统计其中二进制1的个数
/** * 题目:输入一个十进制整数,统计其中二进制1的个数 * @author 大闲人柴毛毛 */public class CountBitOne { /** * 这个问题最直观的思路: * 将输入的整数转换成二进制数, * 再把这个二进制数转换成字符数组, * 最后遍历数组,统计1的个数。 * * 使用数组需要开辟额外的内存空间, * 若在不能使用Jav原创 2016-03-09 16:42:06 · 3080 阅读 · 2 评论 -
剑指 offer代码解析——面试题39判断平衡二叉树
题目:输入一颗二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的高度相差不超过1,那么它就是一棵平衡二叉树。分析:所谓平衡二叉树就是要确保每个结点的左子树与右子树的高度差在-1到1之间。由于之前一题已经给出了二叉树高度的计算方法,因此本题最直观的思路就是分别计算每个结点的左子树高和右子树高,从而判断一棵树的所有结点是否均为平衡二原创 2016-04-02 12:11:00 · 1810 阅读 · 4 评论 -
剑指 offer代码解析——面试题39判断平衡二叉树(高效方法)
题目:输入一颗二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的高度相差不超过1,那么它就是一棵平衡二叉树。分析:所谓平衡二叉树就是要确保每个结点的左子树与右子树的高度差在-1到1之间。由于之前一题已经给出了二叉树高度的计算方法,因此本题最直观的思路就是分别计算每个结点的左子树高和右子树高,从而判断一棵树的所有结点是否均为平衡二原创 2016-04-02 16:32:44 · 2591 阅读 · 0 评论 -
剑指 offer代码解析——面试题26复杂链表的复制
分析:复制单链表较为简单,只需遍历单链表,创建结点,同时将前后连个结点相继连起来即可。本题的难点在于:每个结点还有一个sibling域,指向链表的任意一个结点。本题最直观的思路有两种:1.先复制单链表,然后再复制sibling域;2.在复制单链表的同时确定sibling域名。第一种方法较为简单,复制完单链表后需再次遍历原链表,若当前结点的sibling域不为空,则从当前结点开始依次向后查找sibling域指向的位置,我们可以用一个计数器count记录当前结点与sibling域指向的结点直接的距离,然后在新链原创 2016-03-21 15:21:02 · 974 阅读 · 2 评论 -
剑指 offer代码解析——面试题32统计1到n中1出现的次数
题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。分析:本题常规思路如下:从1开始遍历这n个数,分别统计每个数中“1”出现的次数。那么,问题就转化为“如何统计一个整数中1出现的次数?”首先我们需要知道以下结论: * 1.设整数为n,则n%10就能取到n的个位数; * 2.n除以10后再取整其实就是把n的个位数砍掉。基于上述结论,我们只要循环以下操作即可: * 1.求整数n的余数; * 2.判断余数是否为1,若为1则将计数器加1; * 3.重复上述过程,直到n变原创 2016-03-22 12:14:13 · 1121 阅读 · 1 评论 -
剑指 offer代码解析——面试题38数字在排序数组中出现的次数
题目:统计一个有序数组中K出现的次数。分析:本题最直观的思路就是遍历数组,统计K出现的次数即可。这种方式的时间复杂度为O(n)。下面我们充分利用“有序数组”这一条件,提高算法的时间效率。对于一个有序数组,所有的数字K一定都集中在一起,因此只要我们找到这一组K的头和尾就能知道K出现的次数。此时问题就转化为:在一个有序数组中寻找某个数字。我们很自然地就想到了二分原创 2016-03-26 09:09:45 · 1058 阅读 · 1 评论