《剑指offer第2版》Java题解总结(上)

  • Post author:
  • Post category:java


03-19
20-39
《剑指offer第2版》Java题解总结(中)_科技小猎豹的博客-CSDN博客
40-68

03-19


03. 数组中重复的数字

数组元素交换。时间On,空间O1.


剑指Offer系列(java版,详细解析) 03. 数组中重复的数字_Hi丶ImViper的博客-CSDN博客

三种语言题解:

https://github.com/doocs/leetcode/blob/main/lcof/%E9%9D%A2%E8%AF%95%E9%A2%9803.%20%E6%95%B0%E7%BB%84%E4%B8%AD%E9%87%8D%E5%A4%8D%E7%9A%84%E6%95%B0%E5%AD%97/README.md


04.二维数组中的查找

本题与力扣 240 题同

法二:从左下角或右上角搜索。时间复杂度 O(m+n),空间复杂度 O(1)。为矩阵的行数、列数。


leetcode/lcof/面试题04. 二维数组中的查找 at main · doocs/leetcode · GitHub


05.替换空格

自己遍历比replace()更快


06.从尾到头打印链表


剑指Offer系列(java版,详细解析)06.从尾到头打印链表_Hi丶ImViper的博客-CSDN博客

头插法、栈、递归多种方法。


07. 重建二叉树

本题与主站 105 题重复

测试用例

普通二叉树(完全二叉树;不完全二叉树)

特殊二叉树(所有节点都没有右子节点的二叉树;所有节点都没有左子节点的二叉树;只有一个节点的二叉树)

特殊输入测试(二叉树的根节点为空;输入的前序序列和中序序列不匹配)


力扣

只适用于无重复节点二叉树。分治


08.二叉树的下一个节点

中序遍历


09.用两个栈实现队列


leetcode/lcof/面试题09. 用两个栈实现队列 at main · doocs/leetcode · GitHub


10-I.斐波那契数列问题

动态规划

力扣


10- II. 青蛙跳台阶问题


11. 旋转数组的最小数字

与主站 154 题相同


力扣


12. 矩阵中的路径

( DFS + 剪枝


力扣​​​​​​

class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words = word.toCharArray();

        // 遍历图
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {

                // 如果找到了,就返回true。否则继续找
                if(dfs(board, words, i, j, 0)) return true;
            }
        }

        // 遍历结束没找到false
        return false;
    }
    boolean dfs(char[][] board, char[] word, int i, int j, int k) {
        // 判断传入参数的可行性 i 与图行数row比较,j与图列数col比较
        // i,j初始都是0,都在图左上角
        // k是传入字符串当前索引,一开始是0,如果当前字符串索引和图当前索引对应的值不相等,表示第一个数就不相等
        // 所以继续找第一个相等的数。题目说第一个数位置不固定,即路径起点不固定(不一定是左上角为第一个数)

        // 如果board[i][j] == word[k],则表明当前找到了对应的数,就继续执行(标记找过,继续dfs 下上右左)
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
        // 表示找完了,每个字符都找到了
        // 一开始k=0,而word.length肯定不是0,所以没找到,就执行dfs继续找。
        if(k == word.length - 1) return true;   

        // 访问过的标记空字符串,“ ”是空格 '\0'是空字符串,不一样的!
        // 比如当前为A,没有标记找过,且A是word中对应元素,则此时应该找A下一个元素,假设是B,在dfs(B)的时候还是-
        // ->要搜索B左边的元素(假设A在B左边),所以就是ABA(凭空多出一个A,A用了2次,不可以),如果标记为空字符串->
        // 就不会有这样的问题,因为他们值不相等AB != ABA。 
        board[i][j] = '\0';

        // 顺序是 下 上 右 左;上面找到了对应索引的值所以k+1
        boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || 
                      dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
        
        // 还原找过的元素,因为之后可能还会访问到(不同路径)
        board[i][j] = word[k];

        // 返回结果,如果false,则if(dfs(board, words, i, j, 0)) return true;不会执行,就会继续找
        return res;
    }
}


13.机器人的运动范围

数位和增量公式:

力扣


以下代码为增量公式的三元表达式写法,将整合入最终代码中。

(x + 1) % 10 != 0 ? s_x + 1 : s_x – 8;


14- I. 剪绳子

与主站 343 题相同

动规、数学等等

力扣

