[C++初阶]vector的oj

本篇主要式对一些题目的讲解,以便于提高大家对于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 开始逐渐变大再变小,并最终回到 1。

  2. 第 n 行(从 0 开始编号)的数字有 n+1 项,前 n 行共有 n(n+1)/2​ 个数。

  3. 每个数字等于上一行的左右两个数字之和,

因此,,我们可以一行一行地计算杨辉三角。每当我们计算出第 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)看官方的题解

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值