第426场周赛:仅含置位位的最小整数、识别数组中的最大异常值、连接两棵树后最大目标节点数目 Ⅰ、连接两棵树后最大目标节点数目 Ⅱ

Q1、仅含置位位的最小整数

1、题目描述

给你一个正整数 n。

返回 大于等于 n 且二进制表示仅包含 置位 位的 最小 整数 x 。

置位 位指的是二进制表示中值为 1 的位。

2、解题思路

我们需要找到一个整数 x,使得:

  • x ≥ n
  • x 的二进制表示中仅包含置位位,并且 x 是比 n 大于或等于的最小整数。

解法

通过不断构造形如 111...111 的数并判断是否大于等于 n:

  1. 初始化一个结果变量 ret,初始值为 1(二进制为 1)。
  2. 如果当前 ret 小于 n,则将其左移一位后,最低位补 1。这相当于在二进制末尾追加一个 1,使其逐渐变成 11111 等。
  3. 当 ret 大于等于 n 时,停止循环并返回 ret。

3、代码实现

class Solution {
public:
    int smallestNumber(int n) {
        int ret = 1; // 初始结果
        while (ret < n) {
            ret = (ret << 1) | 1; // 左移一位后补 1
        }
        return ret;
    }
};

4、复杂度分析

  • 时间复杂度O(1)。该算法通过一系列固定次数的位操作计算最小整数,无论 n 的大小如何,位运算的次数是固定的。
  • 空间复杂度O(1)。算法只使用常数空间。

Q2、识别数组中的最大异常值

1、题目描述

给你一个整数数组 nums。该数组包含 n 个元素,其中 恰好 有 n - 2 个元素是 特殊数字 。剩下的 两个 元素中,一个是这些 特殊数字 的 和 ,另一个是 异常值 。

异常值 的定义是:既不是原始特殊数字之一,也不是表示这些数字元素和的数字。

注意,特殊数字、和 以及 异常值 的下标必须 不同 ,但可以共享 相同 的值。

返回 nums 中可能的 最大异常值。

2、解题思路

要解这个问题,我们可以按照以下步骤进行:

  1. 首先理解数组的结构
    • 数组中有 n-2 个特殊数字,这些数字的和是 sum
    • 剩下的两个数字中一个是 sum,另一个是 abnormal
    • 我们需要确定这两个数字分别是什么,并且找出最大的异常值。
  2. 步骤
    • 计算数组中所有元素的总和 totalSum
    • 对于每个元素,假设它是 abnormal,并计算其他元素的和(即 totalSum - abnormal)。
    • 检查这个和是否可以分解成一个 sumn-3 个特殊数字的和。
    • 如果可以,则返回这个 abnormal 数字。
  3. 分析
    • 我们可以通过检查每个元素是否是可能的 abnormal 来找到解。
    • 通过每次尝试去找 abnormal 和其对应的 sum

解法

我们先来尝试通过遍历数组来实现这个思路。具体实现时,我们首先计算总和,然后假设某个元素是异常值,计算剩余部分的和来判断它是否是有效的特殊数字之和。

  1. 避免重复查找:可以通过将数组元素存储在哈希集合中,这样查找 half 是否存在可以在常数时间 O(1) 内完成。
  2. 改进的步骤
    • 计算整个数组的总和 totalSum
    • 对于每个元素,假设它是异常值 abnormal,计算 sum = totalSum - abnormal
    • 如果 sum 是偶数,可以继续判断其一半 half = sum / 2 是否是数组中的其他元素。为了更高效地查找,我们将 nums 中的元素存入哈希表 unordered_map

3、代码实现

