剑指offer
第一题
题目:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:因为这个二维数组是有序的, 可以先定位到左下角, 判断要找的数, 如果target > 左下角 就往右找, 然后target < 左下角 就往上找
1 | public class Solution { |
第二题
题目: 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路:首先不能使用String提供的replace()方法
①从前往后替换, 每替换一次后面的字符就要移动一次, 效率低下
②从后往前替换, 每个字符只需要移动一次, 所以选择这个思路
1 | public class Solution { |
第三题
题目: 输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
1 | public class ListNode { |
代码实现:
解法一: 递归
1 | import java.util.ArrayList; |
解法二: 利用栈(先进后出)
1 | import java.util.ArrayList; |
第四题
题目: 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
1 | Definition for binary tree |
代码实现:
1 | public class Solution { |
第五题
题目: 用两个栈来实现一个队列,完成队列的Push和Pop操作, 队列中的元素为 int 类型
思路: 首先栈是先进后出, 队列是先进先出
1 | import java.util.Stack; |
第六题
题目:把一个数组最开始的若干元素搬到数组的末尾, 我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转, 输出旋转数组的最小元素.例如数组{3,4,5,1,2} 为 {1,2,3,4,5}, 该数组的最小值为1, NOTE: 给出的所有元素都大于0, 若数组大小为0 ,请返回0
思路:(1)array[mid] > array[high]:
出现这种情况的array类似[3,4,5,6,0,1,2],此时最小数字一定在mid的右边。
low = mid + 1
(2)array[mid] == array[high]:
出现这种情况的array类似 [1,0,1,1,1] 或者[1,1,1,0,1],此时最小数字不好判断在mid左边
还是右边,这时只好一个一个试 ,
high = high - 1
(3)array[mid] < array[high]:
出现这种情况的array类似[2,2,3,4,5,6,6],此时最小数字一定就是array[mid]或者在mid的左
边。因为右边必然都是递增的。
high = mid
1 | import java.util.ArrayList; |
第七题
题目: 输入一个整数n, 请你输出斐波那契列的第n项(从0开始,第0项为0)
思路一: 采用递归, 这种解法效率低, 每次都要调自己
1 | public class Solution { |
思路二:
1 | public class Solution { |
第八题
题目: 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
思路: 这还是一个斐波那契列, 唯一不同的是从1开始
1 | public class Solution { |
第九题
题目: 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。
求该青蛙跳上一个n级的台阶总共有多少种跳法。
分析: f(1) = 1
f(2) = f(2-1) + f(2-2) //f(2-2) 表示2阶一次跳2阶的次数。
f(3) = f(3-1) + f(3-2) + f(3-3)
…
f(n) = f(n-1) + f(n-2) + f(n-3) + … + f(n-(n-1)) + f(n-n)
说明:
1)这里的f(n) 代表的是n个台阶有一次1,2,...n阶的 跳法数。
2)n = 1时,只有1种跳法,f(1) = 1
3) n = 2时,会有两个跳得方式,一次1阶或者2阶,这回归到了问题(1) ,f(2) = f(2-1) + f(2-2)
4) n = 3时,会有三种跳得方式,1阶、2阶、3阶,那么就是第一次跳出1阶后面剩下:f(3-1);第一次跳出2阶,剩下f(3-2);第一次3阶,那么剩下f(3-3)
因此结论是f(3) = f(3-1)+f(3-2)+f(3-3)
5) n = n时,会有n中跳的方式,1阶、2阶...n阶,得出结论:
f(n) = f(n-1)+f(n-2)+...+f(n-(n-1)) + f(n-n) => f(0) + f(1) + f(2) + f(3) + ... + f(n-1)
6) 由以上已经是一种结论,但是为了简单,我们可以继续简化:
f(n-1) = f(0) + f(1)+f(2)+f(3) + ... + f((n-1)-1) = f(0) + f(1) + f(2) + f(3) + ... + f(n-2)
f(n) = f(0) + f(1) + f(2) + f(3) + ... + f(n-2) + f(n-1) = f(n-1) + f(n-1)
可以得出:f(n) = 2*f(n-1)
7) 得出最终结论,在n阶台阶,一次有1、2、...n阶的跳的方式时,总得跳法为:
| 1 ,(n=0 )
f(n) = | 1 ,(n=1 )
| 2*f(n-1),(n>=2)代码实现:
1 | public class Solution { |
第十题
题目: 我们可以用2×1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2×n的大矩形,总共有多少种方法?
分析: 还是一个斐波那契
采用递归:
1 | public class Solution { |
不用递归, 效率比较高的解法:
1 | public class Solution { |
第十一题
题目: 输入一个整数, 输出该数二进制表示中1的个数, 其中负数用补码表示
思路:如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
举个例子:一个二进制数1100,从右边数起第三位是处于最右边的一个1。减去1后,第三位变成0,它后面的两位0变成了1,而前面的1保持不变,因此得到的结果是1011.我们发现减1的结果是把最右边的一个1开始的所有位都取反了。这个时候如果我们再把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。如1100&1011=1000.也就是说,把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。
1 | public int NumberOf1(int n){ |
第十二题
题目: 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
解法一: 常规解法, 时间复杂度为O(n)
1 | public class Solution { |
解法二: 递归:
n为偶数时, a^n = a^(n/2) * a^(n/2)
n为奇数时, a^n=(a^(n-1)/2)×(a^(n-1/2))×a
时间复杂度为 O(logn)
1 | public class Solution(){ |
第十三题
题目: 输入一个整数数组,实现一个函数来调整该数组中的数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变.
思路:
1 | 首先统计奇数的个数 |
1 | public class Solution{ |
第十四题
题目: 输入一个链表,输出该链表中倒数第K个节点
1 | /* |
思路: 定义两个指针, 先让着两个指针都指向链表的头结点, 然后让其中一个指针往后移(k - 1)位, 再让另一个指针开始跑(此时两个指针在相对静止的跑), 当先跑的那个指针到达链表末尾时, 后跑的那个指针到达的位置就是倒数第k的位置
1 | public class Solution{ |
1 | 精简写法 |
第十五题
题目: 输入一个人链表, 反转链表后, 输出新链表的表头.
1 | /* |
题解
1 | public class Solution { |
第十六题
题目:输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
1 |
|
1 | //非递归版 |
第十七题
题目:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
1 | /** |
第十八题
题目:操作给定的二叉树,将其变换为源二叉树的镜像
1 | /** |
第十九题
题目:两个链表的第一个公共节点
1 | /* |
第二十题
题目:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路:快慢指针法
1 | /* |
第二十一题
题目: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
1 | package com.holicCode; |