不知道为啥,力扣上没有第一和第二题,后面也有些题没有。感觉剑指offer相比力扣整体要偏简单一点,但想要一次写对也是有一定难度的。
文章目录
3.数组中重复的数字
排序以后找第一个两个一样的数挨在一起的数。
public int findRepeatNumber(int[] nums) {
Arrays.sort(nums);
for(int i = 0 ; i < nums.length-1;i++){
if(nums[i]==nums[i+1])
return nums[i];
}
return 0;
}
4. 二维数组中的查找
从右上角开始找,下面的数必然比当前的数大,左边的数必然比当前的数小。
如果比当前数大,就往下找,如果比当前数小,就往左找。
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if(matrix.length==0)
return false;
int i = 0;
int j = matrix[0].length-1;
while(i<matrix.length && j>=0){
if(matrix[i][j]==target)
return true;
else if(matrix[i][j]>target)
j--;
else
i++;
}
return false;
}
5.替换空格
直接换,没什么好说的
public String replaceSpace(String s) {
for(int i = 0 ; i < s.length() ; i++){
if(s.charAt(i)==' '){
s=s.substring(0,i)+"%20"+s.substring(i+1,s.length());
i+=2;
}
}
return s;
}
6.从尾到头打印链表
用栈
public int[] reversePrint(ListNode head) {
Stack<Integer> stack = new Stack();
while(head!=null){
stack.push(head.val);
head=head.next;
}
int[] res = new int[stack.size()];
int i = 0;
while(!stack.empty()){
res[i++] = stack.pop();
}
return res;
}
7.重建二叉树
思路:
先从中序数组里找到前序数组的第一个元素(根元素)并创建结点,然后递归左边和右边。
public TreeNode buildTree(int[] preorder, int[] inorder) {
TreeNode root = __buildTree(preorder,inorder);
return root;
}
public TreeNode __buildTree(int[] preorder,int[] inorder){
//preorder的长度和inorder的长度永远相等
if(preorder.length==0)
return null;
int i = 0;//指向preorder
int j = 0;//指向inorder
TreeNode root = new TreeNode(preorder[i]);
//如果数组里只有一个数字,说明应该直接返回这个根节点
if(preorder.length==1)
return root;
//首先在inorder中找到根节点
while(inorder[j]!=preorder[i])j++;
//inorder中,在j左边的都是左子树,在j右边的都是右子树
//递归搞定左右子树
if(j!=0){
int[] pre = new int[j];int[] in = new int[j];
System.arraycopy(preorder,1,pre,0,j);
System.arraycopy(inorder,0,in,0,j);
root.left = __buildTree(pre,in);
}
if(preorder.length-j != 0){
int[] pre = new int[preorder.length-j-1];int[] in = new int[inorder.length-j-1];
System.arraycopy(preorder,j+1,pre,0,preorder.length-j-1);
System.arraycopy(inorder,j+1,in,0,inorder.length-j-1);
root.right=__buildTree(pre,in);
}
return root;
}
9.用两个栈实现队列
注意:第二个栈如果不空的话,要等第二个栈空了以后再把第一个栈pop出来的元素push进去
class CQueue {
Stack<Integer> s1,s2;
public CQueue() {
s1 = new Stack();
s2 = new Stack();
}
public void appendTail(int value) {
s1.push(value);
}
public int deleteHead() {
if(s2.empty()){
while(!s1.empty()){
s2.push(s1.pop());
}
}
if(s2.empty())
return -1;
else
return s2.pop();
}
}
10-I.斐波那契数列
这题居然没做出来,因为直接用递归会超过时间限制,直接用递归的话,时间复杂度和空间复杂度都太高了。因此不要用递归,递归会进行很多重复的操作。
public int fib(int n) {
if(n==0)
return 0;
int a = 0, b =1,sum=1;
for(int i = 1; i < n ; i++){
sum=(a+b)%1000000007;
a=b;
b=sum;
}
return sum;
}
10-II.青蛙跳台阶问题
动态规划
public int numWays(int n) {
int[]dp = new int[n+1];
if(n==0||n==1)
return 1;
if(n==2)
return 2;
dp[0]=1;
dp[1]=1;
dp[2]=2;
for(int i = 3 ; i < n+1 ; i++){
dp[i]=(dp[i-1]+dp[i-2])%1000000007;
}
return dp[n];
}
11.旋转数组的最小数字
找到后一个数比前面一个数小的时候就可以返回了,如果找到了最后,说明最小的数是第一个
public int minArray(int[] numbers) {
for(int i = 0 ; i < numbers.length-1 ; i++){
if(numbers[i]>numbers[i+1])
return numbers[i+1];
}
return numbers[0];
}
12.矩阵中的路径
思路:首先确定所有可能的起点位置,然后对每个起点用dfs深度遍历,只要找到一个就返回true,否则继续找,最后也没找到就返回false
要注意:使用过的字符不能再使用!
public boolean exist(char[][] board, String word) {
char start = word.charAt(0);
//寻找start
int i = 0, j = 0;
//把所有start的可能存到list中,然后分别对list的所有可能进行寻找
List<Integer> listI = new ArrayList<>();
List<Integer> listJ = new ArrayList<>();
for (; i < board.length; i++) {
for (j = 0; j < board[0].length; j++) {
if (board[i][j] == start) {
listI.add(i);
listJ.add(j);
}
}
}
if (listI.size() == 0)
return false;
//开始寻找,使用dfs
int count = 0;
boolean[][] used = new boolean[board.length][board[0].length];
while (listI.size() != 0) {
int I = listI.remove(listI.size() - 1);
int J = listJ.remove(listJ.size() - 1);
if (dfs(board, word, count, I, J, used)) {
return true;
}
}
return false;
}
public boolean dfs(char[][] board, String word, int count, int i, int j, boolean[][] used) {
if (count == word.length())
return true;
if (i < 0 || j < 0 || i >= board.length || j >= board[0].length)
return false;
char c = word.charAt(count);
if (board[i][j] != c || used[i][j]) {
return false;
} else {
used[i][j] = true;
}
//左
boolean left = dfs(board, word, count + 1, i, j - 1, used);
//右
boolean right = dfs(board, word, count + 1, i, j + 1, used);
//上
boolean up = dfs(board, word, count + 1, i - 1, j, used);
//下
boolean down = dfs(board, word, count + 1, i + 1, j, used);
if (left || right || up || down)
return true;
used[i][j] = false;
return false;
}