本篇主要式对一些题目的讲解,以便于提高大家对于vector的基本认识。
一、选择题
1.下面这个代码输出的是( )
#include <iostream>
#include <vector>
using namespace std;
int main(void)
{
vector<int>array;
array.push_back(100);
array.push_back(300);
array.push_back(300);
array.push_back(300);
array.push_back(300);
array.push_back(500);
vector<int>::iterator itor;
for(itor=array.begin();itor!=array.end();itor++)
{
if(* itor==300)
{
itor=array.erase(itor);
}
}
for(itor=array.begin();itor!=array.end();itor++)
{
cout<<*itor<<" ";
}
return 0;
}
选项:
A.100 300 300 300 300 500
B.100 3OO 300 300 500
C.100 300 300 500
D.100 300 500
E.100 500
F.程序错误
这题是比较经典的一道题,主要考察的是我们对于vector的函数的理解,答案是选择C
以下来源:牛客网
vector::erase():从指定容器删除指定位置的元素或某段范围内的元素
vector::erase()方法有两种重载形式
如下:
iterator erase( iterator _Where);
iterator erase( iterator _First, iterator _Last);
如果是删除指定位置的元素时:
返回值是一个迭代器,指向删除元素下一个元素;如果是删除某范围内的元素时:返回值也表示一个迭代器,指向最后一个删除元素的下一个元素;
在本题中,当 *itor==300成立时,删除第一个值为300的元素,同时itor指向下一个元素(即是第二个值为300的元素),
在for(;;itor++)执行itor,itor指向第三个值为300的元素,进入下一个循环
进入循环满足*itor==300,重复上面的过程,执行完循环,itor执行值为500的元素。
所有整个过程中,只删除了2个值为300的元素。
2.std::vector::iterator 没有重载下面哪个运算符( )
选项:
A.==
B.++
C.*
D.>>
这题选择D,原因很简单,
vector底层是以当前类型的指针作为迭代器,对于指针而言,能够进行操作的方法都支持,如==,++,*,而>>运算符并没有重载
故答案为D
3.T是一个数据类型,在vs系列编译器中,debug模式下,关于std::vector::at 和 std::vector::operator[] 描述正确的是( )
A.at总是做边界检查, operator[] 不做边界检查.
B.at 不做边界检查, operator[] 做边界检查.
C.at和operator[] 都是会做边界检查的
D.以上都不对
注意题目专门强调了vs系列编译器,debug模式下
at() 和 operator[] 都是根据下标获取任意位置元素的,在debug模式下两者都会去做边界检查。当发生越界行为时,at 是抛异常,operator[] 内部的assert会触发
故选择C
4.下面程序的输出结果正确的是( )
int main()
{
int ar[] = {1,2,3,4,5,6,7,8,9,10};
int n = sizeof(ar) / sizeof(int);
vector<int> v(ar, ar+n);
cout<<v.size()<<":"<<v.capacity()<<endl;
v.reserve(100);
v.resize(20);
cout<<v.size()<<":"<<v.capacity()<<endl;
v.reserve(50);
v.resize(5);
cout<<v.size()<<":"<<v.capacity()<<endl;
}
A.10:10 20:100 5:50
B.10:20 20:100 5:100
C.10:10 20:100 5:100
D.10 10 20:20 20:50
分析:vector<int> v(ar, ar+n);
cout<<v.size()<<":"<<v.capacity()<<endl; //大小为数组元素个数,因此size=10 capacity=10
v.reserve(100); //预留空间100
v.resize(20); //调整元素为20个,此时元素的size会改变,由于个数小于容量,因此容量不会变小
cout<<v.size()<<":"<<v.capacity()<<endl;// 故size=20 capacity=100
v.reserve(50);//期望预留空间为50,可是现在的空间已经有100个,所以空间不会减小
v.resize(5); //元素个数调整为5
cout<<v.size()<<":"<<v.capacity()<<endl;// 故size=5 capacity=100
所以答案为:C
二、编程题
1.118. 杨辉三角 - 力扣(LeetCode)
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> ret(numRows);
for (int i = 0; i < numRows; ++i) {
ret[i].resize(i + 1);
ret[i][0] = ret[i][i] = 1;
for (int j = 1; j < i; ++j) {
ret[i][j] = ret[i - 1][j] + ret[i - 1][j - 1];
}
}
return ret;
}
};
这题我们选择这样解决,首先我们知道杨辉三角形的特性是这样的:
-
每行数字左右对称,由 1 开始逐渐变大再变小,并最终回到 1。
-
第 n 行(从 0 开始编号)的数字有 n+1 项,前 n 行共有 n(n+1)/2 个数。
-
每个数字等于上一行的左右两个数字之和,
因此,,我们可以一行一行地计算杨辉三角。每当我们计算出第 i 行的值,我们就可以在线性时间复杂度内计算出第 i+1 行的值。
2.26. 删除有序数组中的重复项 - 力扣(LeetCode)
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int n = nums.size();
if (n == 0) {
return 0;
}
int fast = 1, slow = 1;
while (fast < n) {
if (nums[fast] != nums[fast - 1]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
};
这题我们准备使用双指针法(我个人认为挺难理解的)
这道题目的要求是:对给定的有序数组 nums 删除重复元素,在删除重复元素之后,每个元素只出现一次,并返回新的长度,上述操作必须通过原地修改数组的方法,使用 O(1) 的空间复杂度完成。
由于给定的数组 nums 是有序的,因此对于任意 i<j,如果 nums[i]=nums[j],则对任意 i≤k≤j,必有 nums[i]=nums[k]=nums[j],即相等的元素在数组中的下标一定是连续的。利用数组有序的特点,可以通过双指针的方法删除重复元素。
如果数组 nums 的长度为 0,则数组不包含任何元素,因此返回 0。
当数组 nums 的长度大于 0 时,数组中至少包含一个元素,在删除重复元素之后也至少剩下一个元素,因此 nums[0] 保持原状即可,从下标 1 开始删除重复元素。
定义两个指针 fast 和 slow 分别为快指针和慢指针,快指针表示遍历数组到达的下标位置,慢指针表示下一个不同元素要填入的下标位置,初始时两个指针都指向下标 1。
假设数组 nums 的长度为 n。将快指针 fast 依次遍历从 1 到 n−1 的每个位置,对于每个位置,如果 nums[fast]=nums[fast−1],说明 nums[fast] 和之前的元素都不同,因此将 nums[fast] 的值复制到 nums[slow],然后将 slow 的值加 1,即指向下一个位置。
遍历结束之后,从 nums[0] 到 nums[slow−1] 的每个元素都不相同且包含原数组中的每个不同的元素,因此新的长度即为 slow,返回 slow 即可。
以下为思路解释:
我们知道是递增的,因此我们只需要从头开始i读取,然后删去重复的。
首先,我们应该像获取所提供的顺序表的元素的个数
int n = nums.size();
然后,对于不同的个数的情况去具体问题具体分析,我们知道,当numsize为0时,我们可以直接返回0,
其次,我们用的是快慢指针法,所以我们要定义快和慢“指针”
int fast = 1, slow = 1;
因为第一位默认时最小的,所以我们只需要从第一位开始改就行,然后我们进行以下条件的判定
while (fast < n) //当fast大于vector中的所有元素总数时,跳出循环
{
if (nums[fast] != nums[fast - 1]) //当fast指向的内容不等时,给slow的指针赋值,然后
//low++
{
nums[slow] = nums[fast];
++slow;
}
++fast;
}
最后
return slow;
题解思路取自:力扣官方题解
链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/solutions/728105/shan-chu-pai-xu-shu-zu-zhong-de-zhong-fu-tudo/
来源:力扣(LeetCode)
3.260. 只出现一次的数字 III - 力扣(LeetCode)
这道题,其实就是我们之前做过的”单身狗“,换了一个形式罢了。
不过,这回,我不准备使用哈希表,我们讨个巧,我们用位运算,我们知道1^1为0,0^任何数=任何数本身,所以我们只需要遍历,然后将vector中的所有数^我们定义的变量即可
class Solution {
public:
vector<int> singleNumber(vector<int> &nums) {
unsigned int xor_all = 0;
for (int x: nums) {
xor_all ^= x;
}
int lowbit = xor_all & -xor_all;
vector<int> ans(2);
for (int x: nums) {
ans[(x & lowbit) != 0] ^= x;
}
return ans;
}
};
4.137. 只出现一次的数字 II
该题有多种解题思路,比如: 1. 统计每个数字出现的次数,然后找出只出现1次的数字,缺点:需要借助辅助空间 2. 对数据进行排序,然后找出只出现1次的数字,缺点:时间复杂度不是O(N) 而题目要求了,时间复杂度必须为O(N)线性时间复杂度,因此便增加了题目的难度。 题目说:只有一个数字出现一次,其余数字均出现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 ans = 0;
for (int i = 0; i < 32; ++i) {
// 统计该每个数字第i个比特位为1的总数
int total = 0;
for (int num: nums) {
total += ((num >> i) & 1);
}
// 如果total能够被3整除,说明只出现一次的数字在该位置上一定是0
// 否则在该位置上一定是1
if (total % 3) {
ans |= (1 << i);
}
}
return ans;
}
};
这种揭发比较容易i解决,但是不够快,如果,你想要更加快的可以去137. 只出现一次的数字 II - 力扣(LeetCode)看官方的题解