class Solution {
public:
    int getLargestOutlier(vector<int>& nums) {
        int n = nums.size();
        int totalSum = 0;
        // 用来存储最大的异常值
        int maxAbnormal = INT_MIN;
        // 使用哈希集合存储数组中的元素, 快速查找
        unordered_map<int, vector<int>> hash;
        for (int i = 0; i < n; ++i) {
            hash[nums[i]].push_back(i);
            totalSum += nums[i];
        }

        // 遍历数组中的每一个元素,假设它是异常值
        for (int i = 0; i < n; ++i) {
            int abnormal = nums[i];
            int sum = totalSum - abnormal; // 假设剩余的和是 sum
            if (sum % 2) {
                continue;
            }
            int half = sum / 2;

            // 判断 sum 是否可以通过删除一个特殊值来得到
            // sum 应该是 nums 中的一个元素,并且这个元素的下标不是 i
            bool valid = false;
            if (hash.count(half)) {
                auto v = hash[half];
                for (const auto& index : v) {
                    if (index != i) {
                        valid = true;
                        break;
                    }
                }
            }

            // 如果找到了合法的 sum,更新最大异常值
            if (valid) {
                maxAbnormal = max(maxAbnormal, abnormal);
            }
        }

        return maxAbnormal == INT_MIN ? -1 : maxAbnormal; // 如果没有找到异常值,则返回 -1
    }
};

4、时间复杂度分析

  • 时间复杂度
    • 构建哈希集合 unordered_map 的时间复杂度是 O(n)
    • 遍历数组,针对每个元素计算 sumhalf,并通过哈希集合判断 half 是否存在,时间复杂度是 O(1)。因此,整个遍历过程的时间复杂度是 O(n)
    • 总体时间复杂度是 O(n)
  • 空间复杂度:我们使用了一个额外的哈希集合 unordered_map 来存储数组元素,因此空间复杂度是 O(n)

Q3、连接两棵树后最大目标节点数目 Ⅰ

1、题目描述

有两棵 无向 树,分别有 n 和 m 个树节点。两棵树中的节点编号分别为[0, n - 1] 和 [0, m - 1] 中的整数。

给你两个二维整数 edges1 和 edges2 ,长度分别为 n - 1 和 m - 1 ,其中 edges1[i] = [ai, bi] 表示第一棵树中节点 ai 和 bi 之间有一条边,edges2[i] = [ui, vi] 表示第二棵树中节点 ui 和 vi 之间有一条边。同时给你一个整数 k 。

如果节点 u 和节点 v 之间路径的边数小于等于 k ,那么我们称节点 u 是节点 v 的 目标节点 。注意 ,一个节点一定是它自己的 目标节点 。

请你返回一个长度为 n 的整数数组 answer ,answer[i] 表示将第一棵树中的一个节点与第二棵树中的一个节点连接一条边后,第一棵树中节点 i 的 目标节点 数目的 最大值 。

注意 ,每个查询相互独立。意味着进行下一次查询之前,你需要先把刚添加的边给删掉。

2、解题思路

  1. 树的表示与遍历
    • 我们需要计算每个节点到其他节点的路径长度。对于树来说,路径长度等于两个节点之间的跳跃边数。
    • 我们可以使用**深度优先搜索(DFS)或者广度优先搜索(BFS)**来计算从某一节点到其他节点的路径长度。
  2. 距离矩阵的构建
    • 为了快速计算两个节点之间的距离,可以利用 BFS 在每棵树上预处理节点之间的最短路径。具体来说,使用 BFS 可以得到从某个节点到所有其他节点的距离。
  3. 处理每个查询
    • 对于每个节点 i,我们需要找出在第二棵树上与 i 连接的节点,使得路径的边数小于等于 k,并且尽可能多。
    • 因为每个查询之后边会被删除,因此每个查询的结果是独立的。
  4. 最大目标节点的数目
    • 我们需要遍历树2中的每个节点,计算在第一棵树中的每个节点与该节点的连接,满足条件的目标节点的最大数目。

解决步骤

  1. 预处理树1和树2的每个节点到其他节点的最短距离,可以通过 BFS 来实现。
  2. 处理每个查询,对于每个查询,检查连接第一棵树的节点到第二棵树的每个节点的路径,计算最大目标节点数。

3、代码实现

