写算法题的注意点

在做编程题目,特别是在解决算法问题时,确实经常会遇到不能一次性通过所有测试用例的情况。这是一个常见的挑战,但有一些策略可以帮助你提高通过率,减少反复调试的次数:

  1. 彻底理解题目

    • 在开始编码之前,确保你完全理解了题目的要求和限制。阅读题目几遍,确保没有遗漏任何细节。
  2. 思考边界条件

    • 考虑所有可能的边界条件,例如空输入、最小输入、最大输入限制等。这些往往是出错的地方。
  3. 手动模拟算法

    • 在纸上或在脑中手动模拟你的算法步骤,使用几个简单的例子。这可以帮助你理解你的算法是否覆盖了所有情况。
  4. 写伪代码

    • 在编写实际代码之前,用伪代码(或简单的步骤说明)草拟解决方案。这有助于你组织思路并分解复杂问题。
  5. 增量开发和测试

    • 开始时,解决一些基本情况,然后逐步添加代码以处理更复杂的情况。在每一步后都进行测试,确保新增加的代码不会破坏已有的功能。
  6. 使用断言

    • 在关键的地方使用断言来确保数据符合预期。这可以在开发过程中早期捕捉错误。
  7. 编写自己的测试用例

    • 在提交解决方案前,尝试编写并运行自己的测试用例。尽量考虑不同的情况,特别是那些不寻常或极端的情况。
  8. 理解和使用数据结构及算法

    • 确保你选择了合适的数据结构和算法。不恰当的选择可能导致性能问题,甚至错误。
  9. 阅读题解和讨论区

    • 如果你发现自己卡住了,查看别人是如何解决这个问题的。学习别人的思路和方法可以帮助你发现自己的盲点。
  10. 持续学习和实践

    • 通过持续学习和实践,你会逐渐熟悉各种类型的问题和典型的解决方案。这将帮助你在面对新问题时更加自信和高效。

是的,对于使用深度优先搜索(DFS)处理网格或图的问题,确实存在一些通用的模板或模式,这些可以帮助你快速设置并解决问题。这里我将提供一个针对二维网格中常见问题的 DFS 模板,特别是对于处理类似“岛屿数量”这类问题非常有用。

DFS 模板

以下是一个基于网格的 DFS 搜索模板,适用于许多包括搜索岛屿、迷宫路径等在内的问题:

  1. 设置全局变量:通常需要设置一些全局变量来存储网格的尺寸,有时还需要记录已访问的位置。

  2. 定义 DFS 函数

    • 确保当前位置有效(在网格范围内,满足特定条件,如是陆地而非水域)。
    • 标记当前位置为已访问。
    • 对于当前位置的每一个可能的移动(上、下、左、右),递归地调用 DFS。
  3. 主函数体

    • 遍历每个单元格。
    • 对未访问的和满足条件的单元格启动 DFS。
    • 每次从 DFS 返回时,根据需要更新计数器或执行其他操作(例如,每次调用 DFS 代表一个岛屿)。

JavaScript 实现

function dfs(grid, i, j) {
    if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] !== '1') {
        // 确保不越界且当前是未访问的陆地
        return;
    }
    grid[i][j] = '0'; // 标记此格为已访问,避免重复访问

    // 向四个方向递归搜索
    dfs(grid, i + 1, j); // 下
    dfs(grid, i - 1, j); // 上
    dfs(grid, i, j + 1); // 右
    dfs(grid, i, j - 1); // 左
}

function numIslands(grid) {
    if (!grid.length) return 0;
    let count = 0;

    for (let i = 0; i < grid.length; i++) {
        for (let j = 0; j < grid[0].length; j++) {
            if (grid[i][j] === '1') {
                dfs(grid, i, j);
                count++; // 每完成一次 DFS 搜索,岛屿计数增加
            }
        }
    }

    return count;
}

这个模板是相当通用的,你可以根据具体问题调整它,比如改变搜索方向(例如,增加对角线方向),或者处理有特殊条件限制的格子。使用这样的模板可以帮助你快速构建解决方案,专注于问题的具体需求上。

