C++ vectorOJ练习题

news2024/11/13 10:12:10

目录

136. 只出现一次的数字

118. 杨辉三角

26. 删除有序数组中的重复项

137. 只出现一次的数字ll

260. 只出现一次的数字 III

17. 电话号码的字母组合

JZ39 数组中出现次数超过一半的数字


136. 只出现一次的数字

采用异或运算的思路

  • 异或运算的特性是,相同的数异或结果为0,而任何数与0异或结果仍为原数。
  • 通过在循环中不断进行异或运算,最终只出现一次的元素将会被保留在变量v中,而其他出现多次的元素则会被抵消掉。
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int v=0;
        for(auto a:nums)
        {
            v^=a;
        }
        return v;
    }
};

118. 杨辉三角

思路:找出杨辉三角的规律,发现每一行头尾都是1,中间第[j]个数等于上一行[j-1]+[j]。

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> v;
        v.resize(numRows, vector<int>());
        for (size_t i = 0; i < numRows; i++) {
            v[i].resize(i + 1, 0);
            v[i][0] = v[i][v[i].size() - 1] = 1;
        }
        for (size_t i = 0; i < v.size(); i++) {
            for (size_t j = 0; j < v[i].size(); j++) {
                if (v[i][j] == 0) {
                    v[i][j] = v[i - 1][j] + v[i - 1][j - 1];
                }
            }
        }
        return v;
    }
};
  • 首先,函数定义了一个二维整型数组v,用于存储生成的杨辉三角形。通过调用resize函数,将数组的行数设置为numRows,并将每一行的列数初始化为0。
  • 接下来,使用两个嵌套的for循环来遍历数组v中的每个元素。外层循环控制行数,内层循环控制列数。
  • 在内层循环中,首先通过v[i].resize(i+1,0)将当前行的列数设置为i+1,并将所有元素初始化为0。然后,将当前行的第一个元素和最后一个元素设置为1,即v[i][0]=v[i][v[i].size()-1]=1
  • 接下来,通过判断当前元素是否为0,来确定是否需要计算该元素的值。如果当前元素为0,则表示该元素是由上方两个元素相加得到的。通过v[i-1][j-1]+v[i-1][j]计算出当前元素的值,并将结果赋值给v[i][j]
  • 通过这样的循环嵌套,依次计算出杨辉三角形中每个位置的值。
  • 最后,函数返回生成的杨辉三角形数组v

26. 删除有序数组中的重复项

方法一 

使用双指针方法,一个指针用于遍历数组并查找唯一的元素,另一个指针用于跟踪下一个不重复元素应该插入的位置。时间复杂度为O(N).

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if (nums.empty())
            return 0;
        int a = 0, b = 1;
        while (b < nums.size()) {
            if (nums[a] != nums[b]){
                nums[++a] = nums[b];
            }
            ++b;
        }
        return a + 1;
    }
};
  • 如果nums为空,则立即返回0。这是因为空数组没有元素可以移除。函数使用两个指针ab(或者可以认为是索引)来遍历数组。a指向要插入下一个唯一元素的位置,而b遍历数组寻找不重复的元素。
  • b小于nums.size()时,继续遍历数组。
  • 检查nums[a]nums[b]。如果它们不相等,这意味着nums[b]是一个新的唯一元素,它应该被移到a指向的下一个位置。
  • 如果nums[a]nums[b]相等,这意味着nums[b]是重复元素,因此不应移动a
  • 当找到新的唯一元素时(即nums[a]nums[b]不相等),将nums[b]的值复制到nums[a+1]的位置。这样做是为了在数组的前部保留所有唯一的元素。
  • 指针a递增以指向下一个可能的唯一元素的位置。
  • 无论nums[a]nums[b]是否相等,b都会递增,以便继续检查数组的下一个元素。
  • 函数返回a+1,这是因为a是最后一个唯一元素的索引,而数组长度是最后一个元素的索引加1。

方法二

 思路: erase删除重复数据,不过会导致数据挪动,时间复杂度为O(N)

  1. 由于数据是排序好的,通过查询每一个数据的重复区间
  2. 将重复区间进行删除,只保留一个数据即可
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if (nums.size() == 1)
            return 1;
        vector<int>::iterator it = nums.begin();
        vector<int>::iterator it1 = it + 1;

        while (it != nums.end()) {
            while (it1 != nums.end() && *it1 == *it){
                it1++;
            }
            it = nums.erase(++it, it1);
            it1 = it;
            it1++;
        }
        return nums.size();
    }
};