class Solution {
public:
    vector<int> maxTargetNodes(vector<vector<int>>& edges1, vector<vector<int>>& edges2, int k) {
        int n = edges1.size() + 1; // 第一棵树的节点数
        int m = edges2.size() + 1; // 第二棵树的节点数

        // 构建树1和树2的邻接表
        vector<vector<int>> adj1(n), adj2(m);
        for (auto& edge : edges1) {
            adj1[edge[0]].push_back(edge[1]);
            adj1[edge[1]].push_back(edge[0]);
        }
        for (auto& edge : edges2) {
            adj2[edge[0]].push_back(edge[1]);
            adj2[edge[1]].push_back(edge[0]);
        }

        // 计算每个节点到其他节点的最短距离
        vector<vector<int>> dist1(n), dist2(m);
        for (int i = 0; i < n; i++) {
            dist1[i] = bfs(i, adj1, n);
        }
        for (int i = 0; i < m; i++) {
            dist2[i] = bfs(i, adj2, m);
        }

        // 对每个节点 i 计算最大目标节点数
        vector<int> result(n, 0);

        // 预计算树2每个节点的目标节点数
        vector<int> targetCount2(m, 0);
        for (int j = 0; j < m; ++j) {
            int count2 = 0;
            for (int x = 0; x < m; ++x) {
                if (dist2[j][x] < k) {
                    count2++;
                }
            }
            targetCount2[j] = count2;
        }

        // 对树1的每个节点,计算其最大目标节点数
        for (int i = 0; i < n; i++) {
            int targetCount1 = 0;
            int maxTargets = 0;
            // 对于树 1 的目标节点个数
            for (int j = 0; j < n; ++j) {
                if (dist1[i][j] <= k) {
                    ++targetCount1;
                }
            }

            // 对每个树2中的节点 j, 检查目标节点数
            for (int j = 0; j < m; j++) {
                // 计算树 1 的节点 i 到树 2 的节点 j 的路径是否符合要求
                int count = targetCount1 + targetCount2[j];
                maxTargets = max(maxTargets, count);
            }
            result[i] = maxTargets;
        }

        return result;
    }

    // BFS 计算从一个节点到其他节点的最短路径
    vector<int> bfs(int start, const vector<vector<int>>& adj, int n) {
        vector<int> dist(n, -1); // -1表示未访问
        queue<int> q;
        dist[start] = 0;
        q.push(start);

        while (!q.empty()) {
            int node = q.front();
            q.pop();

            for (int neighbor : adj[node]) {
                if (dist[neighbor] == -1) { // 如果未访问过
                    dist[neighbor] = dist[node] + 1;
                    q.push(neighbor);
                }
            }
        }

        return dist;
    }
};
  1. BFS计算最短距离bfs 函数用于计算从某个节点出发,所有其他节点的最短路径。
  2. 构建邻接表:首先我们将每棵树的边表示为邻接表 adj1adj2,分别对应第一棵和第二棵树。
  3. 计算每个节点的最短路径:通过 bfs 从每个节点出发,计算到其他所有节点的最短距离,并存储在 dist1dist2 中。
  4. 遍历计算最大目标节点数:对于每个节点 i,我们遍历第二棵树的所有节点,计算其目标节点的数量。

Q4、连接两棵树后最大目标节点数目 Ⅱ

1、题目描述

有两棵 无向 树,分别有 nm 个树节点。两棵树中的节点编号分别为[0, n - 1][0, m - 1] 中的整数。

给你两个二维整数 edges1edges2 ,长度分别为 n - 1m - 1 ,其中 edges1[i] = [ai, bi] 表示第一棵树中节点 aibi 之间有一条边,edges2[i] = [ui, vi] 表示第二棵树中节点 uivi 之间有一条边。

如果节点 u 和节点 v 之间路径的边数是偶数,那么我们称节点 u 是节点 v目标节点注意 ,一个节点一定是它自己的 目标节点

请你返回一个长度为 n 的整数数组 answeranswer[i] 表示将第一棵树中的一个节点与第二棵树中的一个节点连接一条边后,第一棵树中节点 i目标节点 数目的 最大值

注意 ,每个查询相互独立。意味着进行下一次查询之前,你需要先把刚添加的边给删掉。

2、解题思路

节点目标的定义

  • 目标节点的定义是:如果节点 u 和节点 v 之间的路径的边数是偶数,那么 uv 的目标节点。
  • 每个节点一定是它自己的目标节点。

