(java)剑指offer
总结剑指offer中的各种算法面试题
林胖子的私生活
这个作者很懒,什么都没留下…
展开
-
机器人运动范围
题目描述地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?解题思路和前面的矩阵中的路径类似,这个方格也可以看原创 2016-12-11 16:41:25 · 599 阅读 · 0 评论 -
矩阵中的路径
题目请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中任意一格开始,每一步可以在矩阵中间向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。举例分析 例如在下面的 3*4 的矩阵中包含一条字符串“bcced”的路径。但矩阵中不包含字符串“abcb”的路径,因为字符串的第一个字符 b 占据了矩阵中的第一行第二格子之后,路径原创 2016-12-11 16:32:41 · 1916 阅读 · 0 评论 -
滑动窗口的最大值
题目描述给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1原创 2016-12-11 16:12:57 · 363 阅读 · 0 评论 -
数据流中的中位数
题目描述如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。解题思路由于数据是从一个数据流中读出来的,数据的数目随着时间的变化而增加。如果用一个数据容器来保存从流中读出来的数据,当有新的数据流中读出来时,这些数据就插入到数据容器中。这个数据容器用什么数据结构定义更合适原创 2016-12-11 14:57:13 · 392 阅读 · 0 评论 -
二叉搜索树的第k个结点
题目给定一棵二叉搜索树,请找出其中的第k大的结点解题思路如果按照中序遍历的顺序遍历一棵二叉搜索树,遍历序列的数值是递增排序的。只需要用中序遍历算法遍历一棵二叉搜索树,就很容易找出它的第k大结点。 int count = 0; // 遍历计数 TreeNode KthNode(TreeNode pRoot, int k) { if(pRoot == null || k <=原创 2016-12-11 14:03:21 · 455 阅读 · 0 评论 -
序列化二叉树
题目描述请实现两个函数,分别用来序列化和反序列化二叉树我们知道可以从前序遍历和中序遍历构造出一棵二叉树。受此启发,我们可以先把一棵二叉树序列化成一个前序遍历序列和一个中序序列,然后再反序列化时通过这两个序列重构出原二叉树。这个思路有两个缺点。一个缺点是该方法要求二叉树中不能用有数值重复的结点。另外只有当两个序列中所有数据都读出后才能开始反序列化。如果两个遍历序列的数据是从一个流里读出来的,那就可能需原创 2016-12-11 13:51:22 · 372 阅读 · 0 评论 -
按之字形顺序打印二叉树
题目请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,即第一行按照从左到右的顺序打印,第二层按照从右到左顺序打印,第三行再按照从左到右的顺序打印,其他以此类推。上图按之字形打印的结果为: 1 3 2 4 5 6 7 15 14 13 12 11 10 9 8解题思路按之字形顺原创 2016-12-10 23:27:37 · 402 阅读 · 0 评论 -
把二叉树打印出多行
题目从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印一行。解题思路用一个队列来保存将要打印的结点。为了把二叉树的每一行单独打印到一行里,我们需要两个变量:一个变量表示在当前的层中还没有打印的结点数,另一个变量表示下一次结点的数目。 public static void print(BinaryTreeNode root) { if (root == null原创 2016-12-10 23:04:53 · 479 阅读 · 0 评论 -
对称二叉树
题目请实现一个函数来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。解题思路通常我们有三种不同的二叉树遍历算法,即前序遍历、中序遍历和后序遍历。在这三种遍历算法中,都是先遍历左子结点再遍历右子结点。可以定义一种遍历算法,先遍历右子结点再遍历左子结点.比如我们针对前序遍历定义一种对称的遍历算法,即先遍历父节点,再遍历它的右子结点,最后遍历它的左子结点。我们发现可以用过比较二叉原创 2016-12-10 22:57:41 · 480 阅读 · 0 评论 -
二叉树的下一个结点
题目给定一棵二叉树和其中的一个结点,如何找出中序遍历顺序的下一个结点?树中的结点除了有两个分别指向左右子结点的指针以外,还有一个指向父节点的指针。解题思路如果一个结点有右子树,那么它的下一个结点就是它的右子树中的左子结点。也就是说右子结点出发一直沿着指向左子结点的指针,我们就能找到它的下一个结点。接着我们分析一个结点没有右子树的情形。如果结点是它父节点的左子结点,那么它的下一个结点就是它的父结点。如原创 2016-12-10 22:49:16 · 360 阅读 · 0 评论 -
删除链表中重复的结点
题目在一个排序的链表中,如何删除重复的结点?解题思路解决这个问题的第一步是确定删除的参数。当然这个函数需要输入待删除链表的头结点。头结点可能与后面的结点重复,也就是说头结点也可能被删除,所以在链表头添加一个结点。接下来我们从头遍历整个链表。如果当前结点的值与下一个结点的值相同,那么它们就是重复的结点,都可以被删除。为了保证删除之后的链表仍然是相连的而没有中间断开,我们要把当前的前一个结点和后面值比当原创 2016-12-10 22:20:12 · 395 阅读 · 0 评论 -
链表中环的入口结点
题目描述一个链表中包含环,请找出该链表的环的入口结点。解题思路可以用两个指针来解决这个问题。先定义两个指针 P1 和 P2 指向链表的头结点。如果链表中环有 n 个结点,指针 P1 在链表上向前移动 n 步,然后两个指针以相同的速度向前移动。当第二个指针指向环的入口结点时,第一个指针已经围绕着环走了一圈又回到了入口结点。public ListNode EntryNodeOfLoop(ListNode原创 2016-12-10 22:09:41 · 335 阅读 · 0 评论 -
字符流中第一个不重复的字符
题目:请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符“go”时,第一个只出现一次的字符是‘g’。当从该字符流中读出前六个字符“google”时,第一个只出现 1 次的字符是”l”。解题思路字符只能一个接着一个从字符流中读出来。可以定义一个数据容器来保存字符在字符流中的位置。当一个字符第一次从字符流中读出来时,把它在字符流中的位置保存到数据容器里。当这个字符再原创 2016-12-10 01:03:00 · 401 阅读 · 0 评论 -
表示数值的字符串
题目描述请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100”,”5e2”,”-123”,”3.1416”和”-1E-16”都表示数值。 但是”12e”,”1a3.14”,”1.2.3”,”+-5”和”12e+4.3”都不是。各种判断的写法public static boolean isNumeric(String string) { if (strin原创 2016-12-10 00:54:49 · 309 阅读 · 0 评论 -
正则表达式匹配
题目描述请实现一个函数用来匹配包括’.’和’‘的正则表达式。模式中的字符’.’表示任意一个字符,而’‘表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串”aaa”与模式”a.a”和”ab*ac*a”匹配,但是与”aa.a”和”ab*a”均不匹配分析当模式中的第二个字符不是“*”时:如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模原创 2016-12-10 00:42:55 · 520 阅读 · 0 评论 -
构建乘积数组
题目描述给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…A[i-1]*A[i+1]…*A[n-1]。不能使用除法。如果没有除法限制,可以连乘到n-1得到B[i],显然这个方法需要O(n2)的时间更高效的解法可以把B[i]=A[0]A[1]…A[i-1]*A[i+1]…A[n-1]看成A[0]*A[1]…A[i-1]和A[i+1]原创 2016-12-09 20:11:07 · 507 阅读 · 0 评论 -
数组中重复的数字
题目描述在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3。两种简单思路思路1:只需要从头到尾扫描排序后的数组就可以了。排序一个长度为 n 的数组需要 O(nlogn)的时间。思路2:原创 2016-12-09 19:46:44 · 348 阅读 · 0 评论 -
树中两个结点的最低公共祖先
题目:求树中两个结点的最低公共祖先,此树不是二叉树,并且没有指向父节点的指针。分析假设还是输入结点 F 和 H。 我们首先得到一条从根结点到树中某一结点的路径,这就要求在遍历的时候,有一个辅助内存来保存路径。比如我们用前序遍历的方法来得到从根结点到 H 的路径的过程是这样的:( 1 )遍历到 A,把 A 存放到路径中去,路径中只有一个结点 A;( 2 )遍历到 B,把 B 存到路径中去,此时路径为原创 2016-12-08 19:59:48 · 420 阅读 · 0 评论 -
把字符串转换成整数
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0 几个特殊情况数据上下 溢出空字符串只有正负号有无正负号错误标志输出 boolean flag = false; public int StrToInt(String str) { if(str ==null ||str.length()==0){原创 2016-12-08 19:16:02 · 426 阅读 · 0 评论 -
求1+2+3+...+n
题目:求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 //&&如果为false 不会进行下一步 public int Sum_Solution(int n) { int sum = n; boolean ans = (n>0)&&((sum+=Sum_Solution(n-1原创 2016-12-08 17:32:44 · 455 阅读 · 0 评论 -
约瑟夫环问题
题目:0, 1, … , n-1 这 n 个数字排成一个圈圈,从数字 0 开始每次从圆圏里删除第 m 个数字。求出这个圈圈里剩下的最后一个数字。解题思路第一种:经典的解法, 用环形链表模拟圆圈。 创建一个总共有 n 个结点的环形链表,然后每次在这个链表中删除第 m 个结点。时间复杂度高达O(nm)public static int lastRemaining(int n, int m) {原创 2016-12-08 15:21:08 · 347 阅读 · 0 评论 -
扑克牌顺子
题目:从扑克牌中随机抽 5 张牌,判断是不是一个顺子, 即这 5 张牌是不是连续的。2~10 为数字本身, A 为 1。 J 为 11、Q 为 12、 为 13。小王可以看成任意数字。解题思路我们可以把 5 张牌看成由 5 个数字组成的数组。大、小王是特殊的数字,我们不妨把它们都定义为 0,这样就能和其他扑克牌区分开来了。接下来我们分析怎样判断 5 个数字是不是连续的,最直观的方法是把数组排序。值得原创 2016-12-08 14:34:03 · 598 阅读 · 0 评论 -
n个骰子的点数
题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s。输入n,打印出所有可能的值的概率方法一:递归思路:设n个骰子某次投掷点数和为s的出现次数是F(n, s),那么,F(n, s)等于n - 1个骰子投掷的点数和为s - 1、s - 2、s - 3、s -4、s - 5、s - 6时的次数的总和:F(n , s) = F(n - 1, s - 1) + F(n - 1, s - 2) + F(n原创 2016-12-08 14:27:51 · 315 阅读 · 0 评论 -
翻转字符串VS左旋转字符串
题目例如输入 I am a student. 则输出 student. a am I思路 翻转两次第一步翻转句子中所有字符,比如翻转 I am a student. 中的字符串为 .tneduts a ma I ,此时不但翻转了句子,单词也翻转了在翻转每个单词,翻转单词的时候扫描空格来确定单词的起始位置和终止位置 public String ReverseSentence(String st原创 2016-12-07 20:37:07 · 355 阅读 · 0 评论 -
和为s的两个数字VS和为s的连续正数序列
题目一: 输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。第一直觉是想到O(n2)的方法,也就是先固定一个数字,然后再判断数组中其余n-1数字的和与它的和是不是等于s,但并不是最好的方法更好的算法,我们现在数组中选择两个数字,如果他们的和等于输入s,我们就找到,如果小于s,我们希望两个数字比s大,由于数组是排好序的,可以选择原创 2016-12-07 19:15:18 · 429 阅读 · 0 评论 -
数组中只出现一次的2个数
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。思路是异或操作首先数组中所有元素依次异或,因为相同的元素异或得到0,所以最终的答案就等于那2个唯一的元素a^b的值。因为a,b不同,所以异或得到的答案肯定是不等于0的,那么我们就找到a^b的二进制表示中第一个为1的位,假如是第k位。而a,b两个数在第k原创 2016-12-07 18:49:49 · 424 阅读 · 0 评论 -
二叉树深度和判断平衡二叉树
题目描述 输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。思路:比较左右子树深度值,返回较大的那一个 public int TreeDepth(TreeNode root) { if(root==null){ return 0; } int nLeft原创 2016-12-07 14:08:11 · 476 阅读 · 0 评论 -
数字在排序数组中出现的次数
题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4.思路1:因为是排序很好的想到是二分查找,先知道一个3,然后两边顺序查找,分别找到第一个3和最后一个3,以为数字在长度为n的数组中可能出现O(n)次,所以顺序查找的时间复杂度位O(n).思路2:更高效的利用二分查找,在当前是3的左右两边有可能还有3(根据前边或原创 2016-12-07 10:30:49 · 329 阅读 · 0 评论 -
两个链表的第一个公共节点
题目描述 输入两个链表,找出它们的第一个公共结点。如果两个单向链表有公共的结点,也就是说两个链表从某一结点开始,它们的m_pNext都指向同一个结点。但由于是单向链表的结点,每个结点只有一个m_pNext,因此从第一个公共结点开始,之后它们所有结点都是重合的,不可能再出现分叉。所以,两个有公共结点而部分重合的链表,拓扑形状看起来像一个Y,而不可能像X。思路1:采用蛮力的方法:在第一个链表上顺序遍历原创 2016-12-05 21:28:07 · 778 阅读 · 0 评论 -
数组逆序对
题目:在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4)。最直观的解法: 最简单的想法就是遍历每一个元素,让其与后面的元素对比,如果大于则count++,但是这样的时间复杂度是o(n2)。先把数组分解成两个长度为2的子原创 2016-12-05 20:24:19 · 429 阅读 · 0 评论 -
第一个只出现一次的字符
题目:在字符串中找到第一个只出现一次的字符。如输入“abaccdeff”,则输出’b’.最直观的做法是,从头开始扫描这个字符串的每个字符。当访问到某个字符时拿这个字符和后面的每个字符相比较,如果在后面没有出现重复的字符,则该字符就是只出现一次的字符。如果字符串有n字符,每个字符可能与后面的O(n)个字符相比较,因此这种思路的时间复杂度是O(n2)。我们可以统计每个字符在该字符串中出现的次数?要达到这原创 2016-12-04 19:59:59 · 526 阅读 · 0 评论 -
找出丑数
题目:我们只把因子为2、3和5的数称为丑数。求按从小到大的顺序把第1500个丑数。例如6、8都是丑数,但14不是,因为它包含因子为7,习惯上吧1当做第一个丑数直观解法所谓一个数m是另一个n的因子,是指n能被m整除,也就是n%m==0。int GetUglyNumber(int index){ int(index<=0){ return 0; } int number=0; int ugl原创 2016-12-04 14:59:18 · 608 阅读 · 0 评论 -
把数组排成最小的数
输入一个正整数,把数组里所有数字拼接起来排成一个数,打印能拼接处的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这3个数字能拍成的最小数字321323最直接的做法是先求数组中的全排列,然后每个排列拼接,但是如果n个数字共有n!的排列正确解法,确定一个排序规则,比较两个数字,同时考虑大数问题 public String PrintMinNumber(int [] numbers)原创 2016-12-03 15:05:17 · 406 阅读 · 0 评论 -
从1到n整数中1出现的次数
题目:输入一个整数n,求从1到n这个n个整数的十进制表示中1出现的次数。例如输入12,从1到12这些整数中包含1的数字有1,10,11和12,1一共出现了5次,如果不考虑时间复杂度的做法 public int NumberOf1Between1AndN_Solution(int n) { int number=0; for(int i=1;i<=n;i++){原创 2016-12-03 14:43:51 · 388 阅读 · 0 评论 -
连续子数组的最大和
题目输入要给整形数组,数组里有正数也有负数。数组中一个或连续的多个整数组成一个子数组。求所以子数组的和的最大值。要求时间复杂度为O(n)例如输入数组为{1,-2,3,10,-4,7,2,-5}和最大的子数组为{3,10,-4,7,2},因此输出为该子数组的和为18如果枚举数组中所有的子数组并求和。一个长度为n的数组,总共有n(n+1)/2个子数组。计算出所以子数组的和,最快也需要O(n2)时间解法1原创 2016-12-01 21:51:31 · 331 阅读 · 0 评论 -
最小的k个数
题目描述输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 解法1:O(n)的算法,只有当我们可以修改输入的数组时可用 如果基于数组的第k个数字来调整,使得比第K个数字小的所有数字都位于数组的左边,比第k个数字大的所有数字都位于数组的右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数字(这k个数字不一定是排序的)。原创 2016-12-01 20:50:37 · 357 阅读 · 0 评论 -
数组中出现次数超过一半的数字
题目描述数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。看到这个题直观想法就是去排序,如果是排好序的数组,那么我们就能很容易统计出每个数字出现的次数。排序的时间复杂度是O(nlogn),最直观的算法通常不能让面试官满意基于Partition原创 2016-12-01 19:50:34 · 387 阅读 · 0 评论 -
字符串的排列
题目描述输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。思路从字符串数组中每次选取一个元素,作为结果中的第一个元素。然后,对剩余的元素全排列,步骤跟上面一样。很明显这是个递归处理的过程,一直到最后即可。 public static ArrayList<String> P原创 2016-11-29 20:25:00 · 323 阅读 · 0 评论 -
二叉搜索树与双向链表
题目描述输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。实现思路在二叉搜索树中,每个结点都有两个分别指向其左、右子树的指针,左子树结点的值总是小于父结点的值,右子树结点的值总是大于父结点的值。而在双向链表中,每个结点也有两个指针,它们分别指向前一个结点和后一个结点。所以这两种数据结构的结点是一致,二叉搜索树之所以为二叉搜索树,双向链表原创 2016-11-29 19:58:40 · 377 阅读 · 0 评论 -
复杂链表的复制
题目描述输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。、如图 是一个含有 5 个结点的复杂链表。图中实线箭头表示 next 指针,虚线箭头表示 sibling 指针。为简单起见,指向 null 的指针没有画出。 在不用辅助空间的情况下实现 O(n)的时间效率。思路:根据原始链表的每个结点N 创建原创 2016-11-23 20:05:03 · 460 阅读 · 0 评论