题目描述
1、在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
/**
* 根据题意,可以考虑从左下角向右上角开始遍历
*/
public class Solution {
public boolean Find(int target, int [][] array) {
int len = array.length-1; //行数,最后一行
int i = 0;
for(int j=0; len>=0 && i<array[0].length; j++){ //从左下角开始遍历
if(target>array[len][i]){ //如果比左下角元素大,则右移
i ++;
}else if(target<array[len][i]){ //小则上移
len --;
}else{
return true;
}
}
return false;
}
}
2、请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
public class Solution {
public String replaceSpace(StringBuffer str) {
if(str == null){
return null;
}
for(int i = 0; i<str.length();i++){
if(str.charAt(i) == ' '){ //遍历字符串的每一个字符,为空格就替换
str.replace(i,i+1,"%20"); //因为是StringBuffer,直接替换位置
}
}
return str.toString();
}
}
3、输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> al = new ArrayList<>();
while(listNode != null){ //直到遍历到链表的尾部
al.add(0,listNode.val); //根据集合的性质,每次都把每次都把新元素放在首部
listNode = listNode.next;
}
return al;
}
}
4、输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre == null || in == null){
return null;
}
TreeNode root = reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
return root;
}
private TreeNode reConstructBinaryTree(
int[] pre,int startPre,int endPre,int[] in,int startIn,int endIn){
if(startPre>endPre||startIn>endIn){
return null;
}
//前序遍历的第一个数字是根节点的值
TreeNode root = new TreeNode(pre[startPre]);
//遍历中序数组,找到根节点的位置,创建左右子树
for(int i = startIn;i <=endIn; i++){
if(in[i]==pre[startPre]){ //通过找到根节点将其分为左右子树
//将左子树作为整棵树重新遍历,并将返回值作为上一个节点的左节点
root.left = reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
//将右子树作为整棵树遍历
root.right = reConstructBinaryTree(pre,startPre+i+1-startIn,endPre,in,i+1,endIn);
}
}
return root;
}
}
5、用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
/**
* 思路分析:
* 1、队列特性,先进先出,栈特性,先进后出
* 2、两个栈,stack1先存储进来的值,然后将stack1的内容压入stack2,从而实现按顺出弹出
* 3、弹出栈顶元素后,在将stack2的元素重新压入stack1
* 4、循环2,3步,实现队列
*/
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
while(!stack1.isEmpty()){
stack2.push(stack1.pop()); //将stack1的数据压入stack2,实现反转
}
int result = stack2.pop(); //获取进栈的第一个元素
while(!stack2.isEmpty()){
stack1.push(stack2.pop()); //重新压入stack1
}
return result;
}
}
6、把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
/**
* 思路分析:如果用普通的遍历方法,效率太低,所以建议使用二分法查找
* 1、每次获取数组中中间元素的值
* 2、分别与左右边界元素比较,缩小查找范围
* 3、知道查找到最后两个元素,因为为非减排序,则右元素即为所求元素
*/
public class Solution {
public int minNumberInRotateArray(int [] array) {
if (array.length == 0){
return 0;
}
int left = 0;
int right = array.length - 1;
int middle = -1;
while (array[left]>=array[right]) {
if(right-left==1){ //如果只有两个元素时,说明右元素为所求元素
middle = right;
break;
}
middle = left + (right - left) / 2; //获取中间元素指针位置
if (array[middle] >= array[left]) { //如果中间元素大于左边界元素,说明最小值在右部分
left = middle;
}
if (array[middle] <= array[right]) {
right = middle;
}
}
return array[middle];
}
}
7、大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39
/**
* 斐波那契数列(Fibonacci sequence):指的是这样一个数列:
* 1、1、2、3、5、8、13、21、34、……在数学上,
* 斐波纳契数列以如下被以递推的方法定义:
* F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=3,n∈N*)
*/
public class Solution {
public int Fibonacci(int n) {
int f1=1;
int f2=1;
int sum = 0;
if(n == 0){
return 0;
}else if(n ==1 || n == 2){ //两个以内直接到达
return 1;
}else{
for(int i=3;i<=n;i++){ //从第三个数开始
sum = f1 + f2;
f1 = f2;
f2 = sum;
}
}
return sum;
}
}
8、一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
/**
* 思路分析:
* 举例:到达台阶5可以分为:3->5,4->5 两种
* 因此到达台阶5的可能就是到达台阶3,4的总和,即:f(5)=f(3)+f(4)
* 类推可得:f(n)=f(n-1)+f(n-2)
*/
public class Solution {
public int JumpFloor(int target) {
if(target <= 0){
return 0;
}else if(target == 1){ //一步到达
return 1;
}else if(target == 2){ //一步到位或者两个1
return 2;
}
int one = 1;
int two = 2;
int result = 0;
for(int i = 2;i < target; i++){ //循环求和
result = one + two; //前两次的和
one = two; //指向下一个数
two = result; //指向下一个数
}
return result;
}
}
9、一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
/**
* 思路分析:因为每一层台阶都可以到达指定台阶
* 因此:f(n)=f(1)+f(2)+...+f(n-1)+1,1是直接到达
* 在分析可得:因为f(1)=1,f(2)=f(1)+1=2f(1);f(3)=f(1)+f(2)+1=2f(2)
* 类推可得:f(n)=2f(n-1),即结果为2的幂次方
*/
public class Solution {
public int JumpFloorII(int target) {
if(target <= 0){
return 0;
}else if(target == 1){
return 1;
}
int result = 2;
for(int i = 2; i< target; i++){
result = 2 * result; //结果为2的幂次方,每次乘以2
}
return result;
}
}
10、我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法
/**
* 和台阶跳原理相似
*/
public class Solution {
public int RectCover(int target) {
if(target <= 0){
return 0;
}else if(target == 1){
return 1;
}else if(target == 2){
return 2;
}
int f1 = 1;
int f2 = 2;
int result = 0;
for(int i = 2; i <target; i++){
result = f1 + f2;
f1 = f2;
f2 = result;
}
return result;
}
}
总结:剑指offer的题都是非常经典的,在此总结记录,比方便日后查看,因为有些方法的答案为博主自己编写的,所以可能不是最优答案,所以此文仅供大家参考,希望得到更优秀解答方案的可以查看剑指offer的解答。