137. 只出现一次的数字ll

方法一:我们可以使用哈希映射统计数组中每个元素的出现次数。对于哈希映射中的每个键值对,键表示一个元素,值表示其出现的次数。在统计完成后,我们遍历哈希映射即可找出只出现一次的元素。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int, int> count;
        for (auto a : nums) {
            ++count[a];
        }
        for (auto& pair : count) {
            if (pair.second == 1) {
                return pair.first;
            }
        }
        return -1;
    }
};

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        unordered_map<int, int> map;
        for (auto n : nums) {
            ++map[n];
        }
        int a = 0;
        for (auto [n, o] : map) {
            if (o == 1) {
                a = n;
                break;
            }
        }
        return a;
    }
};
  1. 创建一个无序映射(unordered_map)count,用于记录每个元素出现的次数。

  2. 遍历数组nums,对于数组中的每个元素a,将其作为键,将其出现的次数加1。

  3. 遍历映射count中的每个键值对,对于每个键值对pair,如果其值等于1,说明该键对应的元素只出现了一次,返回该键。

  4. 如果遍历完映射count后仍未找到只出现一次的元素,则返回-1。

方法二:只有一个数字出现一次,其余数字均出现3次,假设数组为{3,5,3,3} 通过分析可知: 3的二进制:0 0 0 0 0 0 1 1 5的二进制:0 0 0 0 0 1 0 1 3的二进制:0 0 0 0 0 0 1 1 3的二进制:0 0 0 0 0 0 1 1 0 0 0 0 0 1 3 4 二进制1的总数 对于出现3次的数字,各位出现的次数都是3的倍数,因此对统计的为1的比特总数%3 0 0 0 0 0 1 0 1 = 5 

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for (int i = 0; i < 32; i++) {
            int sum = 0;
            for (auto n : nums) {
                if (((n >> i) & 1) == 1)
                    sum++;
            }
            sum %= 3;
            if (sum == 1)
                ret |= 1 << i;
        }
        return ret;
    }
};

260. 只出现一次的数字 III

 方法一:哈希表

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        unordered_map<int, int> map;
        for (auto n : nums) {
            map[n]++;
        }
        vector<int> rec;
        for (size_t i = 0; i < nums.size(); ++i) {
            if (map[nums[i]] == 1) {
                rec.push_back(nums[i]);
            }
        }
        return rec;
    }
};

这种方法虽然在代码中实现了,但是它不符合题目要求的线性时间和常数空间的要求。

  • 使用哈希表来记录每个元素出现的次数。
  • 遍历数组,将出现一次的元素添加到结果列表中返回。

这种方法的时间复杂度为O(n),空间复杂度也为O(n),因为需要额外的空间来存储哈希表。

 方法二:位操作

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int sum = 0;
        for (int num : nums) {
            sum ^= num;
        }
        int l = (sum == INT_MIN ? sum : sum & (-sum));
        int num1 = 0, num2 = 0;
        for (int num : nums) {
            if (num & l)
                num1 ^= num;
            else
                num2 ^= num;
        }
        return {num1, num2};
    }
};