广度优先搜索(BFS)是另一种常用的图和网格搜索算法,特别适用于找到最短路径或者层次遍历的问题。在 BFS 中,我们使用队列来实现层级遍历,这有助于按照从近到远的顺序访问节点。

下面,我将提供一个针对二维网格问题的 BFS 模板,这个模板适用于解决诸如“最短路径”、“岛屿数量”等问题。

BFS 模板

这里是一个 BFS 的基本模板,用于遍历或搜索二维网格:

  1. 初始化队列

    • 队列用于存储每一层要访问的节点。
  2. 定义 BFS 函数

    • 确保起始位置有效。
    • 将起始位置加入队列,并标记为已访问。
  3. 处理队列中的元素

    • 从队列中取出元素。
    • 对当前元素的每个可能的移动(上、下、左、右),检查新位置是否有效(未越界、未访问过、满足特定条件)。
    • 将有效的新位置加入队列并标记为已访问。
  4. 主函数体

    • 遍历每个单元格,对未访问的和满足条件的单元格启动 BFS。
    • 根据需要更新计数器或执行其他操作。

JavaScript 实现

function bfs(grid, startRow, startCol) {
    const queue = [[startRow, startCol]]; // 使用数组模拟队列,存储每个位置的坐标
    grid[startRow][startCol] = '0'; // 标记为已访问

    while (queue.length > 0) {
        const [row, col] = queue.shift(); // 从队列前端取出元素

        // 探索四个方向
        const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]];
        for (const [dr, dc] of directions) {
            const newRow = row + dr, newCol = col + dc;
            if (newRow >= 0 && newRow < grid.length && newCol >= 0 && newCol < grid[0].length && grid[newRow][newCol] === '1') {
                grid[newRow][newCol] = '0'; // 标记新位置为已访问
                queue.push([newRow, newCol]); // 将新位置加入队列
            }
        }
    }
}

function numIslands(grid) {
    if (!grid.length) return 0;
    let count = 0;

    for (let i = 0; i < grid.length; i++) {
        for (let j = 0; j < grid[0].length; j++) {
            if (grid[i][j] === '1') {
                bfs(grid, i, j);
                count++; // 完成一次 BFS 表示找到一个岛屿
            }
        }
    }

    return count;
}

这个模板可以根据具体的问题进行调整,例如增加对角线移动、增加条件判断等。使用 BFS 的关键是理解队列的使用和层级遍历的概念。

二分查找是一种高效的搜索方法,适用于已排序的数组。使用二分查找,可以在对数时间复杂度内找到一个元素的位置或解决相关问题。这里,我将提供二分查找的两种常见模板,并解释它们的适用场景。

模板 1:寻找特定值

这个模板用于查找特定值在已排序数组中的位置。如果找到该值,返回其索引;如果未找到,返回 -1

JavaScript 实现:
function binarySearch(nums, target) {
    let left = 0;
    let right = nums.length - 1;

    while (left <= right) {
        let mid = left + Math.floor((right - left) / 2);
        if (nums[mid] === target) {
            return mid;  // 找到目标,返回索引
        } else if (nums[mid] < target) {
            left = mid + 1;  // 目标在右侧
        } else {
            right = mid - 1;  // 目标在左侧
        }
    }

    return -1;  // 未找到目标
}

模板 2:寻找边界

这个模板用于查找满足条件的最左边界(最小索引)或最右边界(最大索引)。例如,在查找第一个不小于目标值的元素或最后一个不大于目标值的元素时使用。

查找左边界(第一个大于等于目标的元素)
function findLeftBoundary(nums, target) {
    let left = 0;
    let right = nums.length;  // 注意边界是 nums.length,不是 nums.length - 1

    while (left < right) {
        let mid = left + Math.floor((right - left) / 2);
        if (nums[mid] < target) {
            left = mid + 1;  // 目标在右侧
        } else {
            right = mid;  // 缩小右边界
        }
    }

    return left;  // left 是第一个不小于 target 的索引
}
查找右边界(最后一个小于等于目标的元素)
function findRightBoundary(nums, target) {
    let left = 0;
    let right = nums.length;

    while (left < right) {
        let mid = left + Math.floor((right - left) / 2);
        if (nums[mid] <= target) {
            left = mid + 1;  // 目标可能还在右侧
        } else {
            right = mid;  // 缩小右边界
        }
    }

    return left - 1;  // left - 1 是最后一个小于等于 target 的索引
}

