剑指offer-java实现
hutongling
知行合一!
展开
-
猴子下山摘桃
/* *题目描述: * 小猴子下山,沿着下山的路有一排桃树,每棵树都结了一些桃子。小猴子想摘桃子,但是有一些条件需要遵守,小猴子只能沿着下 * 山的方向走,不能回头,每颗树最多摘一个,而且一旦摘了一棵树的桃子,就不能再摘比这棵树结的桃子少的树上的桃子。那么小 * 猴子最多能摘到几颗桃子呢?举例说明,比如有5棵树,分别结了10,4,5,12,8颗桃子,那么小猴子最多能摘3颗桃子,来原创 2017-08-21 19:59:00 · 3241 阅读 · 1 评论 -
数组中出现次数超过一半的数字
题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。分析: 方法1:复杂度为O(n^2),从第二个数字开始分别与该数字前面的数字相比较,如果一样的话就将其次数加一,不一样的话就将其次数置为1,并比较该次数是否大于数组长度的一半,如果大于的话就输出该数字。 方法2:先对数组进行排序,然后取位于中间的那个数字即出现次数大于数组长度的一半的数字。 方法三:因为数字出现的次数大于数组长原创 2017-03-24 09:15:14 · 259 阅读 · 0 评论 -
八皇后问题(由字符串排列问题拓展)
题目:在8x8的国际象棋上摆放着8歌皇后,使其不能互相攻击,即任意两个皇后不得处在同一行,同一列或者同一条对角线上。如下图,请问一共有多少中符合条件的摆法? 分析:八皇后问题其实可以看做字符串排列问题的一种扩展,先将0~7个数进行排列,然后从这么多个排列中选择出条件符合的情况保留下来。思路:先遍历出所有的情况,不论是符合条件的还是不符合条件的,然后再筛选由于8个皇后的任意两个不能处于同一行,那么说原创 2017-03-23 20:06:34 · 481 阅读 · 0 评论 -
字符串排列问题拓展
题目: 解决思路:先将8个数字的数组的排列都找出来,然后判断三对相对面上的顶点之和是否相等,如果相等的话就保留下来,如果不相等就不要。字符串排列问题在这里:字符串排列问题 代码如下:/** * */package problem2;import java.util.ArrayList; import java.util.List; /** * @author Hutonglin原创 2017-03-23 19:58:06 · 268 阅读 · 0 评论 -
字符串的排列
题目:输入一个字符串,打印该字符串中字符的所有排列。例如输入abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab,cba六种。分析:该题可以使用递归的方法解决。先可以创建一个集合类用于保存结果,同时创建一个集合类用于保存中间的临时结果。对于字符串我们先从头到尾访问字符串中的每个元素,对于访问到的元素,我们先在字符串中删除该元素,并把该元素加入到临时结果中去,原创 2017-03-23 19:51:36 · 323 阅读 · 0 评论 -
n个色子的点数
题目:把n个色子扔在地上,所有色子朝上以免的点数之和为S.输入n,打印出所有可能的值出现的概率。分析: 方法1:基于递归求色子点数,时间效率不高先把n个色子分成两堆:第一堆只有一个,另一对有n-1个。d单独的那个有可能出现从1到6的点数。我们需要计算从1到6的每种点数和剩下的n-1个色子来计算点数和。接下来把剩下的n-1个色子还是分成两堆,1,和n-2。我们把上一轮那个单独色子的四岸数和这一轮单独原创 2017-03-30 20:20:31 · 602 阅读 · 0 评论 -
字符串的左旋转
题目:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如输入字符串“abcdefg”和数字2,改函数将返回左旋转2位得到的结果为“cdefgab”.分析:只需要将字符串进行三次翻转即可,第一次将字符串完全翻转,第二次将第一步得到的结果前length-k个字符串翻转,第三次将第二步得到的结果的后k个字符翻转。代码如下:/** * 题目:字符原创 2017-03-30 14:59:01 · 401 阅读 · 0 评论 -
翻转句子(单词内部顺序不变)
题目:输入一个英文句子,翻转句子中的单词的顺序,但是单词内的字符顺序不变。为简单起见, 标点符号和普通字母一样处理。例如输入:“I am a student. ”,输出“student. a am I”分析:在这里可以考虑使用集合类list来做,先将字符串分割成一个个单词,然后分别添加到集合类的最前面,然后从头遍历集合类就可以。/** * 题目:输入一个英文句子,翻转句子中的单词的顺序,但是单词原创 2017-03-30 14:24:05 · 391 阅读 · 0 评论 -
和为s的连续正数序列
题目:题目:输入一个正数s,打印出所有的和为s的连续正数序列(至少含有两个数)。例如输入15,由于1+2+3+4+5=4+5+6=7+8,所以结果打印出3个连续序列1~5,4~6,7~8分析:考虑使用small和big分别表示序列的最小值和最大值,small初始化为1,big初始化为2.计算small到big之间的数的和。如果从small到big的序列和大于s的话就将small增大,如果等于s的话就原创 2017-03-30 11:33:35 · 256 阅读 · 0 评论 -
扑克牌的顺子
题目:从扑克牌中随机抽取5张牌,判断是不是一个顺子,即这5张P牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大小王可以看成任意数字。代码:/** * 题目:从扑克牌中随机抽取5张牌,判断是不是一个顺子,即这5张P牌是不是连续的。2~10为 * 数字本身,A为1,J为11,Q为12,K为13,而大小王可以看成任意数字。 */package problem2;/**原创 2017-03-31 11:17:33 · 284 阅读 · 0 评论 -
约瑟夫环
题目:0,1,2,3,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈中删除第m个数字。求这个圆圈中剩下的最后一个数字。 这个问题就是约瑟夫环问题。代码:/** * 题目:0,1,2,3,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈中删除第m个数字。求这个圆圈中剩下的最后一个数字。 * 这个问题就是约瑟夫环问题。 */package problem2;import jav原创 2017-03-31 13:40:24 · 244 阅读 · 0 评论 -
最小的k个数
题目:给定一个数组,请找出数组中最小的k个数。分析:可以使用快速排序算法中的一部分加以改造利用。如果基于数组的第k个数来调整,使得比第k个数字小的所有数字都位于数组的左边,比第k个数大的数字都位于数组的右边。这样调整之后,位于数组中左边的k个数字就是最小的k个数(不一定有序)代码如下:import java.util.Set;import java.util.TreeSet;/** * @aut原创 2017-03-24 11:11:46 · 266 阅读 · 0 评论 -
1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 输入: 输入可能包含多个测试样例。 对于每个测试案例,输入为一个整数n(1<= n<=100000)。 输出: 对应每个测试案例, 输出1+2+3+…+n的值。 样例输入: 3 5 样例输出: 6 15import java.util.S转载 2017-08-06 21:48:27 · 543 阅读 · 0 评论 -
数值的整数次方
数值的整数次方(Java实现,与自带的幂函数进行了比较,结果完全一样) 自己编写一个求幂的函数,但是不允许调用系统的幂函数。 注:底数类型可以为double,指数类型只能为整数。分析:不仅需要考虑底数的符号,以及底数和指数分别为正,零,负数的情况,剑指offer中的解答好像是有漏洞的,具体在代码中说明了。 代码如下:package problem1;import java.util.Scan原创 2017-03-17 16:22:55 · 273 阅读 · 0 评论 -
斐波那契数列问题汇总
第一种情况:直接让斐波那契数列的第几项。f(1)=1,f(2)=1. 如:现在要求输入一个整数n,请你输出斐波那契数列的第n项。第二种情况:跳台阶问题也是一种斐波那契数列问题,只不过是初始情况不一样而已。 如:一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶,求该青蛙跳上一个n级的台阶一共有多少种跳法。f(0)=1,f(1)=2.如:我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩原创 2017-05-26 14:59:29 · 1459 阅读 · 0 评论 -
递归读取文件夹下的文件
如题:使用递归读取文件夹下面的所有文件/** * */package problem1;import java.io.File;/** * @author Hutongling * * @time:2017年4月30日 下午9:16:53 */public class 递归读取文件夹下面的所有文件 { /** * 递归读取文件夹下的 所有文件 *原创 2017-04-30 21:28:56 · 2038 阅读 · 0 评论 -
兔子只数问题
题目:有一对兔子,从出生第三个月后起每个月都生一对兔子,小兔子涨到第四个月之后每个月又生一对兔子, 假如兔子不死,问每个月的兔子总数是多少?分析:这是一个典型的斐波那契数列问题 兔子只数的规律为:1,1,2,3,5,8,13,21……package problem2;/** * @author Hutongling * * @time:2017年4月6日 上午9:48:28 */pu原创 2017-04-06 09:53:41 · 496 阅读 · 0 评论 -
将一个正整数分解质因数
题目:将一个正整数分解质因数。例如输入90,打印90=2*3*3*5分析:对n进行分解指数,应该先找到一个最小的指数k,然后按照下面的步骤完成: (1)如果这个指数恰好等于n,则说明分解指数的过程已经结束,打印出即可; (2)如果k!=n,但n能被k整除,则应打印出k的值,并用n除以k的商,作为心的正整数,重复执行第一步; (3)如果n不能被k整除,则用k+1作为k 的值,重复执行第一步。代码原创 2017-04-06 09:38:17 · 737 阅读 · 0 评论 -
连续子数组的最大和
题目:输入一个整形数组,数组里面有正有负。数组中一个连续的多个整数组成一个子数组。求所以子数组的和的最大值。要求时间复杂度为O(n).分析: 代码如下:import java.util.LinkedList;/** * @author Hutongling * * @time:2017年3月24日 上午11:12:40 */public class 连续子数组的最大和 {原创 2017-03-27 11:00:46 · 307 阅读 · 0 评论 -
实现将String类型转换成int类型输出
题目:编写一个函数将String 类型的数据转换成int类型的数据。分析: (1)考虑输入的合法性 (2)考虑正负 (3)考虑溢出 (4)考虑返回值 代码:/** * 题目:编写一个函数将String 类型的数据转换成int类型的数据 */package problem2;/** * @author Hutongling * * @time:2017年3月31日 下午2原创 2017-03-31 15:07:13 · 4105 阅读 · 0 评论 -
在递增排序数组中找和为S的两个数
题目:输入一个递增排序数组和一个数字,在数组中找到一对数字,其和等于S.分析: 方法1: 直接使用O(n^2)的算法进行遍历查找 方法2:使用优化的算法,时间复杂度为O(n):先定义两个指针,第一个指针指向第一个数组元素,第二个指针指向数组最后一个元素,计算这两个指针所在位置的元素之和,如果大于和,就将第二个指针向前移动,如果小于的话就将第一个指针向后移动,如此往复即可得到结果。 代码如下:/原创 2017-03-30 10:38:21 · 1117 阅读 · 0 评论 -
数组中只出现一次的数字
题目:一个整形数组中除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度为O(n),空间复杂度为O(1).分析:按照常规的思路是遍历数组并对每个数字进行计数,最后再遍历计数器数组,找到计数为1的数字。但是这种方法的时间复杂度为O(n^2),不符合题目的要求。故需要另外找思路。我们知道两个数在进行异或操作的时候有一种特性,那就是这个数和自己本身异或的时候其结果为原创 2017-03-30 09:31:59 · 256 阅读 · 0 评论 -
计算从1到n整数中1出现的次数
题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。分析: 方法1:不考虑时间效率的解法,通过对10求余判断个位数是否是1,若大于10就除以10之后再求余.方法2:将这n个数转换成字符串数组,然后对每个字符串的每个字符进行判断是否等于‘1’,若等于的话就将计数器加1,直到遍历完所有的数为止。代码如下:package problem2;import java.util.Scann原创 2017-03-28 10:17:18 · 1215 阅读 · 0 评论 -
栈的压入,弹出序列
题目:给定一个压栈序列,和另一个输出序列,根据压栈序列判断该栈是否能产生该输出序列。如给定入栈序列:1,2,3,4,5,判断序列4,5,3,2,1是否能通过该栈产生。分析:先将输出序列按照逆序压入一个辅助栈中,然后比较栈顶元素是否和入栈序列中的元素相等,如果不相等的话就将该元素压入栈中,如果相等就继续比较栈顶元素是否相等,直到不相等为止,最后比较所得到的相等元素的个数等于入栈的栈深度,如果等于栈的深原创 2017-03-20 19:43:46 · 323 阅读 · 0 评论 -
带有min函数的栈
自己编写一个栈,该栈含有min方法,能得到栈中在最小元素。 分析:使用两个栈,第一个栈用来存储数据,第二个栈用来存储最小的数据,每次压栈的时候都和第二个栈的栈顶元素比较,如果小于栈顶的话就压入第二个栈。 代码如下:package problem2;import java.util.*;//import java.util.Stack;/** * @author Hutongling */原创 2017-03-20 14:32:31 · 276 阅读 · 1 评论 -
顺时针打印二维数组(螺旋输出数组)
题目:给定一个数组,将该数组从第一个元素开始顺时针打印出来。分析:先考虑打印周围一圈的问题,然后可以使用递归求解,直到最后全都打印完为止。 代码如下:package problem2;/** * @author Hutongling */public class 顺时针打印二维数组 { static void print2DArray(int data[][]) {原创 2017-03-19 17:44:43 · 9838 阅读 · 0 评论 -
在o(1)时间删除链表节点
在o(1)时间删除链表节点剑指offer 面试题13 : 在o(1)时间删除链表节点 给定单向链表的头指针和一个节点指针,定义一个函数在o(1)时间删除该节点。 代码如下: 这里先使用数组创建一个链表(头插法和尾插法都有),然后需要创建一个节点,该节点在链表中的位置是未知的,故还需要创建一个搜索该节点在链表中的位置的函数,具体代码如下:代码代码块语法遵循标准markdown代码,例原创 2017-03-17 15:44:24 · 739 阅读 · 0 评论 -
调整数组使得奇数都在前面,偶数都在后面
调整数组使得奇数都在前面,偶数都在后面(可扩展到其他形式) 分析:可以使用时间复杂度为O(n),空间复杂度也为O(n)的插入算法。新建一个和原来数组一样大小的数组,再遍历数组中的每个元素,如果是奇数,则插入数组的前半部分,如果是偶数,则插入数组的后半部分,这样就可以看成是两端不断往中间扩展直至前后两端相接触为止。 具体代码如下:package problem2;/** * @author H原创 2017-03-17 21:25:21 · 1536 阅读 · 0 评论 -
输出链表的倒数第k个节点
题目:输出链表的倒数第k个节点 分析: 方法一: 先遍历链表,得到链表的总长度n,然后再次从头遍历链表定位到第(n-k+1)的节点,最后输出。这种方法需要遍历链表两次,但是鲁棒性好,对于输入的数据能较好的得到结果,但是该方法需要遍历链表两次,时间花费较多。 方法二: 设两个头指针,第一个头指针往下遍历,直到第k-1个节点的时候停止,然后两个指针同时向后遍历,原创 2017-03-18 12:41:01 · 542 阅读 · 0 评论 -
反转链表
题目: 反转链表 代码如下:package problem2;/** * @author Hutongling */public class 反转链表 { static void reverseList(Node head){ if(head==null) return ; Node head1=new Node(head.v原创 2017-03-18 14:34:36 · 272 阅读 · 0 评论 -
把数组排成最小的数
题目:输入一个整数数组,把数组里所有数字拼接成一个数,打印出能拼接的所有数字中最小的一个。例如:输入数组{3,32,321,3123}分析:可以根据数组长度创建一个字符串,例如长度是4的话,创建的字符串为“0123”,以此类推,但是如果超过10的话就需要使用字符之类的来表示。然后对字符串进行全排列,然后根据下标将所有的数连接起来一一比较。代码如下:package problem2;import ja原创 2017-03-28 16:23:31 · 269 阅读 · 0 评论 -
丑数
题目:我们把只包含因子2,3,5的数称作丑数。求从小到大的顺序的第1500个丑数。例如6,8都是丑数,但14不是,因为它包含因子7.习惯上我们把1当做第一个丑数。方法1:如果一个数能被2整除,我们就把它连续除以2;如果能被3整除就连续除以3,如果能被5整除就连续除以5.如果最后我们得到的是1的话就说明该数是丑数。方法2:创建数组保存已经找到的丑数,用空间换时间的解法。 丑数应该是另一个丑数乘以2,3原创 2017-03-28 20:17:07 · 1771 阅读 · 0 评论 -
字符串中第一个只出现一次的字符
题目:找出字符串中第一个只出现一次的字符。例如:“abbaccdeff”,第一个只出现一次的字符是‘d’.分析:对于ASCII码而言一共有256个字符,所以我们可以设置一个数组,长度为256,用来保存每个字符出现的次数。然后根据原始字符串将每个字符映射到数组中去,最后遍历次数数组,找到第一个出现次数为1 的字符。代码:/** * 题目:在字符串中找出第一个只出现一次的字符。如果输入“abaccde原创 2017-03-28 21:33:48 · 338 阅读 · 0 评论 -
判断一棵二叉树是不是平衡二叉树
题目:输入一棵二叉排序树的根节点,判断该树是不是平衡二叉树。分析:根据平衡二叉树的定义,我们只要计算左右子树的深度,然后通过这两个深度之差去判断是否是平衡二叉树。代码如下:/** * 给定一棵二叉树,判断该二叉树是不是平衡二叉树 */package problem2;/** * @author Hutongling * * @time:2017年3月29日 下午5:21:26 */原创 2017-03-29 20:58:55 · 709 阅读 · 0 评论 -
Java 多线程1:多线程生成的原因(Java内存模型与i++操作解析)
Java 内存模型 线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM(Java内存模型)的一个抽象概念,并不真实存在。它涵盖了缓存,写 缓冲区,寄存器以及其 他的硬件和编译器优化。Java内存模型的抽象示意图如下图: i++操作实质对于一个简单的 i++ 操作,结转载 2017-04-07 20:35:28 · 675 阅读 · 0 评论 -
Java 多线程2:生产者消费者问题
概念生产者消费者问题描述了两个线程(即生产者线程和消费者线程),共享固定大小的缓冲区,在实际运行中可能出现的问题。生成者:生成一定量的数据放到缓冲区中,然后重复此过程。 消费者:在缓冲区消耗这些数据。 该问题的关键就是 要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。要解决该问题,就必须 让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的转载 2017-04-07 20:38:01 · 365 阅读 · 0 评论 -
数字在排序数组中出现的次数
题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,结果输出4.分析: 方法1:直接从头开始比较,当等于给定数字的时候就将计数器加1,不等的时候就停止并返回计数器的值。 方法2:利用该数组是排序树组的这一特性,使用二分查找算法找到该数字,然后分别统计在找到的该数字位置前面等于该数字的个数和其后面等于该数字的个数,最后将两个个数相加即可。方法3:利原创 2017-03-29 16:27:27 · 324 阅读 · 0 评论 -
两个链表的第一个公共结点
题目:输入两个链表,找出他们的第一个公共结点。分析: 方法1:直接采用遍历的方法,从第一个链表的第一个元素开始分别与第二个链表的所有元素比较,直到相等为止,相等即找到了公共结点。 方法2:先分别遍历两个链表,分别得到链表的长度n,m,然后对长的链表进行遍历,遍历的节点数为|n-m|,最后再依次按顺序遍历两个链表并比较结点是否相等。代码如下:package problem2;/** * @aut原创 2017-03-29 13:27:00 · 284 阅读 · 0 评论 -
不使用加减乘除做加法
题目:不使用加减乘除实现两个整数的加法。分析:不适用加减乘除实现整数的加法很自然就考虑到使用位运算。 例子:5+17. 5的二进制是101,17的二进制是10001.第一步各位相加但是不计进位,得到结果10100(最后以为两个数字都是1,相加的结果是二进制10.这一步不计进位,因此结果依然是0);第二步,记下进位。在这个例子中只在最后以为相加时产生了进位,结果是10;第三步,把前两步的结果相加得原创 2017-03-29 10:54:18 · 349 阅读 · 0 评论 -
复制复杂链表
题目:实现一个能够复制复杂链表的函数。在该复杂链表中,每个节点出来有一个pNext指针指向下一个节点之外,还有pSibling指针指向链表中的任意节点或者null。分析:采用的方法是先将每个节点复制然后插在该节点的后面,但是此处的复制只复制该链表节点的pNext和value域,而对于pSibling域来说因为其指向的节点是任意的,故需要在后期将pSibling域补上,所以在第二部分就是将复制节点的p原创 2017-03-22 10:58:41 · 216 阅读 · 0 评论