这是符合题目要求的方法,利用了XOR运算的性质来解决问题:

  • 异或运算特性:相同为0,相异为1,无进位相加

    • 任何数和0做异或运算,结果仍然是原来的数,即 a⊕0=aa⊕0=a。
    • 任何数和其自身做异或运算,结果是0,即 a⊕a=0a⊕a=0。
    • 异或运算满足交换律和结合律,即 a⊕b=b⊕aa⊕b=b⊕a 和 (a⊕b)⊕c=a⊕(b⊕c)(a⊕b)⊕c=a⊕(b⊕c)。
  • 第一次异或

    • 我们遍历整个数组,将所有元素进行异或运算。由于数组中的大部分元素都是成对出现的,所以这些成对的元素相互抵消,最后得到的结果就是那两个只出现一次的数的异或结果。设这两个数为 xx 和 yy,那么我们得到的异或结果 sum=x⊕ysum=x⊕y。
  • 寻找差异位

    • 因为 xx 和 yy 是不同的数,所以 sumsum 至少有一个比特位是1。我们需要找到这个比特位,这可以通过将 sumsum 和它的补码 sum⊕(−sum)sum⊕(−sum) 进行与运算得到。这个比特位就是 sumsum 中从最低位开始的第一个1。
    • 另一种方法是直接使用 sumsum 本身,因为如果 sumsum 不是最小负数 INT_MIN,那么 sumsum 和它的补码的与运算结果就是 sumsum 的最低位1。如果 sumsum 是 INT_MIN,那么 sumsum 就已经是这个比特位了。
  • 第二次异或

    • 利用找到的差异位,我们可以将数组中的所有元素分为两类:那些在这个比特位上为1的数,以及那些在这个比特位上为0的数。
    • 对这两类数分别进行异或运算。因为每一对重复的数在这个比特位上的值是一样的,它们会在各自的类别中相互抵消,剩下的就是那个类别中只出现一次的那个数。
    • 于是我们得到了 xx 和 yy。

这种方法的时间复杂度为O(n),并且只需要常数级别的额外空间,满足题目的要求。

方法三:排序后比较

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<int> res;
        int i = 0;
        for (; i < nums.size() - 1;) {
            if (nums[i] == nums[i + 1]) {
                i += 2;
            } else {
                res.push_back(nums[i]);
                i += 1;
            }
        }
        if (i < nums.size()) {
            res.push_back(nums[i]);
        }
        return res;
    }
};

这种方法也不完全符合题目要求的线性时间和常数空间的要求,但可以理解它的逻辑:

  • 先对数组进行排序。
  • 遍历排序后的数组,如果遇到相邻元素不相等的情况,则当前元素一定是只出现一次的元素。
  • 最后处理数组尾部的元素。

这种方法的时间复杂度为O(n log n),因为排序通常需要O(n log n)的时间复杂度。空间复杂度取决于使用的排序算法,如果是原地排序则可以达到O(1),但大多数情况下会大于O(1)。

17. 电话号码的字母组合

回溯算法

class Solution {
public:
    string num_str[10] = {"",    "",    "abc",  "def", "ghi",
                          "jkl", "mno", "pqrs", "tuv", "wxyz"};
    void combination(const string& digits, size_t di, string combStr,
                     vector<string>& strv) {
        if (di == digits.size()) {
            strv.push_back(combStr);
            return;
        }
        int num = digits[di] - '0';
        string str = num_str[num];
        for (auto ch : str) {
            combination(digits, di + 1, combStr + ch, strv);
        }
    }
    vector<string> letterCombinations(string digits) {
        vector<string> str;
        if (digits.size() == 0)
            return str;
        combination(digits, 0, "", str);
        return str;
    }
};
  1. 初始化映射表

    • 创建了一个静态数组 num_str,用于存储数字到字母的映射关系。例如,"2" 映射到 "abc""3" 映射到 "def" 等等。注意索引 0 和 1 处的字符串为空,因为我们不考虑这两个数字对应的字母。
  2. 递归函数 combination

    • 这个函数接受四个参数:digits(输入的数字字符串)、di(当前处理的数字索引)、combStr(当前构建的字符串组合)以及strv(用于存储所有可能组合的向量)。
    • 如果当前处理的索引 di 已经等于 digits 的长度,说明已经处理完所有的数字,此时将当前构建的字符串 combStr 加入结果向量 strv
    • 否则,获取当前数字对应的字母字符串 str,然后遍历这个字符串中的每一个字母,并递归调用 combination 函数,同时增加索引 di 并将当前字母加入到 combStr
  3. 主函数 letterCombinations

    • 检查输入的 digits 字符串是否为空,如果为空则直接返回空的字符串向量。
    • 调用 combination 函数开始递归生成所有可能的组合。
    • 最终返回所有可能的字母组合。

示例步骤

假设 digits = "23",则有以下步骤:

  • 开始时,di=0combStr=""num=2,对应的字母是 "abc"
  • 对于每个字母 abc,执行 di+1,即 di=1
  • 当 di=1 时,num=3,对应的字母是 "def"
  • 对于每个字母 def,执行 di+1,即 di=2
  • 当 di=2 时,已经到达字符串末尾,将当前的 combStr 添加到结果向量中。