树的层次分组

  • 由于目标节点数目与路径的边数是否为偶数相关,我们可以将树的节点按层次分组。即,我们可以利用 深度优先搜索(DFS)对每棵树进行层次划分。
  • 在每棵树中,通过 DFS 遍历节点,并将节点根据奇偶层分到两个组中。对于树1,按奇偶层分组后的节点数目可以用来计算目标节点数。

最大目标节点数

  • 对于第一棵树中的每个节点 i,我们要计算该节点通过与第二棵树中节点连接后,能得到的最大目标节点数。
  • 由于目标节点的定义是与路径的奇偶性相关,因此树2中的每层节点数可以影响树1中每个节点的目标节点数。

优化

  • 通过 DFS 预处理每棵树的节点层次信息,然后利用这些信息计算每个节点的目标节点数。这样可以避免每次连接时重新计算所有节点之间的路径关系,显著提高效率。

3、代码实现

class Solution {
private:
    // 构建邻接表
    void buildGraph(vector<vector<int>>& graph, const vector<vector<int>>& edges) {
        for (const auto& edge : edges) {
            int u = edge[0], v = edge[1];
            graph[u].push_back(v);
            graph[v].push_back(u);
        }
    }

    // 更新树 1 中每个节点的目标节点数
    void updateTargetNodes(vector<int>& result, const vector<vector<int>>& layers1) {
        for (const auto& layer : layers1) {
            int layerSize = layer.size();
            for (int node : layer) {
                result[node] += layerSize; // 增加该层节点数
            }
        }
    }

    // 深度优先搜索函数, 按奇偶层分组
    void dfs(int node, int parent, int layer, vector<vector<int>>& graph, vector<vector<int>>& layers) {
        // 将当前节点加入对应层的分组
        layers[layer].push_back(node);

        // 遍历相邻节点, 递归调用 DFS
        for (int neighbor : graph[node]) {
            // 跳过父节点
            if (neighbor == parent) {
                continue;
            }
            // 切换层次 (奇偶层)
            dfs(neighbor, node, 1 - layer, graph, layers);
        }
    }

public:
    vector<int> maxTargetNodes(vector<vector<int>>& edges1, vector<vector<int>>& edges2) {
        int n = edges1.size() + 1; // 第一个树的节点数
        int m = edges2.size() + 1; // 第二个树的节点数

        // 构建邻接表,表示两棵树
        vector<vector<int>> graph1(n), graph2(m);
        buildGraph(graph1, edges1);
        buildGraph(graph2, edges2);

        // 存储每个树按层分组的节点
        vector<vector<int>> layers1(2), layers2(2);

        // 进行 DFS 遍历,分层存储节点
        dfs(0, -1, 0, graph1, layers1);
        dfs(0, -1, 0, graph2, layers2);

        // 找到树2中节点数量最多的层
        int maxLayerSizeInTree2 = max(layers2[0].size(), layers2[1].size());

        // 初始化答案数组,每个节点的目标节点数默认为树2最大层的节点数
        vector<int> result(n, maxLayerSizeInTree2);

        // 对树1中的每个节点,增加与该层节点数相等的目标节点数
        updateTargetNodes(result, layers1);

        return result;
    }
};

代码讲解

  1. 构建图
    • buildGraph 函数通过给定的边列表(edges1edges2)构建图的邻接表。
  2. DFS 遍历
    • dfs 函数用于对树进行深度优先搜索,并按层将节点分到两个层(奇层和偶层)。我们通过层次分组来记录树中每个节点的奇偶层信息。
  3. 计算最大目标节点数
    • updateTargetNodes 函数通过遍历树1的奇偶层,更新每个节点的目标节点数。目标节点数的增加量就是该层的节点数。
  4. 最终答案
    • 对于树1中的每个节点,初始时其目标节点数设置为树2中最大的层数(即maxLayerSizeInTree2),然后再根据树1中该节点所处的层次进行更新。

4、时间复杂度

  • 构建图的时间复杂度为 O(n + m),因为我们需要处理每一条边。
  • DFS 遍历的时间复杂度为 O(n + m),每个节点和边都只访问一次。
  • 计算每个节点的目标节点数的时间复杂度为 O(n),其中我们遍历树1的节点和层。

