16.数值的整数次方
题目
实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
思路
这道题思路比较简单,但是要考虑各种情况。因为题目没有指定整数的范围,整数可能是正数,0,负数。正数简单不用说。任何数的零次幂都是零。负数取绝对值求幂后取倒数。再考虑底数,如果底数是0也要单独计算。
测试用例
底数为正数,负数,零,指数为正数,负数,零。
核心代码
public double printReversly(double base, int exp) {
if (exp == 0) {
return 1;
}
if (exp == 1) {
return base;
}
//用右移代替除2的操作
double res = printReversly(base, exp >> 1);
res = res * res;
//用一个数和1进行与运算,如果结果是1,证明他是奇数。
if ((exp & 0x1) == 1){
res = res * base;
}
return res;
}
17.打印1到最大的n位数
题目
输入数字n,按顺序打印出从1最大的n位十进制数。比如输入3,则打印出1、2、3一直到最大的3位数即999。
思路
误区:这道题没有限制n的大小,那么n就有可能超出整数的表示范围,不能简单地循环打印。
思路一:用字符串模拟数字,并且模拟数字的加法,分别打印数字。
思路二:数字的全排列
测试用例
n<1,n=1,n=2,n=10000…
18.删除链表的节点
题目
给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点。
思路
删除链表的某一个节点有两种方式,一种是找到删除节点的前驱,然后改变其指针。一个是将该节点的下一个节点的值复制到该节点,然后删除下一个节点即可。这道题显然应该采用后一种。
然后考虑特殊情况,如果要删除链表的尾节点呢,只能从头遍历。
测试用例
删除头节点,删除尾节点,链表只有一个节点,链表有多个节点,空指针
扩展.删除链表中的重复节点
题目
在一个排序的链表中,删除重复的结点,包括其自身。例如11123删除后变为23。
思路
三指针法:一个节点记录被删除节点的前驱,两个指针比较是否重复。
测试用例
空指针,一个节点的链表,全是重复节点的链表。尾节点重复的链表,头节点重复的链表。
核心代码
while(after!=null){
if(after.val == cur.val){
while(after.val == cur.val){
after = after.next;
//防止空指针错误
if(after == null) break;
}
if(after == null){
pre.next = null;
}
else{
pre.next = after;
cur = pre.next;
after = after.next;
}
}
else{
pre = pre.next;
cur = cur.next;
after = after.next;
}
}
19.正则表达式匹配
20.表示数值的字符串
21.调整数组顺序使奇数位于偶数前面
题目
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
思路
两个指针分别指向链表的头部和尾部,两个指针向中间移动,每当移动到左边为偶数,右边为奇数时候,交换二者,直到两个指针相遇。
测试用例
空指针,空数组,全是奇数的数组,全是偶数的数组,长度为1的数组
22.链表中倒数K个节点
题目
输入一个链表,输出该链表中倒数第k个结点。链表的尾结点是倒数第1个结点。
思路
双指针法,一个指针先走k-1步,一个指针从头开始。然后两个指针同时向后移动即可。注意考虑特殊情况。
测试用例
空指针,长度为1的链表,长度小于K的链表,删除链表头,删除链表尾部,K=0
扩展:求链表的中间节点
23.链表中环的入口节点
题目
一个链表中包含环,找出环的入口结点
思路
先确定链表包含环,采用快慢指针法,两个指针相遇证明包含环,如果两个指针未相遇(即快指针已经遇到p.next==null的情况),证明没有环。
确定了链表有环之后,将慢指针放到头节点,快指针从相遇点出发,两者同速度移动,相遇点就是环的入口节点。
测试用例
空指针,链表没有环,链表只有一个节点
24.反转链表
要求
必须做到迅速准确流畅的写出反转链表的循环写法,尽量掌握递归写法。
测试用例
空指针,长度为1的链表。
25.合并两个排序链表
题目
输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。
思路
迭代写法较为简单,尽量掌握递归写法,重点注意程序的鲁棒性。
测试用例
其中一个链表为空,两个链表均为空,两个链表长度相等,两个链表长度不等。
26.树的子结构
题目
输入两棵二叉树A和B,判断B是不是A的子结构。
思路
先对A进行遍历,找到树A中与B的根节点的值相等的节点R,然后判断R是否包含和B一样的结构,没有的话继续遍历A找R。考察递归以及鲁棒性。
测试用例
两个树有一个是空树或者都是空树,斜二叉树,包含子结构,不包含子结构。
27.镜像二叉树
题目
写一个函数,输入一个二叉树,函数输出它的镜像。
思路
思路比较简单,是一道初级递归问题,建议多练
测试用例
空指针,斜二叉树。
28.对称二叉树
题目
写一个函数,判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的
思路
有了上题的基础,容易想到的思路就是,求出二叉树的镜像树,判断是否一样就行
另外一种奇特思路:不同于前序遍历,定义一个对称遍历方法,先访问根节点,在访问右子节点,在访问左子节点。如果对称遍历序列和前序序列一样,那么这个树是对称二叉树。
测试用例
空指针,只有一个节点的二叉树,斜二叉树,结构不对称的二叉树,结构对称但是值不相同的二叉树。值都相同的二叉树。
29.顺时针打印矩阵
30.包含min函数的栈
题目
定义新的栈的数据结构,该类型中实现一个能够得到栈的最小元素的min函数。要求调用min、push及pop的时间复杂度都是O(1)。
思路
题目没有规定使用那种数据结构,于是决定使用一个数组来表示堆栈,push pop直接在数组尾部添加删除,但是求min的时间复杂度变成了O(n),所以这个思路不可取。
于是采用一个辅助栈存放栈的最小值(注意是存放最小值,而不是数值本身)。那么就要重写入栈和出栈的规则,入栈时,把之前最小元素与新入栈元素的较小值压入辅助栈,出栈时两个栈同时出栈。
测试用例
入栈数字比最小值大,比最小值小,将最小值出栈,将最小值入栈
31.栈的压入弹出序列
题目
输入两个整数序列,第一个序列表示栈的压入顺序,判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1、2、3、4、5是某栈的压栈序列,序列4、5、3、2、1是该压栈序列对应的一个弹出序列,但4、3、5、1、2就不可能是该压栈序列的弹出序列。
思路
用一个堆栈来模拟压入和弹出,首先读弹出序列,如果要弹出的数字位于栈顶,直接弹出,如果不位于栈顶,那么从未入栈的剩余压入序列中寻找该数字,如果未找到,说明两个序列不匹配,如果找到了,就将这个数以前的数字和他本身依次压入堆栈中。
核心代码
测试用例
空数组,空指针,一个数字的数组,正确的弹出序列,错误的弹出序列,两个数组长度不同
32.二叉树层次遍历
题目
从上往下打印出二叉树的每个结点,同一层的结点按照从左到右的顺序打印。
思路
根节点入队,然后进入循环,头节点出队,访问之,如果有左右子节点,则将左右子节点依次入队。没有就继续将头结点出队,直到队列为空。
测试用例
空指针,只有一个节点的树,左斜树,右斜树
扩展:分行打印二叉树
题目
从上到下按层打印二叉树,同一层的结点按从左到右的顺序打印,每一层打印到一行。
思路
测试用例
空指针,只有一个节点的树,左斜树,右斜树
扩展:之字形打印二叉树
题目
第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
思路
测试用例
空指针,只有一个节点的树,左斜树,右斜树。
33.二叉搜索树的后序遍历序列
题目
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。
思路
典型的递归解法,建议熟练掌握
测试
空指针,空数组,只有一个节点的数组,左斜树右斜树的后序序列。
34.二叉树中和为某一值的路径
题目
输入一棵二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
思路
首先,肯定要遍历二叉树,遍历二叉树无非4种形式,前序,后序,中序,层次遍历。这道题显然从前序遍历入手,原因如下:
- 路径总是以根节点为起始点
- 前序遍历的顺序正好是一条路径一条路径来的
要打印二叉树,必须保存路径上的节点,所以采用链表(?)来保存,思路如下:没访问到一个节点,讲这个节点放入路径,并加上这个节点的值,如果这个节点是叶节点,并且路径的值等于目标值,则打印该节点,如果不是叶子节点,就继续访问子节点。