使用场景

  • 模板 1:当你需要确认一个值是否存在于数组中,并获取其准确位置时使用。
  • 模板 2:当你需要找到满足某些条件的元素的边界位置时使用,比如“寻找最左侧的元素”或“寻找最右侧的元素”。

二分查找的关键是保持数组有序,并且正确处理边界和中点。

动态规划(DP)是解决优化问题和计数问题的强大工具,特别是在涉及多阶段决策的最优解问题中。动态规划通常用于解决具有重叠子问题和最优子结构的问题。虽然不存在单一的“模板”适用于所有动态规划问题,但有几个常用的方法和步骤可以帮助你构建和实现动态规划解决方案。

动态规划的基本步骤

  1. 定义状态

    • 识别问题的状态,并定义一个状态数组(或表),例如 dp[i] 可能代表“到达第 i 步的最优解”。
  2. 确定转移方程

    • 确定如何从一个或多个较小的状态转移到当前状态。这个转移方程是 DP 解决方案的核心,它定义了如何利用之前的状态来求解当前状态。
  3. 初始化条件

    • 确定基础案例(通常是数组的开始部分),这些是直接可知的,无需进一步计算。
  4. 填表(或迭代)

    • 根据转移方程和初始化条件,按顺序填充状态数组。这可能是从左到右、从顶部到底部,或者根据问题的特性,也可能需要其他顺序。
  5. 解决问题

    • 根据需要解决的问题,可能需要返回状态数组的最后一个元素,或者状态数组中的最小/最大值。

常见的动态规划模式

1. 线性动态规划(一维 DP)

例如,求解斐波那契数列、最大子数组和等问题。

function fib(n) {
    if (n <= 1) return n;
    let dp = [0, 1];
    for (let i = 2; i <= n; i++) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}
2. 二维动态规划

例如,求解编辑距离、二维路径问题等。

function minPathSum(grid) {
    let m = grid.length, n = grid[0].length;
    let dp = Array.from({length: m}, () => Array(n).fill(0));
    dp[0][0] = grid[0][0];

    // 初始化边界
    for (let i = 1; i < m; i++) dp[i][0] = dp[i - 1][0] + grid[i][0];
    for (let j = 1; j < n; j++) dp[0][j] = dp[0][j - 1] + grid[0][j];

    // 填充剩余的 dp 表
    for (let i = 1; i < m; i++) {
        for (let j = 1; j < n; j++) {
            dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
        }
    }

    return dp[m - 1][n - 1];
}
3. 分治法与记忆化(优化的递归)

例如,计算第 n 个斐波那契数,但通过记忆化来避免重复计算。

function fib(n, memo = {}) {
    if (n <= 1) return n;
    if (memo[n]) return memo[n];
    memo[n] = fib(n - 1, memo) + fib(n - 2, memo);
    return memo[n];
}

结论

虽然没有一种通用的动态规划模板适用于所有问题,但通过定义状态、转移方程、初始化条件和迭代过程,你可以构建出针对具体问题的动态规划解决方案。动态规划问题的关键在于如何分解问题为可管理的子问题,并找到合适的方法来组合这些子问题的解。

记忆化搜索是动态规划的一种实现方式,它结合了递归和记忆化(memoization)来避免重复计算相同的子问题。这种方法特别适用于那些有明显递归解决方案但由于重叠子问题导致效率低下的问题。通过使用记忆化,我们可以存储已解决的子问题的结果,从而大幅提高效率。

记忆化搜索的基本步骤

  1. 定义递归函数:这个函数应该能够解决问题的任何一个子问题。
  2. 添加记忆化机制:通常使用一个数据结构(如数组或哈希表)来存储已经计算过的结果。
  3. 递归调用时先检查记忆:在递归调用之前,先检查是否已经解决了这个子问题,如果是,直接返回存储的结果。
  4. 处理基本情况:确保递归有终止条件,通常对应于最简单的子问题。