结果

对于 "23",结果向量将会包含 "ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"

这种方法的时间复杂度是 O(3^N * 4^M),其中 N 是数字2、3、4、5、6、8出现的次数,M 是数字7、9出现的次数,因为数字7和9对应4个字符,其它数字对应3个字符。空间复杂度主要取决于递归调用栈的深度,最坏情况下为 O(N)。

JZ39 数组中出现次数超过一半的数字

哈希表 

class Solution {
  public:
    int MoreThanHalfNum_Solution(vector<int>& numbers) {
        unordered_map<int, int> count;
        int n=numbers.size();
        for (auto a : numbers) {
            ++count[a];
            if (count[a] > n / 2) {
                return a;
            }
        }
        return -1;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多机编队—(1)ubuntu 配置Fast_Planner

文章目录 前言一、Could not find package ...二、使用error: no match for ‘operator’...总结 前言 最近想要做有轨迹引导的多机器人编队&#xff0c;打算采用分布式的编队架构&#xff0c;实时的给每个机器人规划出目标位置&#xff0c;然后通过Fast_Planner生成避障路径&…

【与C++的邂逅】--- string容器使用

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 与C的邂逅 本篇博客我们将来了解string容器本身以及接口的使用。 string是串&#xff0c;本质是一个字符数组&#xff0c;可以对其进行增删查改。 &am…

Camtasia2024破解版本电脑屏幕录像编辑神器全新体验

&#x1f31f; 屏幕录像与编辑神器——Camtasia2024全新体验 大家好&#xff01;今天我要来和大家安利一款让我彻底摆脱视频制作烦恼的神器——Camtasia2024&#xff01;&#x1f389; &#x1f308; 功能升级&#xff1a;更智能&#xff0c;更便捷 得提的是Camtasia 2024在功…

python的常用模块,必能覆盖你的需求

1.Request 把python的提示信息做到精细且覆盖广泛 2.Numpy 非常重要的库&#xff0c;最初学Python&#xff0c;第一个使用的就是这个。为Python提供了很多高级的数学方式 3.SciPy 是Python的算法和数学工具车&#xff0c;把很多科学家从RUby吸引到了python 4. P…

【车载开发系列】ParaSoft安装步骤介绍

【车载开发系列】ParaSoft安装步骤介绍 【车载开发系列】ParaSoft安装步骤介绍 【车载开发系列】ParaSoft安装步骤介绍一. 前言二. 安装步骤1. 双击安装包2. 选择安装语言3. 选择许可协议4. 选择软件安装位置5. 选择开始菜单文件夹6. 选择安装时的附加任务7. 安装准备完毕8. 执…

【小沐学OpenGL】Ubuntu环境下glfw的安装和使用

文章目录 1、简介1.1 OpenGL简介1.2 glfw简介 2、安装glfw2.1 直接命令二进制安装2.2 源码安装 3、测试glfw3.1 测试1&#xff0c;glfwglew3.2 测试2&#xff0c;glfwglad3.3 测试3 结语 1、简介 1.1 OpenGL简介 OpenGL作为图形界的工业标准&#xff0c;其仅仅定义了一组2D和…

PhotoZoom9怎么样?图片模糊怎么办?

DeepZoomPix的前身。PhotoZoom是一款新颖的、技术上具有革命性的对数码图片进行放大的工具。通常的工具对数码图片进行放大时&#xff0c;总会降低图片的品质&#xff0c;而这款软件使用了S-SPLINE Max技术 一种申请过专利的&#xff0c;拥有自动调节、高级的插值算法的技术&am…

PCIe总线-Linux内核PCIe设备枚举流程分析(十三)

1.简介 当系统启动时或者有新的PCIe设备接入时&#xff0c;PCIe主机会扫描PCIe总线上的PCIe设备&#xff0c;读取设备配置空间信息&#xff0c;建立设备的拓扑关系&#xff0c;然后为设备分配资源&#xff08;如内存空间、I/O空间、中断、总线编号等&#xff09;&#xff0c;最…

网络安全AI大模型训练从入门到精通

前言 2022年下半年&#xff0c;国内安全圈内开始完chatGPT&#xff0c;当时在安全圈内小火了一把。大家纷纷注册去体验一把&#xff0c;希望chatGPT能帮助解决日常安服渗透问题。当时以为仅此而已&#xff0c;谁知年后大火&#xff0c;随后以chatGPT为代表的大语言模型&#x…

【老课推荐】基于LangChain和知识图谱的大模型医疗问答机器人项目

在当今数据驱动和人工智能主导的时代&#xff0c;大模型和知识图谱的结合是一个重要的研究和应用方向。大模型实战课程通过48课时&#xff0c;分为六个主要章节&#xff0c;涵盖了从基本概念到高级应用的多方面内容。学员将通过本课程学习如何使用LangChain和OpenAI进行开发&am…

Spring Boot:医疗排班系统开发的技术革新

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

数据分析:Python语言相关性对角矩阵计算

文章目录 介绍加载R包导入数据计算连续型变量相关系数展示显著性结果图总结介绍 下三角相关系数矩阵是指相关系数矩阵中,仅展示主对角线以下部分(不包括主对角线)的值。在相关系数矩阵中,主对角线上的元素都是1(因为任何变量与自身的相关系数都是完美的1),而上三角和下…

Java笔试面试题AI答之单元测试JUnit(2)

文章目录 7. 为什么JUnit只报告单次测试中的第一次失败&#xff1f;8. Java中&#xff0c;assert是一个关键字。 这不会与JUnit的assert&#xff08;&#xff09;方法冲突吗&#xff1f;9. 解释如何测试静态方法&#xff1f;一、直接调用测试二、隔离依赖三、使用Mock框架四、重…

助贷行业的三大严峻挑战:贷款中介公司转型债务重组业务

大家是否察觉到一种趋势&#xff1f;现如今&#xff0c;众多贷款辅助服务机构与专注于债务再构的公司之间形成了紧密的“联动”。有的选择将获取的贷款需求转介给债务重组方&#xff0c;有的则直接下场&#xff0c;动用自身资本参与债务重组业务。这一现象背后&#xff0c;究竟…

每日一练:合并区间

一、题目要求 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&#xff1a;in…

四.海量数据实时分析-Doris数据导入导出

数据导入 1.概述 Apache Doris 提供多种数据导入方案&#xff0c;可以针对不同的数据源进行选择不同的数据导入方式。 数据源导入方式对象存储&#xff08;s3&#xff09;,HDFS使用 Broker 导入数据本地文件Stream Load, MySQL LoadKafka订阅 Kafka 数据Mysql、PostgreSQL&a…

表格多列情况下,loading不显示问题

问题描述&#xff1a; 用element plus 做得表格&#xff0c;如下图&#xff0c;列数较多&#xff0c;且部分表格内容显示比较复杂&#xff0c;数据量中等的情况下&#xff0c;有一个switch 按钮&#xff0c;切换部分列的显示和隐藏&#xff0c;会发现&#xff0c;切换为显示的时…

单线程 TCP/IP 服务器和客户端的实现

单线程 TCP/IP 服务器和客户端的实现 文章目录 单线程 TCP/IP 服务器和客户端的实现通信流程服务端客户端 代码实现服务端客户端 运行结果 通信流程 服务端 socket&#xff1a;创建监听的文件描述符(socket) fd&#xff1b;bind&#xff1a;fd 和自身的 ip 和端口绑定&#x…

【Transformer】Positional Encoding

文章目录 为什么需要位置编码&#xff1f;预备知识三角函数求和公式旋转矩阵逆时针旋转顺时针旋转 原始Transformer中的位置编码论文中的介绍具体计算过程为什么是线性变换&#xff1f; 大模型常用的旋转位置编码RoPE基本原理Llama3中的代码实现 参考资料 为什么需要位置编码&a…

DPDK基础入门(五):报文转发

网络处理模块划分 Packet Input: 接收数据包&#xff0c;将其引入处理流程。Pre-processing: 对数据包进行初步处理&#xff0c;例如基本的检查和标记。Input Classification: 细化数据包的分类&#xff0c;例如基于协议或流进行分流。Ingress Queuing: 将数据包放入队列中进行…