【C++】7道经典面试题带你玩转vector

举报
修修修也 发表于 2024/09/30 17:20:07 2024/09/30
【摘要】 ​ 🦄个人主页:修修修也 🎏所属专栏:C++ ⚙️操作环境:Leetcode/牛客网​编辑目录一 .只出 现 一次的数字 二. 杨辉 三角 三. 删 除有序数 组 中的重复 项 四.只出 现 一次的数字 II 五.只出 现 一次的数字 III 六.数 组 中出 现 次数超 过 一半的数字 七. 电话 号 码 的字母 组 合 结语 一.只出现一次的数字题目链接:136. 只出 现 一次...

 

🦄个人主:修修修也

🎏所属专栏:C++

⚙️操作:Leetcode/牛客网

​编辑


.只出 一次的数字

二. 杨辉 三角

三. 除有序数 中的重复

四.只出 一次的数字 II

五.只出 一次的数字 III

六.数 中出 次数超 一半的数字

七. 电话 的字母

结语


.只出一次的数字

:

136. 只出 一次的数字 https://leetcode.cn/problems/single-number/


目描述:

        给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

        你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。


:

​编辑


思路:

        将数中的所有元素相异或,异或的果就是要求的解.

        对于这种题目的异或解法详细原理原理我在之前有写过C语言版本,下图是文章中节选出的部分推理过程,感兴趣的朋友可以移步:【C 言】找 问题 ​编辑


:

//数组元素异或法

class Solution

{

public:

int singleNumber(vector<int>& nums)

{

int ret=0;

for(auto e:nums)

{

ret^=e;

}

return ret;

}

};

提交运行:

​编辑


二.杨辉三角

:

118. 杨辉 三角 https://leetcode.cn/problems/pascals-triangle/


目描述:

给定一个非负整数 numRows生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

编辑


:

​编辑


思路:

        创建一个vector<vector<int>>的对象集合,集合中的元素是vector<int>.实际相当于一个二维数组,结构图示如下:​编辑        然后我们按照每一行的杨辉三角规律,将第一个和最后一个数置为1,其余数置为左上数加右上数的和即可.详细过程见代码注释.


:

class Solution

{

public:

vector<vector<int>> generate(int numRows)

{

vector<vector<int>> vv;

vv.resize(numRows);//numRows行,vv<int>就有多少个v<int>元素




for(int i=0; i < numRows; i++)

{

vv[i].resize(i+1,0);//第n行就有n个int,+1因为下标从0开始,行数从1开始




for(int j=0; j < vv[i].size(); j++)

{

//如果,不是每一行的第一个数字也不是最后一个数字,就等于左上加右上数字的和

if(j > 0 && j != i)

{

vv[i][j] = vv[i-1][j-1] + vv[i-1][j];

}

else //否则,就是1

{

vv[i][j] = 1;

}

}

}

return vv;

}

};

提交运行:

​编辑


三.除有序数中的重复

:

26. 除有序数 中的重复 https://leetcode.cn/problems/remove-duplicates-from-sorted-array/


目描述:

        给你一个 增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出一次 ,返回删除后数组的新长度。元素的 对顺 应该保持 一致 。然后返回 nums 中唯一元素的个数。

        考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

• 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。

• 返回 k 。

题标:

        系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组

int[] expectedNums = [...]; // 长度正确的期望答案


int k = removeDuplicates(nums); // 调用


assert k == expectedNums.length;

for (int i = 0; i < k; i++) {

assert nums[i] == expectedNums[i];

}

        如果所有断言都通过,那么您的题解将被


:

​编辑


思路:

        解题思路见下图:​编辑


:

class Solution

{

public:

int removeDuplicates(vector<int>& nums)

{

//因为vector的erase接口接收的参数类型是迭代器,

//所以我们创建一个nums的初始迭代器,方便后续传参

vector<int>::iterator it = nums.begin();




//用i循环遍历数组

for(int i = 0; i < nums.size()-1; i++)

{

//如果i指向的数据和i+1相等,那么我们就删除数据i

while(nums[i] == nums[i+1])

{

nums.erase(it + i);




//如果删除后数组只剩下一个元素或i已经是数组最后一个元素

//终止循环

if(nums.size() == 1 || i >= nums.size()-1)

{

break;

}

}

}




//数组的元素个数即为数组中唯一元素的个数

return nums.size();

}

};

提交运行:

​编辑


四.只出一次的数字 II

:

137. 只出 一次的数字 II https://leetcode.cn/problems/single-number-ii/


目描述:

        给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

        你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。


:

​编辑


思路:

        首先,我们可以观察一下题目的特征:​编辑        然后我们需要了解一下整型数据在内存中的存储,详细的内容可以移步这篇博客:【C 言】整形数据和浮点型数据在内存中的存 ​编辑        然后我们举一组数据的例子来帮助大家理解一下这个解法的过程:​编辑        还有一点需要注意的是,如果结果为负数,我们要按补码的方式计算十进制数:​编辑


:

class Solution

{

public:

int singleNumber(vector<int>& nums)

{

vector<int> v;

v.resize(32,0);




for(int i=0 ; i<nums.size() ; i++)

{

for(int j=0 ; j<32 ; j++)

{

//将num[i]的二进制位的数字累加到v中

if(((nums[i] >> j) & 1) == 1)

{

v[31-j]++;

}

}

}

//消除所有位上呈3次出现的1

for(int i=0;i<v.size();i++)

{

v[i]%=3;

}




//留下的数据就是没有出现过三次的,而是只出现过一次的

int ret=0;

//负数的话按补码的方式计算原码的十进制数,即先取反再+1;

if(v[0]==1)

{

for(int i=1;i<v.size();i++)

{

if(v[i]==0)//相反的位才是有效数据

{

ret += pow(2 , (31 - i));

}

}

return -ret-1;

}

else//不是负数,按正常原码计算十进制数

{

for(int i=1;i<v.size();i++)

{

if(v[i]!=0)

{

ret += pow(2 , (31 - i));

}

}

return ret;

}

}

};

提交运行:

​编辑


五.只出一次的数字 III

:

260. 只出 一次的数字 III https://leetcode.cn/problems/single-number-iii/


目描述:

        给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意 返回答案。

        你必须设计并实现线性时间复杂度的算法且仅使用常量额外空间来解决此问题。


:

​编辑


思路:

        这个问题的解题思路推导在我之前的一个博客里有详细的解释,感兴趣的朋友可以移步:【C 言】找 问题  在这里我简单截取一些博文中的解释,方便大家理解:

​编辑

由上述推导可得,该题目解题步骤如下:

1. 将数所有元素相异或

2. 找到可以区分两个只出一次的数的二制位

3. 根据个不同的二制将数据分异或

4. 异或的果就是两个只出了一次的数字


:

class Solution

{

public:

vector<int> singleNumber(vector<int>& nums)

{

//求出两个只出现一次的元素相异或的结果

int test=0;

for(int i=0 ; i<nums.size() ; i++)

{

test^=nums[i];

}




//根据异或结果求出它们哪个二进制位不相等

int pos=0;

for(int i=0 ; i<32 ; i++)

{

//检查将test右移1位后末位是否为1,如果是1,记录下右移的位数

if(((test >> i) & 1) == 1)

{

pos=i;

break;

}

}




//以test右移pos位后末位是1还是0为条件,将nums数组元素分为两组,分别相异或

int ret1=0;

int ret2=0;

for(int i=0 ; i<nums.size() ; i++)

{

if(((nums[i] >> pos) & 1) == 1)

{

ret1^=nums[i];

}

else

{

ret2^=nums[i];

}

}




//分组相异或的结果,就是两个只出现一次的数字,将其通过vector返回

vector<int> vRet;

vRet.push_back(ret1);

vRet.push_back(ret2);




return vRet;

}

};

        对于上述代码中的这行代码,很多朋友可能不太理解,我在这里详细解释一下:

if(((test >> i) & 1) == 1)

解析

1. 位运算符 >>

o test >> i:这个操作是将整数 test 的二进制表示右移 i 位。

o 右移操作会将整数的所有位向右移动 i 位,移动出来的位会被丢弃,左侧将用符号位填充(即对于正数填充0,对于负数填充1)。

例如,对于 test = 10(即二进制 1010)和 i = 1,则:

10 (二进制 1010) 右移 1 位 -> 0101 (即 5)

2. 位与运算符 &

o (test >> i) & 1:这个操作会对右移后的结果和 1 进行按位与操作。

o 1 的二进制表示是 ...0001,所以这个操作的目的是检查右移后的结果的最低位(也就是现在的第 i 位)是否为 1。

继续上面的例子:

右移后结果:0101 (5) 0101 & 0001 = 0001 (保留最低位,结果为 1)

3. 判断是否等于 1

o ((test >> i) & 1) == 1:最终的判断是检查上面的操作结果是否等于 1。

o 如果结果是 1,则说明原始的 test 在第 i 位上是 1;如果结果是 0,则说明第 i 位上是 0。


提交运行:

​编辑


六.数中出次数超一半的数字

:

JZ39 数 中出 次数超 一半的数字 https://www.nowcoder.com/practice/e8a1b01a2df14cb2b228b30ee6a92163?tpId=13&&tqId=11181&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking


目描述:

        给一个长度为 n 的数组,数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

        例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

        数据范围:n≤50000,中元素的 0≤val≤10000

        要求:空间复杂度:O(1),时间复杂度 O(n)


:

​编辑


思路:

        利用哈希的思想,创建一个数据范围内大小的vector,用于统计各个数据出的次数.然后遍历数组numbers,每遍历一个数据就给其对应哈希映射的对应数据+1,然后判断其映射数据是否大于numbers数组长度的一半,如果大于,则该数据即为待求数据.解题过程图示如下:​编辑


:

class Solution {

public:

/**

* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可

*

*

* @param numbers int整型vector

* @return int整型

*/

int MoreThanHalfNum_Solution(vector<int>& numbers)

{

// write code here




vector<int> ret;

ret.resize(10001, 0);

for(int i=0;i<numbers.size();i++)

{

ret[numbers[i]]++;

if(ret[numbers[i]]>(numbers.size()/2))

{

return numbers[i];

}

}

return 0;

}

};

提交运行:

​编辑


七.电话的字母

:

17. 电话 的字母 https://leetcode.cn/problems/letter-combinations-of-a-phone-number/


目描述:

        给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意 返回。

        给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

编辑


:

​编辑


思路:

        该题我们首先要创建一个字符串数组来将数字和字符的映射关系存储起来,方便我们后续取用数字对应的映射关系:

string strA[10]={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};

        其次我们通过画图可知,digits字符串有几个数字,我们的组合层数就会有几层,而每一层和下一层的组合逻辑都是相似的,所以我们可以尝试使用递归来将每一层组合出的字符组合在一起,这样直到递归到最后一层,就可以得到这次组合的结果,详细的过程见解题代码注释:​编辑


:

//多路递归

class Solution

{

//构造字符串映射关系

string strA[10]={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};

public:

// 题目的digits 递归过程中的记录组合变量

void Combine(string digits,int level,string combineStr,vector<string>& vs)

// 表示传到第level层了 最终要把得到的字符串存进vector里

{

//首先先确定自己在第几层,同时设定递归的递出条件

if(level == digits.size())

{

vs.push_back(combineStr);

return ;

}




//num代表取strA数组的哪个映射

int num = digits[level] - '0';

//取映射字符串

string str = strA[num];




//依次取字符串里的字符

for(int i=0 ; i<str.size() ; i++)

{

Combine(digits,level+1,combineStr + str[i],vs);

}

}




vector<string> letterCombinations(string digits)

{

vector<string> vs;

if(digits.size()==0)

{

return vs;

}

Combine(digits,0,"",vs);




return vs;

}

};

提交运行:

​编辑


结语

        希望通上面的目能使大家vector象集合的理解以及运用能更上一,迎大佬留言或私信与我交流.学海漫浩浩,我亦苦作舟!关注我,大家一起学,一起!

相关文章推荐

【C++】9道 典面 试题带 你玩 string

【C++】模 拟实现 string

【C++】 解深浅拷 的概念及其区

【C++】 动态 内存管理

【C++】 库类 string

【C++】构建第一个C++ :Date

【C++】 的六大默 函数及其特性 (万字 )

【C++】函数重

【C++】什么是 ?


​编辑

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。