以下为博主自己实现的剑指Offer里面的题目,使用java语言,不一定是最好的解法,参考书上的代码,以及使用牛客网的平台进行测试是否通过编程。
完整代码链接:
https://github.com/Parallelline1996/offer
面试题3:数组中重复的数字
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
解法:1. 不考虑空间限制,使用hashtable
// duplication[0] 用于记录重复的数字
public static boolean duplicate(int numbers[],int length,int [] duplication) {
// 对输入情况的判断,判断数组是否为空
if (numbers == null) {
return false;
}
// 判断数组内容是否符合要求
for (int i : numbers) {
if (i >= length || i < 0) {
return false;
}
}
// 采用哈希表的方式进行
Hashtable<Integer, Integer> hashtable = new Hashtable<>();
for (int i = 0; i < numbers.length; i++) {
if (hashtable.containsValue(numbers[i])) {
duplication[0] = numbers[i];
return true;
} else {
hashtable.put(i, numbers[i]);
}
}
return false;
}
考虑空间限制:
// 下面采用不需要空间开销的解法:
public static boolean duplicate_(int numbers[],int length,int [] duplication) {
// 对输入情况的判断,判断数组是否为空
if (numbers == null) {
return false;
}
// 判断数组内容是否符合要求
for (int i : numbers) {
if (i >= length || i < 0) {
return false;
}
}
for (int i = 0; i < numbers.length; i++) {
// 注意要有这一个判断
while (numbers[i] != i) {
// 将数组每一个元素的值与其下标进行比较,如果不同,与元素值对应的下标进行交换
// 元素与下标相对应。当重复元素存在时,会碰到,即停止
if (numbers[i] == numbers[numbers[i]]) {
duplication[0] = numbers[i];
return true;
} else {
int temp = numbers[i];
numbers[i] = numbers[temp];
numbers[temp] = temp;
}
}
}
return false;
}
面试题4:二维数组中的查找
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数
public static boolean Find(int target, int [][] array) {
// 判断输入的合法
if (array == null) {
return false;
}
// 提取行列
int row = array.length;
int column = array[0].length;
// 进行寻找
for(int i = column - 1; i >= 0; i--) {
for(int j = 0; j < row; j++) {
if(array[j][i] == target) {
return true;
}else if (array[j][i] > target) {
break;
}else if (array[j][i] < target) {
continue;
}
}
}
return false;
}
面试题5:替换空格
请实现一个函数,将一个字符串中的空格替换成“%20”。
例如,当字符串为“We Are Happy”.则经过替换之后的字符串为“We%20Are%20Happy”
这个题对于java来说,因为有string的存在,所以省去了很多麻烦,如果对于C/C++,因为使用的是char[],为了节省移位的时间,可以采取先扫描一遍,获取空格数,然后求出新数组的长度并创建,然后从后往前进行复制,遇到空格则用“%20”进行替代。
/*
补充java基础:
String字符串常量, StringBuilder、StringBuffer是字符串变量
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
*/
public static String replaceSpace(StringBuffer str) {
StringBuilder sBuilder = new StringBuilder();
for(int i = 0; i < str.length(); i++) {
if(str.charAt(i) != ' ') {
sBuilder.append(str.charAt(i));
}else {
sBuilder.append("%20");
}
}
return sBuilder.toString();
}
面试题6:从尾到头打印链表
思路:只是进行打印,因此,递归,或者通过栈进行操作
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
// 用于返回最后的结果
ArrayList<Integer> temp = new ArrayList<>();
// 对输入进行判断
if (listNode == null) {
return temp;
}
Stack<ListNode> aIntegers = new Stack<>();
ListNode head = listNode;
// 进行压栈
while (head != null) {
aIntegers.push(head);
head = head.next;
}
// 进行出栈
while (!aIntegers.empty()) {
temp.add(aIntegers.pop().val);
}
return temp;
}
面试题7:重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回
public static TreeNode reConstructBinaryTree(int[] pre, int pre_start, int pre_end,
int[] in, int in_start, int in_end) {
// 判断是否符合要求
if (pre_start > pre_end || in_start > in_end) {
return null;
}
TreeNode root = new TreeNode(pre[pre_start]);
// 根据先序和中序的特点,通过先序确定根节点,再使用根节点的位置对中序进行划分
for (int i = in_start; i <= in_end; i++) {
// 中序的划分: 左子树:in_start ~ i - 1; 右子树: i + 1 ~ in_end;
// 前序的划分: 左子树:pre_start + 1 ~ pre_start + (i - in_start); 右子树:pre_start + (i - in_start) + 1 ~ pre_end
// 原因:对于中序遍历,i刚好就是划分左右子树的中间值,所以分成两个,一边从头到i-1,一边从i+1到结束
// 对于先序遍历,因为每次都是先取走pre[pre_start],所以实际上是划分pre[]的pre_start + 1 ~ pre_end,划分成两段
// 重点就是将前后分开,通过中序确定前序的左右子树的大小,进而进行划分
if (in[i] == pre[pre_start]) {
// 先序遍历的理解也可以理解为:通过中序来判断前序左侧的数目
root.left = reConstructBinaryTree(pre, pre_start + 1, pre_start + i - in_start, in, in_start, i - 1);
root.right = reConstructBinaryTree(pre, pre_start + i - in_start + 1, pre_end, in, i + 1, in_end);
break;
}
}
return root;
}
面试题9:用两个栈实现队列
// 这个用于进栈
static Stack<Integer> stack1 = new Stack<Integer>();
// 这个用于出栈
static Stack<Integer> stack2 = new Stack<Integer>();
// 实现入队列操作
public static void push(int node) {
stack1.push(node);
}
// 出队列
public static int pop() {
// 查看用于出栈的栈是否空
if (!stack2.isEmpty()) {
return stack2.pop();
} else {
// 当用于出栈的栈为空时,将所有用于入栈的栈里的元素全部移动到出栈的
while (!stack1.isEmpty()) {
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
面试题10:斐波那契数列
public static int Fibonacci(int n) {
if (n <= 1) {
return n;
}
int number1 = 0, number2 = 1, totalNumber = 0;
for (int i = 1; i < n; i++) {
totalNumber = number1 + number2;
number1 = number2;
number2 = totalNumber;
}
return totalNumber;
}
面试题11:旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
// 顺序查找的方式:
public int minNumberInRotateArray(int [] array) {
if (array == null || array.length == 0) {
return 0;
}
if (array.length == 1) {
return array[0];
}
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
return array[i];
}
}
return array[0];
}
// 二分法待补充
面试题12:矩阵中的路径
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。
路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。
如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。
例如 a b c e s f c s a d e e 矩阵中包含一条字符串”bcced”的路径,但是矩阵中不包含”abcb”路径,
因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子
public boolean hasPath(char[] matrix, int rows, int cols, char[] str) {
// 创建一个数组来记录是否被访问
int flag[] = new int[matrix.length];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
// 从每一个点进行遍历
if (helper(matrix, rows, cols, i, j, str, 0, flag)) {
return true;
}
}
}
return false;
}
private boolean helper(char[] matrix, int rows, int cols, int i, int j, char[] str, int k, int[] flag) {
// 确定在矩阵中的位置
int index = i * cols + j;
// 不符合条件
if (i < 0 || i >= rows || j < 0 || j >= cols || matrix[index] != str[k] || flag[index] == 1) {
return false;
}
if(k == str.length - 1) {
return true;
}
flag[index] = 1;
// 向上下左右
if (helper(matrix, rows, cols, i - 1, j, str, k + 1, flag)
|| helper(matrix, rows, cols, i + 1, j, str, k + 1, flag)
|| helper(matrix, rows, cols, i, j - 1, str, k + 1, flag)
|| helper(matrix, rows, cols, i, j + 1, str, k + 1, flag)) {
return true;
}
flag[index] = 0;
return false;
}