记忆化搜索的模板

这里是一个用于解决递归问题的记忆化搜索的模板,这个例子使用 JavaScript:

function solve(problem) {
    // memo 用于存储已解决子问题的结果
    let memo = {};

    function dp(state) {
        // 如果在 memo 中找到了当前状态的解,直接返回它
        if (memo.hasOwnProperty(state)) {
            return memo[state];
        }

        // 处理基本情况,返回明确的结果
        if (isBaseCase(state)) {
            return baseCaseResult;
        }

        // 定义解决当前状态的方法,可能依赖于多个子状态的结果
        let result = initialValue; // 初始化结果
        for (let nextState of possibleNextStates(state)) {
            result = combine(result, dp(nextState));  // 结合当前结果和从下一个状态获得的结果
        }

        // 存储当前状态的结果以供将来使用
        memo[state] = result;
        return result;
    }

    // 开始递归求解
    return dp(initialState);
}

// 用于确定是否到达基本情况
function isBaseCase(state) {
    // 实现细节依赖具体问题
}

// 结合两个状态的结果的函数
function combine(result1, result2) {
    // 实现细节依赖具体问题
}

应用实例:斐波那契数列

记忆化搜索常见的应用之一是计算斐波那契数列,下面是一个具体的示例:

function fibonacci(n, memo = {}) {
    if (n <= 1) return n;
    if (!memo[n]) {
        memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
    }
    return memo[n];
}

在这个例子中,memo 哈希表用来存储每个数字对应的斐波那契数,避免了重复计算。

记忆化搜索是一个非常强大的技术,可以应用于各种递归问题中,尤其是那些解决方案中包含大量重叠子问题的情况。

并查集(Union-Find)是一种数据结构,专门用于处理一些不交集(Disjoint Sets)的合并及查询问题,非常适用于组网络连接、找出图中是否存在环、集群的快速查找等问题。并查集主要支持两种操作:找到某个元素的根节点(Find)和合并两个元素所在的集合(Union)。

并查集的基本结构

并查集通常通过一个数组来实现,数组中的每个位置 i 表示第 i 个元素,数组的值代表该元素的父节点。如果元素 i 是自己的父节点,那么 i 就是一个集合的根节点。

基本操作

  1. Find:找到元素 x 的根节点,同时进行路径压缩,使得树的深度尽可能小,加快后续操作的速度。
  2. Union:合并两个元素所在的集合,通常通过先找到它们的根节点,然后将一个根节点连接到另一个根节点。

并查集的模板

这里提供一个基本的并查集实现模板,使用 JavaScript 编写:

class UnionFind {
    constructor(size) {
        this.root = Array.from({ length: size }, (_, index) => index);
        this.rank = Array.from({ length: size }, () => 1);
    }

    find(x) {
        if (x === this.root[x]) {
            return x;
        }
        // 路径压缩
        this.root[x] = this.find(this.root[x]);
        return this.root[x];
    }

    union(x, y) {
        let rootX = this.find(x);
        let rootY = this.find(y);

        if (rootX !== rootY) {
            // 按秩合并
            if (this.rank[rootX] > this.rank[rootY]) {
                this.root[rootY] = rootX;
            } else if (this.rank[rootX] < this.rank[rootY]) {
                this.root[rootX] = rootY;
            } else {
                this.root[rootY] = rootX;
                this.rank[rootX] += 1;
            }
        }
    }

    connected(x, y) {
        return this.find(x) === this.find(y);
    }
}

使用并查集的步骤

  1. 初始化:构建一个并查集对象,大小为节点总数。
  2. 执行 Find 操作:为了查找任意节点的根节点。
  3. 执行 Union 操作:将两个节点合并到同一个集合中。
  4. 检查连接:检查两个节点是否位于同一个集合中。

并查集是解决动态连通性问题的非常有效的工具。上述模板提供了路径压缩和按秩合并两种优化方法,这两种方法都是用来提高并查集操作的效率。