因此,总时间复杂度为 O(n + m)

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

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

相关文章

Vue框架开发一个简单的购物车(Vue.js)

让我们利用所学知识来开发一个简单的购物车 &#xff08;记得暴露属性和方法&#xff01;&#xff01;&#xff01;&#xff09; 首先来看一下最基本的一个html框架 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"&…

注册表修改键盘位置

1.winr 输入 regedit 2.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout 3.右键Keyboard Layout->新建->二进制值->取名Scancode Map 4.右键Scancode Map&#xff0c;修改如下 //第一列 自动生成序号&#xff0c;不用管 第一行 输入8个00 第二…

【Verilog】实验二 数据选择器的设计与vivado集成开发环境

目录 一、实验目的 二、实验环境 三、实验任务 四、实验原理 五、实验步骤 top.v mux2_1.v 一、实验目的 1. 掌握数据选择器的工作原理和逻辑功能。 2. 熟悉vivado集成开发环境。 3. 熟悉vivado中进行开发设计的流程。 二、实验环境 1. 装有vivado的计算机。 2. Sw…

一、文本预处理

文本预处理 前言一、文本处理的基本方法1.1 分词1.1.1 举例&#xff1a;1.1.2 作用1.1.3 分词工具——jieba1.1.3.1 jieba特性1.1.3.2 jieba 的 API 代码演示 二、命名实体识别2.1 命名实体2.2 命名实体识别2.3 举例2.4 作用 三、词性标注3.1 词性3.2 词性标注3.3 jieba词性对照…

【HM-React】02. React基础-下

React表单控制 受控绑定 概念&#xff1a;使用React组件的状态&#xff08;useState&#xff09;控制表单的状态 function App(){const [value, setValue] useState()return (<input type"text" value{value} onChange{e > setValue(e.target.value)}/>) …

二分法篇——于上下边界的扭转压缩间,窥见正解辉映之光(2)

前言 上篇介绍了二分法的相关原理并结合具体题目进行讲解运用&#xff0c;本篇将加大难度&#xff0c;进一步强化对二分法的掌握。 一. 寻找峰值 1.1 题目链接&#xff1a;https://leetcode.cn/problems/find-peak-element/description/ 1.2 题目分析: 题目要求返回数组内…

【C语言】结构体(一)

一&#xff0c;是什么 结构体就是一些值的集合&#xff0c;这些值称为成员变量。 结构体的每个成员可以是不同类型的变量。说到集合&#xff0c;数组也是集合&#xff0c;但是不同的是数组只能是相同类型元素的集合。 二&#xff0c;结构体的声明 struct tag {   member1;…

Leetcode - 周赛425

目录 一&#xff0c;3364. 最小正和子数组 二&#xff0c; 3365. 重排子字符串以形成目标字符串 三&#xff0c;3366. 最小数组和 四&#xff0c;3367. 移除边之后的权重最大和 一&#xff0c;3364. 最小正和子数组 本题可以直接暴力枚举&#xff0c;代码如下&#xff1a; …

uniapp Electron打包生成桌面应用exe文件

1.uniapp Electron打包生成桌面应用exe文件 随着跨平台开发的需求日益增长,UniApp 成为了开发者们的首选之一。通过 UniApp,你可以使用 Vue.js 的语法结构和组件系统来构建原生应用、Web 应用甚至是桌面应用。本文将详细介绍如何使用 UniApp 将你的项目打包成 Windows 桌面端…

Linux -初识 与基础指令1

博客主页&#xff1a;【夜泉_ly】 本文专栏&#xff1a;【Linux】 欢迎点赞&#x1f44d;收藏⭐关注❤️ 文章目录 &#x1f4da; 前言&#x1f5a5;️ 初识&#x1f510; 登录 root用户&#x1f465; 两种用户➕ 添加用户&#x1f9d1;‍&#x1f4bb; 登录 普通用户⚙️ 常见…

【笔记总结】华为云:应用上云后的安全规划及设计

一、背景和问题 数字化时代&#xff0c;随着信息技术的飞速发展&#xff0c;企业和各类组织纷纷将自身的应用程序迁移至云端。云计算凭借其诸多优势&#xff0c;如成本效益、可扩展性、灵活性以及便捷的资源共享等&#xff0c;已然成为了现代业务运营的重要支撑。 今年&#xf…