关于为什么切分为3的优先级最高 可以利用均值不等式求出乘积最大值 L(m)=(n/m)^m 对此式求导(可利用对数法),可以证明当 m=n/e 时,乘积取最大,此时每段绳子的长度为 n/(n/e)=e,自然对数e的值为2.718,显然接近3,所以总体来讲3最好

class Solution {
    public int cuttingRope(int n) {
        if(n <= 3) return n - 1;
        int a = n / 3, b = n % 3;
        if(b == 0) return (int)Math.pow(3, a);
        if(b == 1) return (int)Math.pow(3, a - 1) * 4;
        return (int)Math.pow(3, a) * 2;
    }
}


14- II. 剪绳子 II       大数越界情况下的求余问题


力扣

大数求余!

力扣

class Solution {
    public int cuttingRope(int n) {
        if(n == 2) return 1;
        if(n == 3) return 2;

        int a = n / 3;
        int b = n % 3;
        // ans * 3 可能在求余之前超出int32的值,所以用long类型
        long ans = 1;
        switch(b) {
            case 0 :
                for(int i = 0; i < a; i++) {
                    ans = ans * 3 % 1000000007 ;
                }
            break;
            case 1 :
                for(int i = 0; i < a - 1; i++) {
                    ans = ans * 3 % 1000000007 ;
                }
                ans = ans * 4  % 1000000007;
            break;
            case 2 :
                for(int i = 0; i < a; i++) {
                    ans = ans * 3 % 1000000007 ;
                }
                ans = ans * 2  % 1000000007;
            break; 
        }
        return (int)ans;
    }
}


15. 二进制中1的个数


力扣

,=主站191

力扣

public int hammingWeight(int n) {
        int res = 0;
        while(n != 0) {
            res += n & 1;
            n >>>= 1;
        }
        return res;
    }


16. 数值的整数次方

与主站 50 题相同:

力扣

快速幂(数论),在普通计算机内,数是用补码表示滴,而这里b = -b 和 b = -n就隐藏着这个坑。int由于补码无法表示+2147483648。b不能用-n赋值,必须用-b 因为b是long的 可以表示+2147483648


力扣

K佬题解


17. 打印从1到最大的n位数

String表示大数,全排列dfs。

Integer.parseInt这个接口,会自动把整数前面的0去掉。(此法速度慢)

class Solution {
    char[] num;
    int[] ans;
    int count = 0,n;
    public int[] printNumbers(int n) {
        this.n = n;
        num = new char[n];
        ans = new int[(int) (Math.pow(10, n) - 1)];
        dfs(0);
        return ans;
    }
    private void dfs(int n) {
        if (n == this.n) {
            String tmp = String.valueOf(num);
            int curNum = Integer.parseInt(tmp);
            if (curNum!=0) ans[count++] = curNum;
            return;
        }
        for (char i = '0'; i <= '9'; i++) {
            num[n] = i;
            dfs(n + 1);
        }
    }
}


18. 删除链表的节点

注意各种特殊情况、限制条件。

public ListNode deleteNode(ListNode head, int val) {
        if(head.val == val) return head.next;
        ListNode pre = head, cur = head.next;
        while(cur != null && cur.val != val) {
            pre = cur;
            cur = cur.next;
        }
        if(cur != null) pre.next = cur.next;
        return head;
    }


19. 正则表达式匹配

hard,动规or递归

class Solution {
    public boolean isMatch(String A, String B) {
        int n = A.length();
        int m = B.length();
        boolean[][] f = new boolean[n + 1][m + 1];

        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= m; j++) {
                //分成空正则和非空正则两种
                if (j == 0) {
                    f[i][j] = i == 0;
                } else {
                    //非空正则分为两种情况 * 和 非*
                    if (B.charAt(j - 1) != '*') {
                        if (i > 0 && (A.charAt(i - 1) == B.charAt(j - 1) || B.charAt(j - 1) == '.')) {
                            f[i][j] = f[i - 1][j - 1];
                        }
                    } else {
                        //碰到 * 了,分为看和不看两种情况
                        //不看
                        if (j >= 2) {
                            f[i][j] |= f[i][j - 2];
                        }
                        //看
                        if (i >= 1 && j >= 2 && (A.charAt(i - 1) == B.charAt(j - 2) || B.charAt(j - 2) == '.')) {
                            f[i][j] |= f[i - 1][j];
                        }
                    }
                }
            }
        }
        return f[n][m];
    }
}



版权声明:本文为qq_41227539原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。