【Leetcode】vector刷题

Alt

🔥个人主页Quitecoder

🔥专栏Leetcode刷题

Alt

目录

  • 1.只出现一次的数字
  • 2.杨辉三角
  • 3.删除有序数组中的重复项
  • 4.只出现一次的数字II
  • 5.只出现一次的数字III
  • 6.电话号码的字母组合

1.只出现一次的数字

题目链接:136.只出现一次的数字
题目描述在这里插入图片描述

这道题很简单,我们只需要遍历一遍数组,利用异或操作的性质(一个数与自身异或结果为0,任何数与0异或还是其本身)

class Solution {
public:int singleNumber(vector<int>& nums) {int value =0;for(auto v:nums){value^=v;}return value;}
};

2.杨辉三角

题目链接:118.杨辉三角
题目描述在这里插入图片描述

这道题我们需要构造二维数组,典型的vector的嵌套使用

在这里插入图片描述
首先,我们先构建二维数组,开辟行数大小:

vector<vector<int>> v(numRows);

接着对每一行进行开辟空间,并将两端初始化为1

for(int i=0;i<numRows;i++)
{v[i].resize(i+1);v[i][0]=1;v[i][i]=1;
}

注意,resize是会进行初始化的,我们没有传值,默认为零

所以我们只需要遍历一遍,遍历到的位置为0,进行相加操作

完整代码如下:

class Solution {
public:vector<vector<int>> generate(int numRows) {vector<vector<int>> v(numRows);for(int i=0;i<numRows;i++){v[i].resize(i+1);v[i][0]=1;v[i][i]=1;}for(int i=0;i<numRows;i++){for(int j=0;j<i;j++){if(v[i][j]==0){v[i][j]=v[i-1][j]+v[i-1][j-1];}}}return v;}
};

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

题目链接:26.删除有序数组中的重复项
题目描述在这里插入图片描述

这题是一道简单的双指针思路的题,由于已经排序好,我们只需要设置两个索引,一个向后遍历,若与前面的索引指向值不相同,则对前面的值进行修改

lass Solution {
public:int removeDuplicates(vector<int>& nums) {if (nums.size() == 0) {return 0;}int slow = 0;for (int fast = 1; fast < nums.size(); fast++) {if (nums[fast] != nums[slow]) {slow++;nums[slow] = nums[fast];}}return slow + 1;}
};

完成了值的覆盖过程

4.只出现一次的数字II

题目链接:137.只出现一次的数字II
题目描述在这里插入图片描述

这个问题的解决方案基于位操作和有限状态自动机的原理。我们要处理的数字是32位整数,因此,我们需要考虑每一位相加后的结果。由于除了一个数字以外,其它数字都出现了三次,我们可以构造一个数字的每一位相加后,模3的结果就是这个只出现一次的数字的相应位

思路如下:

使用两个整数变量onestwosones将会记录每个位只出现一次的情况,而twos将会记录每个位出现两次的情况

对于每个数字num及其每一位,我们更新onestwos

  1. 在第i个位置上,如果ones里的位是1,则表示num要么是第一次遇到i位为1,要么是第四次。如果是第四次,我们已经在twos里记录了两次,所以这次应该把ones里的该位清零,否则保持不变

  2. 同理,如果twos里的位是1,则是第二次遇到i位为1或者是第五次。如果是第五次,我们既要在ones里面加1,同时也要在twos里面清零该位,否则保持不变

  3. 由于我们只需要考虑每个位上1出现的次数,所以任何时候位上的1出现3次,我们都应该清零

最后,ones保留的就是每位上出现一次的结果,而twos将会是0。

class Solution {
public:int singleNumber(vector<int>& nums) {int ones = 0, twos = 0;       for (int num : nums) {ones = (ones ^ num) & ~twos;twos = (twos ^ num) & ~ones;}return ones;}
};

当我们讨论处理出现三次的数字和一个只出现一次的数字时,onestwos 的位操作确实是难以理解的 ,分解这两行代码:

对于每一个新的数字 num,我们用 onestwos 来跟踪彼此独立的状态:

  1. ones = (ones ^ num) & ~twos;