双指针技术是一种常用于数组或链表的算法策略,用来简化复杂度或提高效率,特别是在需要比较、搜索或修改一系列数据时。根据问题的性质,双指针可以分为几种不同的类型:

1. 快慢指针

用于解决如环形链表检测、找到链表的中点等问题。快指针移动速度是慢指针的两倍。

2. 左右指针

常用于有序数组问题,如二分查找、两数之和等。两个指针分别从数组的开头和结尾向中间移动。

3. 滑动窗口

这是一种特殊类型的双指针应用,用于找到满足某些条件的最小子数组或最大子数组等问题。

双指针的通用模板

快慢指针模板

例如,判断链表是否有环:

function hasCycle(head) {
    if (!head) return false;
    let slow = head;
    let fast = head;

    while (fast && fast.next) {
        slow = slow.next;          // 慢指针每次移动一步
        fast = fast.next.next;    // 快指针每次移动两步

        if (slow === fast) {      // 如果相遇,则表示有环
            return true;
        }
    }

    return false;                // 如果快指针遇到 null,则没有环
}
左右指针模板

例如,求一个有序数组中两个数字的和等于一个给定值:

function twoSum(numbers, target) {
    let left = 0, right = numbers.length - 1;

    while (left < right) {
        const sum = numbers[left] + numbers[right];
        if (sum === target) {
            return [left + 1, right + 1];  // 返回结果
        } else if (sum < target) {
            left++;  // 移动左指针
        } else {
            right--; // 移动右指针
        }
    }

    return [-1, -1];  // 如果没有找到
}
滑动窗口模板

例如,找到数组中的最小子数组,其和大于等于给定值:

function minSubArrayLen(s, nums) {
    let left = 0;
    let sum = 0;
    let minLength = Infinity;

    for (let right = 0; right < nums.length; right++) {
        sum += nums[right];

        while (sum >= s) {
            minLength = Math.min(minLength, right - left + 1);
            sum -= nums[left];
            left++;
        }
    }

    return minLength === Infinity ? 0 : minLength;
}

这些模板涵盖了双指针技术的主要应用场景,可以根据具体问题进行适当调整。双指针策略非常有用于解决相关的算法问题,尤其是在处理有序数据或需要优化时间复杂度时。

如果你有一个数组,其中包含对象,而你想对这些对象中的特定数字属性求和,可以使用 reduce() 方法来实现这一点。这种方式可以保持代码简洁,同时易于维护。以下是一个例子,假设每个对象都有一个名为 number 的属性:

示例数组

const items = [
    { name: "item1", number: 10 },
    { name: "item2", number: 20 },
    { name: "item3", number: 30 }
];

使用 reduce() 方法求和

const sum = items.reduce((acc, item) => acc + item.number, 0);

在这个例子中,reduce() 方法初始化累加器 acc0,然后遍历数组 items,将每个元素的 number 属性值累加到 acc 中。

解析

  • items.reduce():调用数组的 reduce() 方法。
  • (acc, item) => acc + item.number:箭头函数作为 reduce() 的回调函数,其中 acc 是累加器,item 是数组中的当前元素。函数体内将当前元素的 number 属性值加到累加器上。
  • 0reduce() 方法的第二个参数,它是累加器的初始值。

这种方法不仅代码简洁,而且由于 reduce() 是一个内置函数,它的执行效率对于绝大多数应用来说已经足够高效。使用这种方法,你可以轻松扩展或修改,例如,如果需要对不同的属性求和,只需修改属性名即可。

要找出两个数组中相同的部分,即它们的交集,有几种不同的方法可以实现。这里将介绍几种常见的方法,包括使用 JavaScript 的内置方法以及一些手动实现的方法。每种方法都有其特定的使用场景和性能考虑。

方法 1: 使用 Set 和 filter

这是一种简单且常用的方法,适用于现代 JavaScript 环境。利用 Set 来检测一个数组中的元素是否存在于另一个数组中。

function intersection(arr1, arr2) {
    const set2 = new Set(arr2);
    return arr1.filter(item => set2.has(item));
}

这个方法首先将 arr2 转换成 Set,这样可以通过 has 方法以 O(1) 的时间复杂度来检查元素是否存在。然后使用 filter 方法过滤 arr1,只保留那些也存在于 arr2 的元素。

