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的区别
    具体打卡内容:

    训练营会员 2025-06-06 9:53 下午

    本打卡对应问题:线程的状态.
    具体打卡内容:

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

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

    归并排序

    class Solution {
    public:
    int reversePairs(vector& record) {
    if(record.empty()) return 0;
    int cnt=0;
    cnt=mergesort(record,0,record.size()-1);
    return cnt;
    }
    private:
    int mergesort(vector& record,int left,int right) {
    int mid=0,cnt=0;
    if(left<right) {
    mid=(right-left)/2+left;
    cnt+=mergesort(record,left,mid);
    cnt+=mergesort(record,mid+1,right);
    cnt+=merge(record,left,mid,right);
    }
    return cnt;
    }

    int merge(vector<int>& record,int left,int mid,int right) {
    int m=mid-left+1,n=right-mid;
    vector<int> L(m),R(n);
    int i,j,k,cnt=0;
    for (int i = 0; i < m; ++i) {
    L[i] = record[left + i];
    }
    for (int j = 0; j < n; ++j) {
    R[j] = record[mid + 1 + j];
    }
    i=0,j=0,k=left;
    while(i<m && j<n) {
    if(L[i] <= R[j]) {
    record[k++]=L[i++];
    }else {
    record[k++]=R[j++];
    cnt+=m-i;
    }
    }
    while(i < m) {
    record[k++]=L[i++];
    }
    while(j < n) {
    record[k++]=R[j++];
    }
    return cnt;
    }

    };

    训练营会员 2025-06-06 7:09 下午

    本打卡对应问题:如何实现处理线程的返回值
    具体打卡内容:

    训练营会员 2025-06-06 5:51 下午

    本打卡对应问题:Thread和Runnable的关系
    具体打卡内容:

    训练营会员 2025-06-06 5:01 下午

    本打卡对应问题:线程的start和run方法的区别
    具体打卡内容:

    训练营会员 2025-06-06 3:51 下午

    本打卡对应问题:进程和线程的区别
    具体打卡内容:

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

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

    快排:
    class Solution {
    public:
    vector inventoryManagement(vector& stock, int cnt) {
    if(stock.empty()||cnt0) return {};
    return quickFind(stock,0,stock.size()-1,cnt);
    }
    private:
    vector quickFind(vector& stock, int left,int right,int cnt) {
    int i=patition(stock,left,right);
    if(i+1cnt) {
    vector find(stock.begin(),stock.begin()+cnt);
    return find;
    }else if(i+1>cnt) {
    return quickFind(stock,left,i-1,cnt);
    }else {
    return quickFind(stock,i+1,right,cnt);
    }
    }

    int patition(vector<int>& stock, int left,int right) {
    int pivot=stock[left];
    int i=left,j=right;
    while(i<j) {
    while(i<=j && pivot >= stock[i]) i++;
    while(i<=j && pivot < stock[j]) j--;
    if(i>=j) break;
    swap(stock[i],stock[j]);
    }
    swap(stock[j],stock[left]);
    return j;
    }

    };

    2.堆排序
    class Solution {
    public:
    vector inventoryManagement(vector& stock, int cnt) {
    vector vec;
    if(stock.empty() || cnt0) return vec;
    priority_queue maxHeap;
    for(int i=0;i<cnt;i++) {
    maxHeap.push(stock[i]);
    }
    for(int i=cnt;i<(int)stock.size(); i++){
    if(stock[i] < maxHeap.top()) {
    maxHeap.pop();
    maxHeap.push(stock[i]);
    }
    }
    for(int i=0;i<cnt;i++) {
    vec.push_back(maxHeap.top());
    maxHeap.pop();
    }
    return vec;
    }
    };

    启龙 永久会员 2025-06-05 10:56 下午

    本打卡对应问题:ind()和binary_search()有什么区别?
    具体打卡内容:

    应该是这个吧,find()和binary_search()有什么区别?

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

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

    class Solution {
    public:
    string crackPassword(vector& password) {
    vector strs;
    for(int num : password) {
    strs.push_back(to_string(num));
    }
    quicksort(strs, 0, strs.size() – 1);
    string complete;
    for(string s : strs) {
    complete.append(s);
    }
    return complete;
    }
    private:
    void quicksort(vector& strs, int left, int right) {
    if(left >= right) return;
    int pivot = partition(strs, left, right);
    quicksort(strs, left, pivot – 1);
    quicksort(strs, pivot + 1, right);
    }

    int partition(vector<string>& strs, int left, int right) {
    string pivot = strs[left];
    int i = left, j = right;
    while (i < j) {
    // 从右向左找第一个比基准小的元素
    while (i < j && (strs[j] + pivot >= pivot + strs[j])) {
    j--;
    }
    // 从左向右找第一个比基准大的元素
    while (i < j && (strs[i] + pivot <= pivot + strs[i])) {
    i++;
    }
    if (i < j) {
    swap(strs[i], strs[j]);
    }
    }
    swap(strs[left], strs[j]);
    return j;
    }

    };

    Z-COM Industry 永久会员 2025-06-05 7:20 下午

    本打卡对应问题:【二叉树专题】剑指 Offer 55 – II. 平衡二叉树
    具体打卡内容:

    // 自底向上
    public static boolean isBalanced(TreeNode root) {
    return dfs(root) != -1;
    }

    public static int dfs(TreeNode root) {

    if (root == null) {
    return 0;
    }

    int count_left = dfs(root.left);
    if (count_left == -1) {
    return -1;
    }

    int count_right = dfs(root.right);

    // 若在向上归的过程中发现了某个子树不平衡, 则层层向上返回-1, 无需再去递归另一边的某个(大)子树
    if (count_right == -1 || Math.abs(count_left - count_right) > 1) {
    return -1;
    }

    // 层层向上返回子树的深度
    return Math.max(count_left, count_right) + 1;
    }

    柠月如风 普通 2025-06-05 11:18 上午

    本打卡对应问题:【二分查找专题】给出四种二分查找的模板
    具体打卡内容:

    package sort;

    public class BanarySort {

    public static void main(String[] args) {
    int[] arr = new int[]{1, 2,3,3,3,4,5,5,7};
    int target = 3;
    int index = floor_lower(arr, target);
    System.out.println("index = "+ index + ", value = " + arr[index]);

    }

    //1.寻找第一个大于 target 的元素的下标,案例:arr[1, 2,3,3,3,4,5,5,7], target = 3。
    public static int upper(int[] arr, int target){
    // 二分查找需要想清楚的点
    int l = 0;
    int r = arr.length - 1;
    // 判断特殊情况
    if(arr[r] <= target){
    return -1;
    }
    //[l,r],,在我们二分查找的过程中,不断缩小我们的查找范围,直到范围里面只有一个元素,那个就是我们要找的元素了
    while(l < r){
    int mid = (r - l) / 2 + l;
    if(arr[mid] > target){
    //[l ,mid, r]
    r = mid;
    } else if(arr[mid] == target){
    l = mid + 1;
    }else {//arr[mid] < target
    l = mid + 1;
    }
    }
    return l;
    }

    //2.如果数组中存在元素等于 target,则返回最后一个等于target 的元素下标,
    // 如果不存在,则返回第一个大于 target 的元素下标
    //案例:arr[1, 2,3,3,3,4,5,5,7], target = 3。
    public static int floor_upper(int[] arr, int target){
    int l = 0;
    int r = arr.length - 1;
    // 判断特殊情况
    if(arr[r] < target){
    return -1;
    }
    //[l,r],,在我们二分查找的过程中,不断缩小我们的查找范围,直到范围里面只有一个元素,那个就是我们要找的元素了
    while(l < r){
    int mid = (r - l) / 2 + l;
    if(arr[mid] > target){
    //[l ,mid, r]
    r = mid;
    } else if(arr[mid] == target){
    l = mid + 1;
    }else {//arr[mid] < target
    l = mid + 1;
    }
    }

    if(l - 1 >= 0 && arr[l - 1] == target){
    return l -1;
    }

    return l;
    }

    //3.寻找最后一个小于 target 的元素的下标
    // [1, 2,3,3,3,4,5,5,7],target = 3;
    public static int lower(int[] arr, int target){
    int l = 0;
    int r = arr.length - 1;
    // 判断特殊情况
    if(arr[l] >= target){
    return -1;
    }
    //[l,r],,在我们二分查找的过程中,不断缩小我们的查找范围,直到范围里面只有一个元素,那个就是我们要找的元素了
    while(l < r){
    // r = 1,l = 0,mid = 0
    int mid = (r - l + 1) / 2 + l;
    if(arr[mid] > target){
    //[l ,mid, r]
    r = mid - 1;
    } else if(arr[mid] == target){
    r = mid - 1;
    }else {//arr[mid] < target
    l = mid;
    }
    }
    //
    return l;
    }

    // 4.如果数组中存在元素等于 target,则返回第一个等于target 的下标,
    // 如果不存在,则返回最后一个小于 target 的元素的下标
    //[1, 2,3,3,3,4,5,5,7],target = 3;
    public static int floor_lower(int[] arr, int target){
    int l = 0;
    int r = arr.length - 1;
    // 判断特殊情况
    if(arr[l] > target){
    return -1;
    }
    //[l,r],,在我们二分查找的过程中,不断缩小我们的查找范围,直到范围里面只有一个元素,那个就是我们要找的元素了
    while(l < r){
    // r = 1,l = 0,mid = 0
    int mid = (r - l + 1) / 2 + l;
    if(arr[mid] > target){
    //[l ,mid, r]
    r = mid - 1;
    } else if(arr[mid] == target){
    r = mid - 1;
    }else {//arr[mid] < target
    l = mid;
    }
    }
    //
    if(l + 1 < arr.length && arr[l + 1] == target){
    return l + 1;
    }
    return l;
    }

    }