这里,我们正更新 ones 以包含出现一次的位。让我们分解这行代码:

  • ones ^ num:这个按位异或操作背后的思想是:当前的 ones 表示上一步迭代中已经出现一次的位。当我们再次看到这些位时(即 num 中的对应位也是1),我们希望重置 ones 中的那些位(因为出现一次变成了两次)。对于 num 中新出现的1,ones 中还没有记录,这将被加进 ones

  • & ~twos:接下来的按位与操作~twos 结合表示:我们删除 twos 中已经出现两次的位。~twos 是对 twos 取反,意味着取出 twos 中为0的位。只有那些在 twos 中没有记录(即还没达到两次)的1才应该加入 ones。即使刚才 ones ^ num 把某些位变成了1,若那些位在 twos 中已经出现过两次,我们必须确保它们在 ones 中不变成1

结合二者,ones 在每次迭代结束时仅保留那些恰好出现一次的位。如果某位在 ones 中变成了1但已经在 twos 中出现过,我们需要重置 ones 中的那位为0

  1. twos = (twos ^ num) & ~ones;

接着我们更新 twos 来反映那些已经看到两次的位:

  • twos ^ num:与更新 ones 类似,我们对于每个新来的 num,我们都会用按位异或更新 twos。如果在 twos 中的位是1,且对应的 num 中的位也是1,那么它们会重置为0,因为现在这个位出现了第三次,而我们的目标是找到出现了一次和两次的位。如果出现的是一个新的1(即 num 中的1,而 twos 中并没有记录),twos 就会记录它。这会出现加到三的情况,我们随后会处理。

  • & ~ones:这个按位与操作保证如果在 ones 中有1(意味着这个位已经出现了一次),我们不会在 twos 中加入该位。如果某个位同时在 onestwos 中出现,这意味着这个位出现了3次,并且最终会被忽略。

通过 & ~ones,我们确保了一个位仅仅当它在 num 中为1且在 ones 中尚未出现(即 ones 中为0)时,才会被加入 twos

总结来说,这两步操作是相互独立并且排他的:它们保证一个位在 onestwos 中出现,但不会同时出现。我们在整体数组中使用循环来考虑每个数字的影响。最终,由于所有出现三次的数字在这两个变量中都被消去,ones 会留下那个出现一次的唯一位

5.只出现一次的数字III

题目链接:260.只出现一次的数字III
题目描述在这里插入图片描述

此类问题可以通过位运算(异或操作)来解决。首先,我们可以通过对所有数组元素执行异或操作来找出两个只出现一次的元素的异或结果。因为异或操作具有交换律和结合律,同时一个数字和自己进行异或会变成0,所以最终剩下的结果就是那两个只出现一次的数字的异或结果

这个结果中至少有一个位是1(否则这两个数相同),我们可以找到这个数中的任何一个为1的位,用它来把原数组分成两组,一组在该位上是1,一组在该位上是0。这样每组就包含了一个只出现一次的数字和一些成对出现的数字。然后再对这两个组分别进行异或操作,即可得到这两个只出现一次的数字。

下面是这个算法实现:

class Solution {
public:vector<int> singleNumber(vector<int>& nums) {// 第一步,对所有元素进行异或,最终的结果就是两个只出现一次数的异或结果int diff = 0;for (int num : nums) {diff ^= num;}// 找到diff中任何为1的位,可以使用diff & -diff快速找到// 这个操作可以隔离出diff最右端的1unsigned int diff_unsigned = diff;diff_unsigned &= -diff_unsigned;// 使用找到的这一位将数组中的数字分成两组vector<int> results(2, 0); // 最终结果for (int num : nums) {if ((num & diff_unsigned) == 0) {// 第一组,与diff_unsigned对应位为0results[0] ^= num;} else {// 第二组,与diff_unsigned对应位为1results[1] ^= num;}}return results;}
};

在这个代码中:

  • diff_unsigned 最终会被设置为两个目标数字的异或结果。
  • diff_unsigned &= -diff_unsigned; 的结果是取出 diff_unsigned 最右边的1位,也就是两个只出现一次的数在这一位上不同的地方。
  • 然后我们通过判断这一位是否为1来将全部数字分为两组,并再次分别对它们进行异或操作,以此找到两个只出现一次的数。

这条语句 diff_unsigned &= -diff_unsigned; 是一种计算机用来找到一个数字中最右边的1的位,并且保持所有其他位为0的技巧。为了更好地理解这个技巧,我们需要先了解计算机中的数字表示——特别是补码表示法,因为这个技巧与负数的二进制表示相关

在补码表示中,一个负数是通过取其正值的二进制表示的反码(每个位取反)然后加1得到的。例如,假设我们有一个4位的系统:

正数 2 的二进制表示:  0010
反码 (invert):      1101
加1得到负数 -2:      1110

观察发现,从正数2的二进制表示到负数-2的表示,最右边的1以及之前的所有0都保持不变,而最右边的1之后的所有位都翻转了。这给了我们一种找到最右边的1的方法。现在,如果我们对2和-2执行按位与操作:

正数 2:                0010
负数 -2:               1110
按位与:                0010

按位与操作的结果就是只有最右边的1保留了下来,其它所有位都变成了0。换句话说,diff_unsigned &= -diff_unsigned; 将结果的所有位都置为0,除了最右边的1所在的位。

在解决问题时,我们首先会通过对所有数字进行异或得到 diff,这代表了两个只出现一次的数字的差异。
diff 变量首先被转换成一个无符号整数 diff_unsigned,然后对它进行取负和按位与操作,以避免未定义行为。这样就保证了即使 diff 的最高有效位是1,我们也不会超出无符号整型的范围

然后使用 diff_unsigned &= -diff_unsigned; 来保留最右边的1,这是两个独特数字在二进制表示中第一个不同的位。

通过这个位的差异,我们可以将所有的数字分成两组来进一步操作,每组包含一个只出现一次的数字以及成对出现的数字。这个1所在的位将用于分辨哪些数字在该位为0或1 —— 这正是对数组进行划分的依据

6.电话号码的字母组合

题目链接:17.电话号码的字母组合
题目描述在这里插入图片描述

这个问题可以通过回溯法解决,这是一种通过穷举所有可能的解来找到全部解的算法。基本思想是从左到右遍历数字字符串,对于每个数字,向当前的字母组合中添加对应的每个字母,然后对剩余的字符串重复这个过程。

下面是递归解决实现:

class Solution {
public:vector<string> letterCombinations(string digits) {if (digits.empty()) return {}; // 如果输入为空,直接返回空数组vector<string> mappings = {  // 数字到字母的映射"", "", "abc", "def",   // '0','1','2',..."ghi", "jkl", "mno","pqrs", "tuv", "wxyz"};vector<string> result;string current;backtrack(result, digits, 0, current, mappings);return result;}private:void backtrack(vector<string>& result, const string& digits, int index, string& current, const vector<string>& mappings) {if (index == digits.length()) { // 如果到达了数字字符串的末尾,就添加当前的字母组合到结果中result.push_back(current);return;}string letters = mappings[digits[index] - '0']; // 获取当前数字对应的所有字母for (char letter : letters) { // 遍历这些字母current.push_back(letter);   // 添加当前的字母backtrack(result, digits, index + 1, current, mappings);  // 继续处理下一个数字current.pop_back();  // 回溯,移除当前字母,以便尝试下一个字母}}
};

这段代码定义了一个辅助函数 backtrack,用来递归寻找所有可能的字母组合。我们维护一个 current 字符串,它保存当前的部分组合。函数的工作流程是这样的:

  1. 确定终止条件:如果 current 的长度与输入数字字符串的长度相同,说明当前递归路径已经走到头,我们找到了一个完整的字母组合,将其添加到结果中。

  2. 确定递归逻辑:从 mappings 数组中获取当前处理的数字对应的所有可能字母,然后逐一向 current 添加每个字母,并递归地调用自己处理下一个数字。

