剪绳子
题目描述:给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0] x k[1] x … x k[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
思路:
- 5<2x3,6<3x3,比6更大的数字我们就更不用考虑了,肯定要继续分。
- 其次看2和3的数量,2的数量肯定小于3个,为什么呢?因为2x2x2 < 3x3,那么题目就简单了。
- 直接用n除以3,根据得到的余数判断是一个2还是两个2还是没有2就行了。
1 | public int cutRope(int target) { |
把二叉树打印成多行
题目描述:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
思路:用队列实现二叉树的层次遍历(标准写法)
1 | ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) { |
二叉树的下一个结点
题目描述:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
思路:判断当前节点的右子节点是否为空
1 | public TreeLinkNode GetNext(TreeLinkNode pNode){ |
链表中环的入口结点
题目描述:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路:
1 | public ListNode EntryNodeOfLoop(ListNode pHead){ |
字符流中第一个不重复的字符
题目描述:请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符”go”时,第一个只出现一次的字符是”g”。当从该字符流中读出前六个字符“google”时,第一个只出现一次的字符是”l”。
如果当前字符流没有存在出现一次的字符,返回 # 字符。
思路:用数组统计字符出现的次数,并将字符按顺序加入队列,如果队列中字符出现的次数大于1,则出队;如果最后队列不为空,则出队的字符就是第一个出现的字符。
1 | public class Solution { |
表示数值的字符串
题目描述:请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串”+100”,”5e2”,”-123”,”3.1416”和”-1E-16”都表示数值。 但是”12e”,”1a3.14”,”1.2.3”,”+-5”和”12e+4.3”都不是。
思路:用法JDK方法:Double.parseDouble()
1 | public boolean isNumeric(char[] str) { |
数组中重复的数字
题目描述:在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
思路:
1 | public boolean duplicate(int numbers[],int length,int [] duplication){ |
求1+2+3+…+n
题目描述:求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。
思路:利用逻辑与得短路特性做为递归的终止条件。
1 | public int Sum_Solution(int n) { |
孩子们的游戏(圆圈中最后剩下的数)
题目描述:让小朋友们围成一个大圈。然后,随机指定一个数 m,让编号为 0 的小朋友开始报数。每次喊到 m-1 的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续 0…m-1 报数 …. 这样下去 …. 直到剩下最后一个小朋友,可以不用表演。
思路:约瑟夫环,用链表来模拟游戏过程;
1 | public int LastRemaining_Solution(int n, int m) { |
扑克牌顺子
题目描述:LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…..LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。
思路:先统计大小王的个数,当成赖子,通过对抽到的牌进行排序,判断是否能 组成顺子。
1 | public boolean isContinuous(int [] numbers) { |
左旋转字符串
题目描述:汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!
思路:1.先分别反转字符串;2.再整体反转;
1 | public String LeftRotateString(String str,int n) { |
和为S的两个数字
题目描述:输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。对应每个测试案例,输出两个数,小的先输出。
思路:利用双指针,从头和尾分别进行遍历判断(和相同时,两数差距越大,乘积越小)
1 | public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) { |
和为S的连续正数序列
题目描述:小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
思路:
1 | public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) { |
数组中只出现一次的数字
题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
思路:把所有的数异或,得到的结果即两个不同的数异或的结果,这个结果的二进制中的1,表现的是这两个不同的数的不同位。就按照这个结果中为1的位的位置划分,该位为1划分为一组,为0划分为一组。这样两个不同的数就被划分开了,再分别对这两组做异或操作,就找到了两个不同的数。

1 | public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { |
平衡二叉树
题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
思路:递归得到二叉树的高度,判断左子树与右子树的高度差,如果高度差超过1,则返回false
1 | public class Solution { |
数字在排序数组中出现的次数
题目描述:统计一个数字在排序数组中出现的次数。
思路:有序数组,可以利用二分法

1 | public int GetNumberOfK(int [] array , int k) { |
两个链表的第一个公共结点
题目描述:输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
思路:路程相等思想:当访问链表 A 的指针访问到链表尾部时,令它从链表 B 的头部重新开始访问链表 B;同样地,当访问链表 B 的指针访问到链表尾部时,令它从链表 A 的头部重新开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。

1 | public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { |
整数中1出现的次数(从1到n整数中1出现的次数)
题目描述:求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
思路:
个位
我们知道在个位数上,1会每隔10出现一次,例如1、11、21等等,我们发现以10为一个阶梯的话,每一个完整的阶梯里面都有一个1,例如数字22,按照10为间隔来分三个阶梯,在完整阶梯0-9,10-19之中都有一个1,但是19之后有一个不完整的阶梯,我们需要去判断这个阶梯中会不会出现1,易推断知,如果最后这个露出来的部分小于1,则不可能出现1(这个归纳换做其它数字也成立)。
我们可以归纳个位上1出现的个数为:
n/10 * 1+(n%10!=0 ? 1 : 0)
十位
现在说十位数,十位数上出现1的情况应该是10-19,依然沿用分析个位数时候的阶梯理论,我们知道10-19这组数,每隔100出现一次,这次我们的阶梯是100,例如数字317,分析有阶梯0-99,100-199,200-299三段完整阶梯,每一段阶梯里面都会出现10次1(从10-19),最后分析露出来的那段不完整的阶梯。我们考虑如果露出来的数大于19,那么直接算10个1就行了,因为10-19肯定会出现;如果小于10,那么肯定不会出现十位数的1;如果在10-19之间的,我们计算结果应该是k - 10 + 1。例如我们分析300-317,17个数字,1出现的个数应该是17-10+1=8个。
那么现在可以归纳:十位上1出现的个数为:
- 设k = n % 100,即为不完整阶梯段的数字
- 归纳式为:(n / 100) * 10 + (if(k > 19) 10 else if(k < 10) 0 else k - 10 + 1)
百位
现在说百位1,我们知道在百位,100-199都会出现百位1,一共出现100次,阶梯间隔为1000,100-199这组数,每隔1000就会出现一次。这次假设我们的数为2139。跟上述思想一致,先算阶梯数 * 完整阶梯中1在百位出现的个数,即n/1000 * 100得到前两个阶梯中1的个数,那么再算漏出来的部分139,沿用上述思想,不完整阶梯数k199,得到100个百位1,100<=k<=199则得到k - 100 + 1个百位1。
那么继续归纳百位上出现1的个数:
- 设k = n % 1000
- 归纳式为:(n / 1000) * 100 + (if(k >199) 100 else if(k < 100) 0 else k - 100 + 1)
后面的依次类推….
完美!归纳式看起来已经很规整了。 来一个更抽象的归纳,设i为计算1所在的位数,i=1表示计算个位数的1的个数,10表示计算十位数的1的个数等等。
- k = n % (i * 10)
- count(i) = (n / (i * 10)) * i + (if(k > i * 2 - 1) i else if(k < i) 0 else k - i + 1)
好了,这样从10到10的n次方的归纳就完成了。
1 | public int NumberOf1Between1AndN_Solution(int n) { |
连续子数组的最大和
题目描述:HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)
思路:
1 | public int FindGreatestSumOfSubArray(int[] array) { |
数组中出现次数超过一半的数字
题目描述:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路:
法1:对数组进行排序,中间的数一定是出现次数超过数组长度一般的数,否则返回0;
法2:用HashMap统计每个数字出现的次数;
1 | //方法一,时间复杂度nlogn |
1 | //方法二,时间复杂度n |
二叉搜索树与双向链表
题目描述:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
思路:中序遍历结果就是排序结果;中序递归;

1 | private TreeNode pre = null; |
栈的压入、弹出序列
题目描述:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
思路:用栈来模拟题目描述的过程;
1 | public boolean IsPopOrder(int [] pushA,int [] popA) { |
合并两个排序的链表
题目描述:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
思路:

1 | public ListNode Merge(ListNode list1,ListNode list2) { |
反转链表
题目描述:输入一个链表,反转链表后,输出新链表的表头。
思路:头插法:

1 | public ListNode ReverseList(ListNode head) { |
数值的整数次方
题目描述:给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0。
思路:
法1:暴力法;
法2:递归法,时间复杂度logN;
1 | public double Power(double base, int exponent) { |
1 | public double Power(double base, int exponent) { |
二进制中1的个数
题目描述:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路:n&(n-1):相当于把n二进制最后的1变为0
1 | n : 10110100 |
1 | public int NumberOf1(int n) { |
矩形覆盖
题目描述:我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
比如n=3时,2*3的矩形块有3种覆盖方法:
思路:斐波那契数列

1 | public int RectCover(int target) { |
跳台阶
题目描述:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
思路:斐波那契数列:跳 n 阶台阶,可以先跳 1 阶台阶,再跳 n-1 阶台阶;或者先跳 2 阶台阶,再跳 n-2 阶台阶,故有递推公式f(n) = f(n-1) + f(n-2)
1 | public int JumpFloor(int target) { |
斐波那契数列
题目描述:大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0,第1项是1)。
思路:斐波那契数列:f(n) = f(n-1) + f(n-2)
1 | public int Fibonacci(int n) { |
旋转数组的最小数字
题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路:采用二分法;若中间的元素大于 j 指针的元素,说明旋转点在 mid 和 j 之间;否则在 i 和 mid 之间;
特例:如果数组元素允许重复,会出现一个特殊的情况:nums[l] == nums[m] == nums[h],此时无法确定解在哪个区间,需要切换到顺序查找。例如对于数组 {1,1,1,0,1},l、m 和 h 指向的数都为 1,此时无法知道最小数字 0 在哪个区间。
1 | public int minNumberInRotateArray(int [] array) { |
重建二叉树
题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路: