开心果🍅 训练营会员 2026-08-27 7:21 下午

    本打卡对应问题:社区项目实战课程说明
    具体打卡内容:

    项目在没了 找不到了

    开心果🍅 训练营会员 2026-08-27 7:17 下午

    本打卡对应问题:社区项目面试提炼+答案总结(重要重要)
    具体打卡内容:

    这个项目视频在哪里呢

    mpweixin用户 永久会员 2026-08-19 5:00 下午

    本打卡对应问题:漫画:什么是选择排序算法?
    具体打卡内容:

    网站图还是出不来嘞

    mpweixin用户 永久会员 2026-06-25 10:10 上午

    本打卡对应问题:Dubbo面试题阅读指南(必看)
    具体打卡内容:

    怎么没有答案

    mpweixin用户 永久会员 2026-06-17 4:36 下午

    本打卡对应问题:进程的地址空间里面有什么?
    具体打卡内容:

    有错误,堆区是从低地址开始向高地址增长的,原文是堆区从高地址开始向低地址扩展。

    浪里个浪 普通 2026-04-19 9:28 下午

    本打卡对应问题:什么是 Cookie?
    具体打卡内容:

    很好

    mpweixin用户 永久会员 2026-04-09 6:52 下午

    本打卡对应问题:什么是SQL 注入?举个例子?
    具体打卡内容:

    加两个–后面没内容了吗

    mpweixin用户 永久会员 2026-03-30 9:06 上午

    本打卡对应问题:C++ 基础面试题阅读指南(必看)
    具体打卡内容:

    为什么我充值了还是看不了?

    mpweixin用户 永久会员 2026-01-29 4:53 下午

    本打卡对应问题:请解释结构体内存布局的规则。
    具体打卡内容:

    这里讲的有问题,可以去知乎看看

    萧瑟瑟 训练营会员 2025-12-30 8:33 下午

    本打卡对应问题:一探究竟:我们写的Java代码到底是如何运行起来的?
    具体打卡内容:

    使用代码混淆器(如ProGuard):会在不改变程序逻辑的前提下,将代码变得极其难以阅读。重命名(有意义的变量名、类名、方法名改成无意义的字符)、控制流混淆(插入大量无用的跳转指令或复杂的逻辑分支)、敏感字符串加密(API密钥、数据库连接串);
    使用本地代码 (JNI/C++):对于极其核心的算法或加密逻辑,可以不使用 Java 编写,而是使用 C/C++ 编写,然后通过 JNI (Java Native Interface) 调用。因为 C/C++ 编译后是二进制机器码,反编译难度比 Java 字节码高出几个数量级(只能通过汇编层面去分析),大大提升了破解成本。
    GraalVM 静态编译:利用GraalVM将Java直接编译成对应操作系统的原生可执行文件(如Windows下的.exe),这种文件不再包含字节码,而是机器码,传统的java反编译器完全失效。
    字节码加密+自定义类加载器:在发布前用对称加密算法对.class文件进行加密,程序运行时通过自定义的类加载器再内存中动态解密并加载类。虽然能防住普通小白,但高手可以通过内存镜像抓取解密后的字节码。
    改变交付模式:SaaS化,不交付代码,云端运行(核心逻辑部署在自己服务器上,只给用户API接口)

    mpweixin用户 永久会员 2025-12-18 4:01 下午

    本打卡对应问题:成为本站会员,解锁面试神器(持续更新)
    具体打卡内容:

    请问我如何购买会员啊

    mpweixin用户 永久会员 2025-11-21 12:24 上午

    本打卡对应问题:如何构造一个类,使得只能在堆上或只能在栈上分配内存?
    具体打卡内容:

    只在堆上分配应该是将默认构造函数删除或者设置为私有,然后提供create方法进行new操作

    五四青年 训练营会员 2025-11-13 8:09 下午

    本打卡对应问题:递归入门与优化 + 例题🌟🌟🌟🌟🌟
    具体打卡内容:

    这个思路太牛了

    mpweixin用户 永久会员 2025-11-11 9:09 下午

    本打卡对应问题:volatile 关键字在 Java 并发编程中有何作用?
    具体打卡内容:

    禁止指令重排序(有序性):volatile 会通过内存屏障(Memory Barrier)防止编译器和 CPU 对代码进行指令重排序。可理解为,volatile 修饰的变量写时,像设置了一个完成的标志一样,保证前面的读写操作已经完成,但不保证原子性,多步操作可能出现问题,如i=i+1,包括读i的原值,改算i+1的值,写i的值,三步分开。volatile 修饰的变量读时,像检查一个完成标志一样,保证之后所有的读都能读取到前面的最新值

    mpweixin用户 永久会员 2025-11-11 5:35 下午

    本打卡对应问题:用 ThreadLocal 类,如何避免内存泄漏的发生?
    具体打卡内容:

    spring的ThreadLocal,自动清理线程对象

    mpweixin用户 永久会员 2025-11-11 4:42 下午

    本打卡对应问题:为什么 ThreadLocal 类中的 Key 要设计为弱引用(WeakReference)?这样做有什么好处?
    具体打卡内容:

    一个是普通对象的共享,一个线程对象的共享

    mpweixin用户 永久会员 2025-11-11 4:41 下午
    mpweixin用户 永久会员 2025-11-04 4:45 下午

    本打卡对应问题:进程的调度算法有哪些?
    具体打卡内容:

    多级反馈队列描述不对,应该是某个进程如果长时间运行,用完时间片后会降优先级

    柠月如风 普通 2025-09-06 10:30 下午

    本打卡对应问题:【二叉树专题】剑指 Offer 07. 重建二叉树
    具体打卡内容:

    /**
    * Definition for a binary tree node.
    * public class TreeNode {
    * int val;
    * TreeNode left;
    * TreeNode right;
    * TreeNode() {}
    * TreeNode(int val) { this.val = val; }
    * TreeNode(int val, TreeNode left, TreeNode right) {
    * this.val = val;
    * this.left = left;
    * this.right = right;
    * }
    * }
    */
    class Solution {
    Map<Integer,Integer> map = new HashMap<>();
    public TreeNode deduceTree(int[] preorder, int[] inorder) {
    if(preorder null || preorder.length <= 0){
    return null;
    }
    for(int i = 0; i < preorder.length ; i++){
    map.put(inorder[i],i);
    }
    TreeNode root = f(preorder,0,preorder.length-1,inorder,0,inorder.length-1);
    return root;

    }
    TreeNode f(int[] preorder , int l1 , int r1 , int[] inorder , int l2, int r2){
    if(l1 > r1 || l2 > r2){
    return null;
    }
    TreeNode root = new TreeNode(preorder[l1]);
    int i = map.get(preorder[l1]);

    root.left = f(preorder,l1+1,l1+i-l2,inorder,l2,i-1);
    root.right = f(preorder,l1+i-l2+1,r1,inorder,i+1,r2);
    return root;
    }

    }代码

    糕冷 训练营会员 2025-09-01 10:02 上午

    本打卡对应问题:什么是数组?
    具体打卡内容:

    // 先删除较大的索引(因为删除后数组会左移,先删大的不会影响小的索引位置)
    for (int i = inx1; i < a.length-1; i++) {
    a[i] = a[i+1]; // 将后面的元素前移,覆盖要删除的元素
    }

    // 再删除较小的索引(此时数组长度已减1,但a.length没变)
    for (int i = inx2; i < a.length-1; i++) {
    a[i] = a[i+1]; // 再次前移元素
    }

    mpweixin用户 永久会员 2025-07-30 7:24 下午

    本打卡对应问题:什么是分库分表?
    具体打卡内容:

    “垂直分表:将一个大的表分割成多个小表,可以是同一个数据库中的多个表,也可以是跨库的。例如,订单表按时间范围进行分割,每年一个表。”这句话有问题吧,给出的示例好像是水平分表

    mpweixin用户 永久会员 2025-07-24 9:09 上午

    本打卡对应问题:简述什么是数据结构?
    具体打卡内容:

    手机端新改版的页面交互:点最下测的题目跳转后定位到了最下面的题目,希望跳转后定位到页面顶部

    几味老友 训练营会员 2025-07-20 9:50 上午

    本打卡对应问题:2025-几味老友
    具体打卡内容:

    7.14-7.20
    1.牛客网项目目前完成了两个功能模块,分页查询以及注册页面的功能逻辑,两个功能还挺复杂的,需要多多回顾;
    2.jvm虚拟机看了两小节,地哥写的通俗易懂,但是看的有些少了,下个星期争取看5篇左右,并且需要不断地回顾加深印象;
    3.算法题刷了两道,层序遍历基础和加强版,加强版那个开始不知道如何统计每一层的结点个数,学到了可以采用当前队列的长度进行统计,下一周争取刷5道哈哈,先刷树专题

    mpweixin用户 永久会员 2025-07-15 7:49 下午

    本打卡对应问题:如何让一个类不能实例化?
    具体打卡内容:

    你好

    mpweixin用户 普通 2025-07-12 11:40 下午

    本打卡对应问题:阐述一下 Go 的 select 底层数据结构和一些特性?
    具体打卡内容:

    牛

    。 训练营会员 2025-07-10 6:42 下午

    本打卡对应问题:深入浅出索引(下)🌟🌟🌟🌟🌟
    具体打卡内容:

    已看

    。 训练营会员 2025-07-09 10:02 下午

    本打卡对应问题:深入浅出索引(上)🌟🌟🌟🌟🌟
    具体打卡内容:

    已看

    。 训练营会员 2025-07-09 9:03 下午

    本打卡对应问题:为什么MySQL数据库要用B+树存储索引?(必看)
    具体打卡内容:

    已看

    。 训练营会员 2025-06-29 10:41 下午

    本打卡对应问题:第三章总结
    具体打卡内容:

    0-25已看

    mpweixin用户 永久会员 2025-06-29 11:09 上午

    本打卡对应问题:类型转换分为哪几种?各自有什么样的特点?
    具体打卡内容:

    const int x = 10;
    int* y = const_cast<int*>(&x); // 去除const,允许修改
    *y = 20; // 修改x的值,虽然它是const的,但这里直接通过指针修改

    这里的指针y并不能改变x的值把,编译器会对其进行优化,x本身是常量不可以改变

    阿瓜 普通 2025-06-28 5:56 下午

    本打卡对应问题:【排序算法运用】剑指 Offer 41. 数据流中的中位数
    具体打卡内容:

    class MedianFinder {
    private:
    std::priority_queue<int, std::vector, std::less> mMax; // 大根堆,保存较小的一半
    std::priority_queue<int, std::vector, std::greater> mMin; // 小根堆,保存较大的一半
    public:
    MedianFinder() {

    }

    /*这套逻辑背后的本质是:
    保持一个平衡的“左右两半”
    左边是最大堆,右边是最小堆
    插入时保证:
    数值上:左边的最大值 ≤ 右边的最小值
    数量上:左边 ≥ 右边(最多多一个)
    这样才可以快速地、始终正确地返回中位数。*/
    void addNum(int num) {
    /*保证下面两个不变量(invariants)始终成立:
    数值顺序不变量:maxHeap.top() ≤ minHeap.top()
    即最大的小数 ≤ 最小的大数 → 这样合并两个堆就是有序的
    数量平衡不变量:maxHeap.size() == minHeap.size() 或 maxHeap.size() == minHeap.size() + 1
    即保证两个堆的大小差距最多为1,并且 maxHeap 元素个数不小于 minHeap*/
    //保证所有数都优先进入“较小的一半”maxHeap,先默认是“小的”。
    mMax.push(num);
    //把 maxHeap 的最大值(可能是刚刚插入的)移动到 minHeap
    // 这样保证了最终 maxHeap里的值 ≤ minHeap里的值,维护了值的正确划分。
    mMin.push(mMax.top());
    mMax.pop();
    //如果 maxHeap 元素比 minHeap 少,就从 minHeap 抽一个回来
    if (mMax.size() < mMin.size()) {
    mMax.push(mMin.top());
    mMin.pop();
    }
    }

    double findMedian() {
    if (mMax.size() == mMin.size()) {
    return (mMax.top() + mMin.top()) / 2.0;
    } else {
    return mMax.top();
    }
    }

    };

    /**
    * Your MedianFinder object will be instantiated and called as such:
    * MedianFinder* obj = new MedianFinder();
    * obj->addNum(num);
    * double param_2 = obj->findMedian();
    */

    阿瓜 普通 2025-06-28 4:05 下午

    本打卡对应问题:【排序算法运用】剑指 Offer 40. 最小的k个数
    具体打卡内容:

    QuickSelect算法class Solution {
    public:
    /最小的K个数:输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。/
    vector inventoryManagement(vector& stock, int cnt) {
    auto& nums = stock;
    if (nums.empty() || cnt <= 0) {
    return {};
    }

    return quickSelect(nums, 0, nums.size() - 1, cnt);
    }

    std::vector<int> quickSelect(std::vector<int>& nums, int left, int right, int k) {
    int i = partition(nums, left, right);

    /* 下标转换
    要找的是最小的前 k 个元素,也就是下标 [0 ... k - 1]
    当 i == k - 1,[0, i] 正好是前 k 小的元素
    */
    if (i + 1 == k) {
    return std::vector<int>(nums.begin(), nums.begin() + k);
    }

    if (i + 1 > k) {
    // i > k-1, 左边已经包含了超过 k 个最小数,继续在左半边查找。
    return quickSelect(nums, 0, i - 1, k);
    } else {
    // i < k - 1, 左边不够 k 个最小数,还需要从右侧补足,在右半边递归找剩下的 k - (i + 1) 个数
    return quickSelect(nums, i + 1, right, k);
    }

    return {};
    }

    int partition(std::vector<int>& nums, int left, int right) {
    int pivot = nums[left];

    while (left < right) {
    while (left < right && nums[right] >= pivot) {
    right--;
    }
    nums[left] = nums[right];
    while (left < right && nums[left] <= pivot) {
    left++;
    }
    nums[right] = nums[left];
    }
    nums[right] = pivot;
    return right;
    }

    };

    这是个名字 永久会员 2025-06-19 12:11 上午

    本打卡对应问题:【动态规划专题】剑指 Offer 48. 最长不含重复字符的子字符串
    具体打卡内容:

    class Solution {
    public:
    int dismantlingAction(string arr) {
    if(arr.empty()) {
    return 0;
    }
    unordered_map<char,int> hash;
    int i=-1,j=0,len=arr.size();
    vector dp(len,0);
    for(j=0;j<len;j++) {
    if(hash.find(arr[j]) != hash.end()) {
    i=max(i,hash.find(arr[j])->second);
    }
    hash[arr[j]]=j;
    if(j0) {
    dp[0]=1;
    }else{
    dp[j]=max(dp[j-1],j-i);
    }
    }
    return dp[len-1];
    }
    };O(N)
    时间复杂度

    这是个名字 永久会员 2025-06-15 9:49 下午

    本打卡对应问题:【动态规划专题】剑指 Offer 47. 礼物的最大价值
    具体打卡内容:

    class Solution {
    public:
    int jewelleryValue(vector<vector>& frame) {
    int m = frame.size();
    if (m 0) return 0; // 处理空矩阵
    int n = frame[0].size();
    vector<vector> dp(m, vector(n, 0));

    // 初始化起点
    dp[0][0] = frame[0][0];

    // 初始化第一行:只能从左侧到达
    for (int j = 1; j < n; j++) {
    dp[0][j] = dp[0][j-1] + frame[0][j];
    }

    // 初始化第一列:只能从上方到达
    for (int i = 1; i < m; i++) {
    dp[i][0] = dp[i-1][0] + frame[i][0];
    }

    // 填充剩余格子:可以从上方或左侧到达
    for (int i = 1; i < m; i++) {
    for (int j = 1; j < n; j++) {
    dp[i][j] = max(dp[i-1][j], dp[i][j-1]) + frame[i][j];
    }
    }

    return dp[m-1][n-1];
    }

    };

    这是个名字 永久会员 2025-06-15 9:33 下午

    本打卡对应问题:【动态规划专题】剑指 Offer 63. 股票的最大利润
    具体打卡内容:

    class Solution {
    public:
    int bestTiming(vector& prices) {
    int minprice=numeric_limits::max(),maxprofit=0;
    for(int price:prices) {
    maxprofit=max(maxprofit,price-minprice);
    minprice=min(minprice,price);
    }
    return maxprofit;
    }
    };时间复杂度O(N)

    这是个名字 永久会员 2025-06-11 10:54 下午

    本打卡对应问题:【动态规划】剑指 Offer 42. 连续子数组的最大和
    具体打卡内容:

    class Solution {
    public:
    int maxSales(vector& sales) {
    int pre=0,maxone=sales[0];
    for(int i:sales) {
    pre=max(pre+i,i);
    maxone=max(pre,maxone);
    }
    return maxone;
    }
    };时间复杂度O(N)

    这是个名字 永久会员 2025-06-11 9:01 下午

    本打卡对应问题:【回溯专题】剑指 Offer 38. 字符串的排列
    具体打卡内容:

    class Solution {
    public:
    vector goodsOrder(string goods) {
    vector res;
    sort(goods.begin(),goods.end());
    do{
    res.push_back(goods);
    }while(next_permutation(goods.begin(),goods.end()));
    return res;
    }
    };时间复杂度O(N!)

    这是个名字 永久会员 2025-06-11 8:53 下午

    本打卡对应问题:【回溯专题】剑指 Offer 34. 二叉树中和为某一值的路径
    具体打卡内容:

    /**
    * Definition for a binary tree node.
    * struct TreeNode {
    * int val;
    * TreeNode left;
    * TreeNode *right;
    * TreeNode() : val(0), left(nullptr), right(nullptr) {}
    * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
    * };
    */
    class Solution {
    public:
    vector<vector> res;
    vector path;
    vector<vector> pathTarget(TreeNode
    root, int target) {
    preOrderTraversal(root,target);
    return res;
    }

    void preOrderTraversal(TreeNode* root, int target) {
    if(root==nullptr) return;
    path.push_back(root->val);
    target-=root->val;
    if(target==0 && root->left==nullptr && root->right==nullptr) {
    res.push_back(path);
    }
    preOrderTraversal(root->left,target);
    preOrderTraversal(root->right,target);
    path.pop_back();
    }

    };
    时间复杂度O(N)

    这是个名字 永久会员 2025-06-11 8:35 下午

    本打卡对应问题:【回溯专题】剑指 Offer 13. 机器人的运动范围
    具体打卡内容:

    class Solution {
    public:
    int m,n,cnt;
    vector<vector> visit;
    int wardrobeFinishing(int m, int n, int cnt) {
    this->m=m;
    this->n=n;
    this->cnt=cnt;
    visit.resize(m, vector(n, false));
    return dfs(0,0);
    }

    int dfs(int i, int j) {
    if(i<0 || i>=m || j<0 || j>=n || digit(i)+digit(j)>cnt || visit[i][j]) {
    return 0;
    }

    visit[i][j]=true;
    return 1+dfs(i+1,j)+dfs(i,j+1);
    }

    int digit(int num) {
    int res=0;
    while(num!=0) {
    res+=num%10;
    num/=10;
    }
    return res;
    }

    };
    时间复杂度O(M∗N)

    这是个名字 永久会员 2025-06-11 1:39 上午

    本打卡对应问题:【回溯专题】剑指 Offer 12. 矩阵中的路径
    具体打卡内容:

    class Solution {
    public:
    int n, m, len;
    vector<vector> visit;
    bool wordPuzzle(vector<vector>& grid, string target) {
    this->n = grid.size(), this->m = grid[0].size(), this->len = target.size();
    visit.resize(n, vector(m, false)); // 初始化visit数组

    for(int i = 0; i < n; i++) {
    for(int j = 0; j < m; j++) {
    if(dfs(grid, i, j, target, 0)) {
    return true;
    }
    }
    }
    return false;
    }

    bool dfs(vector<vector<char>>& grid, int i, int j, string target, int k) {
    if(i < 0 || i >= n || j < 0 || j >= m || grid[i][j] != target[k] || visit[i][j]) {
    return false;
    }

    if(k == len - 1) {
    return true;
    }

    visit[i][j] = true;
    bool res = (dfs(grid, i + 1, j, target, k + 1) ||
    dfs(grid, i - 1, j, target, k + 1) ||
    dfs(grid, i, j + 1, target, k + 1) ||
    dfs(grid, i, j - 1, target, k + 1) );
    visit[i][j] = false;
    return res;
    }

    };

    初 训练营会员 2025-06-10 4:35 下午

    本打卡对应问题:【回溯专题】剑指 Offer 34. 二叉树中和为某一值的路径
    具体打卡内容:

    class Solution {
    // 用于存储所有满足条件的路径
    List<List> res;
    // 用于临时存储当前路径
    List tmp;

    // 主函数:寻找所有从根节点到叶子节点的路径,使得路径上节点的值之和等于目标值
    public List<List<Integer>> pathSum(TreeNode root, int target) {
    // 初始化结果列表和临时路径
    res = new ArrayList<>();
    tmp = new ArrayList<>();
    // 调用深度优先搜索函数
    dsf(root, target);
    // 返回最终结果
    return res;
    }

    // 深度优先搜索辅助函数
    void dsf(TreeNode root, int target) {
    // 如果当前节点为空,直接返回
    if (root == null) {
    return;
    }

    // 将当前节点的值加入临时路径
    tmp.add(root.val);
    // 更新目标值:减去当前节点的值
    target = target - root.val;

    // 如果当前节点是叶子节点,并且目标值为 0
    if (root.left == null && root.right == null && target == 0) {
    // 将当前路径加入结果列表(注意需要创建一个新的 ArrayList,避免后续修改影响结果)
    res.add(new ArrayList<>(tmp));
    }

    // 递归处理左子树
    dsf(root.left, target);
    // 递归处理右子树
    dsf(root.right, target);

    // 回溯:移除当前节点的值,恢复临时路径的状态
    tmp.remove(tmp.size() - 1);
    }

    }
    时间复杂度:O(n)
    空间复杂度:O(n)

    初 训练营会员 2025-06-09 4:58 下午

    本打卡对应问题:【回溯专题】剑指 Offer 13. 机器人的运动范围
    具体打卡内容:

    class Solution {
    int m; // 棋盘的行数
    int n; // 棋盘的列数
    int k; // 位数和的限制
    boolean[][] visited; // 用于记录每个格子是否被访问过

    // 主方法,计算机器人能够到达的格子数量
    public int movingCount(int m, int n, int k) {
    this.m = m; // 初始化棋盘的行数
    this.n = n; // 初始化棋盘的列数
    this.k = k; // 初始化位数和的限制
    visited = new boolean[m][n]; // 初始化访问记录数组,初始值为 false

    return dfs(0, 0); // 从左上角 (0,0) 开始深度优先搜索
    }

    // 深度优先搜索方法
    int dfs(int i, int j) {
    // 判断当前格子是否在棋盘范围内、是否未被访问过、位数和是否小于等于 k
    if (i < 0 || j < 0 || i >= m || j >= n || visited[i][j] || k < sum(i) + sum(j)) {
    return 0; // 如果不满足条件,返回 0
    }

    visited[i][j] = true; // 标记当前格子为已访问
    // 递归计算向右和向下移动的结果,并加 1 表示当前格子
    return 1 + dfs(i + 1, j) + dfs(i, j + 1);
    }

    // 计算一个数字的位数和
    int sum(int x) {
    int res = 0; // 初始化结果为 0
    while (x != 0) {
    res = res + x % 10; // 取出最低位并累加
    x = x / 10; // 去掉最低位
    }
    return res; // 返回位数和
    }

    }
    时间复杂度:O(mn)
    空间复杂度:O(mn)

    初 训练营会员 2025-06-09 4:13 下午

    本打卡对应问题:【回溯专题】剑指 Offer 12. 矩阵中的路径
    具体打卡内容:

    class Solution {
    int n; // board的行数
    int m; // board的列数
    int len; // word的长度
    boolean[][] visited; // 标记数组,记录某个位置是否被访问过

    // 主函数,判断单词是否存在于board中
    public boolean exist(char[][] board, String word) {
    this.n = board.length; // 获取board的行数
    this.m = board[0].length; // 获取board的列数
    this.len = word.length(); // 获取目标单词的长度
    visited = new boolean[n][m]; // 初始化visited数组

    // 遍历board的每一个位置,尝试从每个位置开始搜索
    for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
    // 如果从位置(i, j)开始能够找到单词,则返回true
    if (dsf(board, i, j, word, 0)) {
    return true;
    }
    }
    }

    // 如果遍历完所有位置都没有找到单词,则返回false
    return false;
    }

    // 深度优先搜索函数,从位置(i, j)开始,尝试匹配word的第k个字符
    boolean dsf(char[][] board, int i, int j, String word, int k) {
    // 判断是否越界,或者当前位置的字符与目标字符不匹配
    if (i < 0 || i >= n || j < 0 || j >= m || board[i][j] != word.charAt(k)) {
    return false;
    }

    // 如果已经匹配到目标单词的最后一个字符,说明找到了单词
    if (k == len - 1) {
    return true;
    }

    // 标记当前位置为已访问,避免重复访问
    // visited[i][j] = true;
    board[i][j] = 'n'; // 通过修改字符为'n'来标记已访问

    // 从当前位置向四个方向(上下左右)继续搜索
    boolean res = dsf(board, i, j + 1, word, k + 1) || // 向右搜索
    dsf(board, i + 1, j, word, k + 1) || // 向下搜索
    dsf(board, i, j - 1, word, k + 1) || // 向左搜索
    dsf(board, i - 1, j, word, k + 1); // 向上搜索

    // 恢复当前位置的字符,以便后续搜索使用
    board[i][j] = word.charAt(k);
    return res; // 返回搜索结果
    }

    }
    时间复杂度:O(3^K * MN) : 最差情况下,需要遍历矩阵中长度为 KK 字符串的所有方案,时间复杂度为 O(3^K);矩阵中共有 MN 个起点,时间复杂度为 O(MN)
    空间复杂度:O(k)

    初 训练营会员 2025-06-09 3:28 下午

    本打卡对应问题:【排序算法运用】剑指 Offer 51. 数组中的逆序对
    具体打卡内容:

    class Solution {
    /**
    * 主函数,用于计算数组中的逆序对数量
    * @param nums 输入数组
    * @return 逆序对的数量
    */
    public int reversePairs(int[] nums) {
    if (nums null || nums.length <= 1) {
    return 0; // 如果数组为空或只有一个元素,没有逆序对
    }
    return mergeSort(nums, 0, nums.length – 1); // 调用归并排序函数
    }

    /**
    * 归并排序函数,递归地将数组分成两部分,并计算逆序对数量
    * @param nums 输入数组
    * @param left 当前区间的左边界
    * @param right 当前区间的右边界
    * @return 当前区间内的逆序对数量
    */
    int mergeSort(int[] nums, int left, int right) {
    if (left >= right) {
    return 0; // 如果区间只有一个元素,没有逆序对
    }
    int mid = (right - left) / 2 + left; // 计算中间索引
    int x1 = mergeSort(nums, left, mid); // 递归处理左半部分
    int x2 = mergeSort(nums, mid + 1, right); // 递归处理右半部分
    int x3 = merge(nums, left, mid, mid + 1, right); // 合并两个有序数组并计算逆序对

    return x1 + x2 + x3; // 返回总逆序对数量
    }

    /**
    * 合并函数,用于合并两个有序数组,并计算跨区间的逆序对数量
    * @param nums 输入数组
    * @param l1 左半部分的左边界
    * @param r1 左半部分的右边界
    * @param l2 右半部分的左边界
    * @param r2 右半部分的右边界
    * @return 跨区间的逆序对数量
    */
    int merge(int[] nums, int l1, int r1, int l2, int r2) {
    int[] temp = new int[r2 - l1 + 1]; // 创建临时数组用于合并
    int count = 0; // 用于记录逆序对数量
    int i = l1, j = l2, k = 0; // 初始化指针

    // 合并两个有序数组
    while (i <= r1 && j <= r2) {
    if (nums[i] > nums[j]) {
    // 如果左半部分的当前元素大于右半部分的当前元素
    count = count + (r1 - i + 1); // 计算逆序对数量
    temp[k++] = nums[j++]; // 将右半部分的元素加入临时数组
    } else {
    temp[k++] = nums[i++]; // 将左半部分的元素加入临时数组
    }
    }

    // 处理左半部分剩余的元素
    while (i <= r1) {
    temp[k++] = nums[i++];
    }

    // 处理右半部分剩余的元素
    while (j <= r2) {
    temp[k++] = nums[j++];
    }

    // 将临时数组的内容复制回原数组
    k = 0;
    for (i = l1; i <= r2; i++) {
    nums[i] = temp[k++];
    }

    return count; // 返回逆序对数量
    }

    }
    复杂度和归并排序一样
    时间:O(nlogn)
    空间:O(n)

    初 训练营会员 2025-06-09 3:05 下午

    本打卡对应问题:【排序算法运用】剑指 Offer 41. 数据流中的中位数
    具体打卡内容:

    class MedianFinder {
    Queue min, max; // 定义两个优先队列,分别用于存储数据

    /**
    * 初始化数据结构
    */
    public MedianFinder() {
    min = new PriorityQueue<>();
    // 小根堆,用于存储较大的一半数据
    max = new PriorityQueue<>((x, y) -> (y - x));
    // 大根堆,用于存储较小的一半数据
    }

    /**
    * 向数据结构中添加一个数字
    * @param num 要添加的数字
    */
    public void addNum(int num) {
    // 如果两个堆的大小相等(即当前数据总数为偶数)
    if (min.size() == max.size()) {
    // 先将数字加入到小根堆min中
    min.add(num);
    // 然后将min的堆顶元素(即当前较大的一半中的最小值)弹出
    // 并加入到大根堆max中
    max.add(min.poll());
    } else {
    // 如果两个堆的大小不相等(即当前数据总数为奇数)
    // 先将数字加入到大根堆max中
    max.add(num);
    // 然后将max的堆顶元素(即当前较小的一半中的最大值)弹出
    // 并加入到小根堆min中
    min.add(max.poll());
    }
    }

    /**
    * 返回当前数据的中位数
    * @return 中位数
    */
    public double findMedian() {
    // 如果两个堆的大小相等(即数据总数为偶数)
    if (min.size() == max.size()) {
    // 中位数是两个堆顶元素的平均值
    return (min.peek() + max.peek()) / 2.0;
    } else {
    // 如果两个堆的大小不相等(即数据总数为奇数)
    // 中位数是大根堆max的堆顶元素
    return max.peek() * 1.0;
    }
    }

    }
    时间复杂度:1. 查找中位数 O(1), 2. 插入元素:O(logn)
    空间复杂度:O(n)

    。 训练营会员 2025-06-08 10:01 下午

    本打卡对应问题:Mybatis注解开发方式
    具体打卡内容:

    p22已看

    。 训练营会员 2025-06-08 8:57 下午

    本打卡对应问题:第二章:MyBatis日志管理(没时间的第二章的内容可以 不看)
    具体打卡内容:

    1-14已看

    。 训练营会员 2025-06-06 10:23 下午

    本打卡对应问题:sleep和wait的区别
    具体打卡内容:

    阅