  3. 回溯处理:每次递归调用完成后,需要将之前添加的字母移除,以便对当前位置尝试不同的字母。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka 3.x.x 入门到精通(05)——对标尚硅谷Kafka教程

Kafka 3.x.x 入门到精通&#xff08;05&#xff09;——对标尚硅谷Kafka教程 2. Kafka基础2.1 集群部署2.2 集群启动2.3 创建主题2.4 生产消息2.5 存储消息2.6 消费消息2.6.1 消费消息的基本步骤2.6.2 消费消息的基本代码2.6.3 消费消息的基本原理2.6.3.1消费者组2.6.3.1.1 消费…

C语言----单链表的实现

前面向大家介绍了顺序表以及它的实现&#xff0c;今天我们再来向大家介绍链表中的单链表。 1.链表的概念和结构 1.1 链表的概念 链表是一种在物理结构上非连续&#xff0c;非顺序的一种存储结构。链表中的数据的逻辑结构是由链表中的指针链接起来的。 1.2 链表的结构 链表…

[Diffusion Model笔记] DDPM数学推导版 2024.04.23

本文是观看以下视频的笔记&#xff1a; https://www.bilibili.com/video/BV1CU4y1i7jn/?p4&spm_id_frompageDriver 其他参考 https://zhuanlan.zhihu.com/p/614147698 https://zhuanlan.zhihu.com/p/563661713 这个写的非常详细&#xff1a; https://www.zhihu.com/ques…

成都爱尔胡建斌院长提醒视网膜脱离并非立即失明!这些征兆要注意!

大家都知道视网膜脱离危险&#xff0c;它的危险在于视网膜脱离后外层视网膜得不到脉络膜的血液供应&#xff0c;未及时复位视网膜感光细胞就会发生凋亡&#xff0c;视力发生缺损。 视网膜脱离对视力的影响是与病程同步的&#xff0c;发病初期眼前多有黑影、漂浮物、闪光感或幕…

十七、Java网络编程(一)

1、Java网络编程的基本概念 1)网络编程的概念 Java作为一种与平台无关的语言,从一出现就与网络有关及其密切的关系,因为Java写的程序可以在网络上直接运行,使用Java,只需编写简单的代码就能实现强大的网络功能。下面将介绍几个与Java网络编程有关的概念。 2)TCP/IP协议概…

2024年03月CCF-GESP编程能力等级认证Python编程三级真题解析

本文收录于专栏《Python等级认证CCF-GESP真题解析》,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 一、单选题(共15题,共30分) 第1题 小杨的父母最近刚刚给他买了一块华为手表,他说手表上跑的是鸿蒙,这个鸿蒙是( ) A.小程序 B.计时器 C.操作系统 D.神话人物 答…

江苏开放大学2024年春《机械CAD/CAM 050097》第三次在线作业参考答案

单选题 1数控编程技术包含了数控加工与编程、金属加工工艺、CA/CA软件操作等多方面的知识&#xff0c;其主要任务就是计算加工走刀中的__________。 A刀具终点 B刀位点 C刀具起点 D刀具中点 答案是&#xff1a;B 2操作人员在CAD/CA系统中起____________作用。 …

认识HTTP

HTTP缺点 通信使用明文&#xff08;不加密&#xff09;&#xff0c;内容可能会被窃听 不验证通信方的身份&#xff0c;可能遭遇伪装 无法证明报文的完整性&#xff0c;所以有可能遭篡改 一、通信使用明文&#xff08;不加密&#xff09;&#xff0c;内容可能会被窃听 TCP/…

互联网安全面临的全新挑战

前言 当前移动互联网安全形势严峻&#xff0c;移动智能终端漏洞居高不下、修复缓慢&#xff0c;移动互联网恶意程序持续增长&#xff0c;同时影响个人和企业安全。与此同时&#xff0c;根据政策形势移动互联网安全监管重心从事前向事中事后转移&#xff0c;需加强网络安全态势感…

new String和直接赋值的一些问题

分析1 我们先看以下代码&#xff1a; String str1 "abc"; // 在常量池中String str2 new String("abc"); // 在堆上System.out.println(str1 str2)以上结果的输出是什么&#xff1f; 输出&#xff1a;false 前置知识&#xff1a; 在JVM中&#xff0c…

快手面试算法真题

按照html中的标签层数遍历节点名。 例如&#xff1a;html代码如下&#xff1a;(上面的数字表示层数) <!-- 1 --><div class"div1"><!-- 2 --><span class"span1"></span><!-- 2 --><p class"p1"><…

PTA 天梯赛 L1-010 比较大小【C++】 L1-011 A-B 【C++ vector动态数组】【Python 字符串replace函数】

L1-010 比较大小 判断顺序很重要 #include<iostream> using namespace std; int main() {int a, b, c;cin >> a >> b >> c;int temp;if (a > b) {temp a;a b;b temp;}if (a > c) {temp a;a c;c temp;}if (b > c) {temp b;b c;c te…