方法 2: 使用 Set 和 forEach

如果你喜欢使用更命令式的代码风格,可以使用 forEach 循环代替 filter

function intersection(arr1, arr2) {
    const set2 = new Set(arr2);
    const result = [];
    arr1.forEach(item => {
        if (set2.has(item)) {
            result.push(item);
        }
    });
    return result;
}

这种方法的工作原理与第一种相同,只是替换了迭代方式,直接将符合条件的元素推入结果数组。

方法 3: 使用双重循环

对于不支持 Set 或更旧的 JavaScript 环境,你可能需要使用传统的双重循环来找出交集。

function intersection(arr1, arr2) {
    const result = [];
    for (let i = 0; i < arr1.length; i++) {
        for (let j = 0; j < arr2.length; j++) {
            if (arr1[i] === arr2[j] && !result.includes(arr1[i])) {
                result.push(arr1[i]);
                break;
            }
        }
    }
    return result;
}

这种方法虽然简单直观,但效率较低,特别是当两个数组都很大时,因为它的时间复杂度接近 O(n*m),其中 nm 分别是两个数组的长度。

方法 4: 使用 ES6 Set 和 spread 操作符

如果你想用更现代的 JavaScript 写法,可以利用 Set 和扩展操作符(spread operator)来实现简洁的一行代码。

const intersection = (arr1, arr2) => [...new Set(arr1)].filter(x => new Set(arr2).has(x));

这种方法虽然在代码上非常简洁优雅,但创建了两个 Set,可能在性能上不如只创建一个 Set 的方法。

结论

根据不同的应用场景和性能需求选择合适的方法。如果两个数组都较大,使用 Setfilter 方法通常会提供最佳的性能。对于代码的简洁性和现代性,使用 ES6 的特性可以使代码更加优雅。如果环境限制,可能需要回退到使用双重循环的方法。

当处理两个包含对象的数组时,寻找它们的交集稍微复杂一些,因为对象之间的比较是基于引用而非值。即使两个对象包含完全相同的数据,它们也不会被认为是相等的,除非它们引用的是同一个对象实例。因此,我们需要定义比较逻辑,通常是基于对象的某个特定属性或多个属性。

以下是几种处理包含对象的数组并找出它们交集的方法,这些方法都基于对象的某个属性进行比较:

方法 1: 使用 Set 和 filter(基于属性比较)

如果对象数组可以基于某个属性(如 id)来唯一标识每个对象,你可以使用这个属性来检查元素是否存在于另一个数组中。

function intersectionByProperty(arr1, arr2, prop) {
    const set2 = new Set(arr2.map(item => item[prop]));
    return arr1.filter(item => set2.has(item[prop]));
}

这个函数首先创建一个包含 arr2 中所有对象的指定属性值的 Set。然后,它过滤 arr1,只保留那些其属性值存在于这个 Set 中的对象。

示例

const array1 = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }];
const array2 = [{ id: 2, name: "Bob" }, { id: 3, name: "Charlie" }];

const result = intersectionByProperty(array1, array2, 'id');
console.log(result);  // [{ id: 2, name: "Bob" }]

方法 2: 使用 JSON 字符串比较(全属性比较)

如果你想比较的是整个对象(所有属性),可以将对象转换为 JSON 字符串来比较。

function intersectionByFullObject(arr1, arr2) {
    const set2 = new Set(arr2.map(item => JSON.stringify(item)));
    return arr1.filter(item => set2.has(JSON.stringify(item)));
}

这种方法首先将 arr2 中的每个对象转换为 JSON 字符串并存储在一个 Set 中,然后过滤 arr1,只包括那些在 Set 中有相同 JSON 字符串表示的对象。

性能注意事项

  • 使用 JSON 字符串进行比较通常性能较低,特别是当对象较大或数组包含大量对象时。
  • 对于只有少量属性或已知的属性集,最好还是基于特定属性进行比较。

