剑指offer 3-12题汇总,比力扣简单,因为简单题和中等题较多。

不知道为啥,力扣上没有第一和第二题,后面也有些题没有。感觉剑指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;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值