【机器学习(二)】分类和回归任务-决策树(Decision Tree,DT)算法-Sentosa_DSML社区版 (1)11111

文章目录 一、算法概念11111二、算法原理&#xff08;一&#xff09;树的构造&#xff08;二&#xff09;划分选择1、信息增益2、基尼指数3、卡方检验 &#xff08;三&#xff09;停止标准&#xff08;四&#xff09;剪枝处理1、预剪枝2、后剪枝 三、决策树的优缺点四、决策树分…

【SpringBoot问题】IDEA中用Service窗口展示所有服务及端口的办法

1、调出Service窗口 打开View→Tool Windows→Service&#xff0c;即可显示。 2、正常情况应该已经出现SpringBoot&#xff0c;如下图请继续第三步 3、配置Service窗口的项目启动类型。微服务一般是Springboot类型。所以这里需要选择一下。 点击最后一个号&#xff0c;点击Ru…

【Linux探索学习】第十八弹——进程等待:深入解析操作系统中的进程等待机制

Linux学习笔记&#xff1a;https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言&#xff1a; 在Linux操作系统中&#xff0c;进程是资源的管理和执行单元&#xff0c;每个进程都有其自己的生命周期。在进程的执行过程中&#xff0c;进程…

如何实现一套键盘鼠标控制两台计算机(罗技Options+ Flow功能快速实现演示)

需求背景 之前我写过一篇文章如何实现一套键盘鼠标控制两台计算机&#xff08;Mouse Without Borders快速上手教程&#xff09;_一套键鼠控制两台电脑-CSDN博客 当我们在局域网内有两台计算机&#xff0c;想使用一套键鼠操控时&#xff0c;可以安装Mouse Without Borders软件…

MATLAB中物理系统建模仿真介绍

Simscape 是 MATLAB 提供的一个强大的多域物理系统建模和仿真工具&#xff0c;它允许用户在 Simulink 环境中创建和模拟复杂的物理系统。Simscape 模型可以帮助用户细化需求、设计控制系统、测试嵌入式控制器&#xff0c;并使用数字孪生支持在役运行 1. Simscape概述 Simscap…

剖析kubernetes service的IP能否在宿主机中ping通

文章目录 前言一、serviceIP是怎么产生的二、宿主机中ping serviceIP地址1.ping示例2.为什么ping不通剖析2.1.封装及解封装过程2.2.ICMP报文以太网数据帧格式2.3.原因 三、ping不通svcIP是否跟iptables规则有关&#xff1f;四、为什么ipvs的的clusterIP类型的service能够ping通…

40分钟学 Go 语言高并发:内存管理与内存泄漏分析

内存管理与内存泄漏分析 一、内存管理基础知识 知识点重要性说明优化目标内存分配⭐⭐⭐⭐⭐栈内存和堆内存的分配机制降低内存分配开销逃逸分析⭐⭐⭐⭐⭐变量逃逸到堆的条件与影响减少堆内存分配泄漏排查⭐⭐⭐⭐内存泄漏的检测和定位防止内存泄漏内存优化⭐⭐⭐⭐内存使用…

云数仓 ByteHouse 的湖仓一体设计与实践

本次交流将聚焦 ByteHouse 湖仓一体主题&#xff0c;主要介绍&#xff1a; ByteHouse 简介 当代分析平台的挑战与 ByteHouse 一体化理念 ByteHouse 湖仓一体的核心能力 最佳实践 ByteHouse 简介 ByteHouse 是什么 ByteHouse 作为新一代云原生架构的数据仓库&#xff0c;属…

第一部分:基础知识 2. SQL基础 --[MySQL轻松入门教程]

第一部分&#xff1a;基础知识 2. SQL基础 --[MySQL轻松入门教程] SQL&#xff08;Structured Query Language&#xff09;是一种用于管理和处理关系型数据库的标准语言。它被广泛应用于各种数据库系统&#xff0c;如MySQL, PostgreSQL, Oracle, SQL Server等。下面是一些SQL的…