这些方法提供了灵活的方式来根据具体需求选择适当的对象比较策略。在选择方法时,要考虑到实际应用中的性能需求和对象结构的复杂性。如果有更具体的需求或问题,可以随时询问以获得更详细的解答。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/763380.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【netty系列-04】反应堆模式的种类和具体实现

Netty系列整体栏目 内容链接地址【一】深入理解网络通信基本原理和tcp/ip协议https://zhenghuisheng.blog.csdn.net/article/details/136359640【二】深入理解Socket本质和BIOhttps://zhenghuisheng.blog.csdn.net/article/details/136549478【三】深入理解NIO的基本原理和底层…

沙箱在“一机两用”新规下的价值体现

在数字化时代&#xff0c;随着企业信息化建设的深入&#xff0c;数据安全问题愈发凸显其重要性。一机两用新规的出台&#xff0c;旨在通过技术创新和管理手段&#xff0c;实现终端设备的安全可控&#xff0c;确保敏感数据的安全存储与传输。SDC沙箱技术作为一种创新的安全防护手…

NLP篇1

场景&#xff1a;假设给你一篇文章。 目标&#xff1a;说白了&#xff0c;就是数学的分类。但是如何实现分类呢。下面将逐步一 一 分析与拆解。先把目标定好了和整体框架定好了。而不是只见树木而不见森林。 情感分类&#xff08;好评、差评&#xff0c;中性&#xff09; 整体…

基于“香港世界”的SLAM技术介绍

在视觉感知技术中&#xff0c;理解和描述复杂的三维室外场景至关重要&#xff0c;尤其是自动驾驶技术的发展要求对陌生环境具有更强的适应能力和鲁棒性。传统上&#xff0c;使用“曼哈顿世界”和“亚特兰大世界”模型来描述具有垂直和水平结构的城市场景。 当遇到像香港这样地形…

burpsuite 设置监听窗口 火狐利用插件快速切换代理状态

一、修改burpsuite监听端口 1、首先打开burpsuite&#xff0c;点击Proxy下的Options选项&#xff1a; 2、可以看到默认的监听端口为8080&#xff0c;首先选中我们想要修改的监听&#xff0c;点击Edit进行编辑 3、将端口改为9876&#xff0c;并保存 4、可以看到监听端口修改成功…

云卓SKYDROID-H30——科技改变未来

云卓H30采用高通处理器、搭载安卓嵌入式系统&#xff0c;拥有三个工作频率&#xff0c;让图像更清晰、延迟更低、距离远、抗干扰性强&#xff0c;支持多种接口&#xff0c;更有10.1寸高清工业级阳光可视屏&#xff0c;防尘耐磨&#xff0c;结构强度高&#xff0c;适用于各种严苛…

前端利用vue如何实现导入和导出功能.md

1. 前端利用vue如何实现导入和到处功能 1.1. 导入功能&#xff08;以导入Excel文件为例&#xff09; 1.1.1. 实现步骤: 1.1.1.1. 安装依赖: 首先&#xff0c;你需要安装处理Excel文件的库&#xff0c;如xlsx。1.1.1.2. 创建上传组件: 使用Element UI的<el-upload>组件或其…

windows USB 驱动开发-URB结构

通用串行总线 (USB) 客户端驱动程序无法直接与其设备通信。 相反&#xff0c;客户端驱动程序会创建请求并将其提交到 USB 驱动程序堆栈进行处理。 在每个请求中&#xff0c;客户端驱动程序提供一个可变长度的数据结构&#xff0c;称为 USB 请求块 (URB) &#xff0c;URB 结构描…

zdppy_api+vue3+antd开发前后端分离的tab卡片

后端代码 import api import uploadsave_dir "uploads"async def rand_content(request):key api.req.get_query(request, "key")return api.resp.success(f"{key} " * 100)app api.Api(routes[api.resp.get("/", rand_content),u…

2024科技文化节程序设计竞赛

补题链接 https://www.luogu.com.cn/contest/178895#problems A. 签到题 忽略掉大小为1的环&#xff0c;答案是剩下环的大小和减环的数量 #include<bits/stdc.h> #include<iostream> #include<cstdio> #include<vector> #include<map> #incl…

Victor CMS v1.0 SQL 注入漏洞(CVE-2022-28060)

前言 CVE-2022-28060 是 Victor CMS v1.0 中的一个SQL注入漏洞。该漏洞存在于 /includes/login.php 文件中的 user_name 参数。攻击者可以通过发送特制的 SQL 语句&#xff0c;利用这个漏洞执行未授权的数据库操作&#xff0c;从而访问或修改数据库中的敏感信息。 漏洞详细信…

mac安装达梦数据库

参考&#xff1a;mac安装达梦数据库​​​​​​ 实践如下&#xff1a; 1、下载达梦Docker镜像文件 同参考链接 2、导入镜像 镜像可以随便放在某个目录&#xff0c;相当于安装包&#xff0c;导入后就没有作用了。 查找达梦镜像名称&#xff1a;dm8_20240613_rev229704_x86…

第11章 规划过程组(11.6规划进度管理)

第11章 规划过程组&#xff08;二&#xff09;11.6规划进度管理&#xff0c;在第三版教材第385页&#xff1b;#软考中级##中级系统集成项目管理师# 文字图片音频方式 第一个知识点&#xff1a;主要输出 1、进度管理计划 准确度 定义活动持续时间估算的可接受区间&#xff0…

Pycharm常用快捷键整理

1&#xff0c;格式化代码 【ctrlAltL】 写代码的时候会发现有很多黄色的波浪号&#xff0c;这个时候可以点击任意黄色波浪号的代码&#xff0c;然后按下【Ctrl Alt L】进行代码格式化 2&#xff0c;快速往返 ctrll Alt ⬅ &#xff0c;表示查看上一步调用函数位置&#xff0…

Oracle 视图、存储过程、函数、序列、索引、同义词、触发器

优质博文&#xff1a;IT-BLOG-CN 一、视图 从表中抽出的逻辑上相关的数据集合&#xff0c;视图是一种虚表&#xff0c;视图是建立在已有表的基础之上&#xff0c;视图赖以建立的这些表称为基表。向视图提供数据的是 SELECT语句&#xff0c;可以将视图理解为存储起来的SELECT语…

KV260视觉AI套件--PYNQ-DPU-Resnet50

目录 1. 简介 2. 代码解析 3. 全部代码展示 4. 总结 1. 简介 Resnet50 一种深度卷积神经网络&#xff08;CNN&#xff09;&#xff0c;它由50层构成。这种网络特别设计用于图像识别任务&#xff0c;并且在2015年的ImageNet大规模视觉识别挑战赛&#xff08;ILSVRC&#x…

notepad++安装并打开json文件

1、notepad安装 1、首先下载Notepad.exe 2、选择简体中文安装 点击下一步 点击“我接受” 选择安装目录&#xff0c;进行下一步安装 默认下一步 选择安装 等待安装完成 点击完成 2、保存json文件 复制返回结果 先把返回结果复制出来。保存到text里面 把文件另存为json格式 3、…

Mac搭建anaconda环境并安装深度学习库

1. 下载anaconda安装包 根据自己的操作系统不同&#xff0c;选择不同的安装包Anaconda3-2024.06-1-MacOSX-x86_64.pkg&#xff0c;我用的还是旧的intel所以下载这个&#xff0c;https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/&#xff0c;如果mac用的是M1&#xff0…

通过百度文心智能体创建STM32编程助手-实操

一、前言 文心智能体平台AgentBuilder 是百度推出的基于文心大模型的智能体&#xff08;Agent&#xff09;平台&#xff0c;支持广大开发者根据自身行业领域、应用场景&#xff0c;选取不同类型的开发方式&#xff0c;打造大模型时代的产品能力。开发者可以通过 prompt 编排的…

拍摄的vlog视频画质模糊怎么办?视频画质高清修复

在短视频逐渐成为主流的今天&#xff0c;许多朋友都会通过vlog的形式记录下自己的生活。但我们会发现&#xff0c;自己拍摄的视频与专业博主拍摄的视频&#xff0c;在画质上就会有所差别&#xff0c;拍摄的vlog视频画质模糊不清晰怎么办&#xff1f; 拍摄的vlog视频画质模糊怎么…