2-刷力扣问题记录
25.2.13
1.to_string函数的作用是什么
to_string
是 C++ 标准库中的一个函数,用于将 数值类型 转换为 字符串。
作用:
to_string
将数值类型(如 int
、float
、double
、long
等)转换为对应的字符串表示形式。
用法:
#include <iostream>
#include <string>
int main() {
int num = 123;
double pi = 3.14159;
std::string str_num = std::to_string(num); // 将整数转为字符串
std::string str_pi = std::to_string(pi); // 将浮点数转为字符串
std::cout << "Integer as string: " << str_num << std::endl; // 输出: Integer as string: 123
std::cout << "Double as string: " << str_pi << std::endl; // 输出: Double as string: 3.141590
}
例子:
int num = 42;
std::string str = std::to_string(num); // str = "42"
double pi = 3.14159;
std::string pi_str = std::to_string(pi); // pi_str = "3.141590"
注意:
- 对于 浮点数(
float
、double
等),to_string
会保留小数点后六位(默认行为)。 to_string
适用于数值类型的转换,不支持直接将其他类型(如char
、bool
等)转换为字符串。
小结:
to_string
是将数值类型转化为字符串的一个便捷工具,适用于在 C++ 中进行类型转换时使用。
25.2.15
1.为什么下面这行代码可以舍弃末尾元素: postorder.resize(postorder.size() - 1);
resize
函数
resize
是 C++ 标准库中 std::vector
类提供的一个成员函数,功能是改变向量的大小。如果新的大小小于当前大小,那么多余的元素会被移除;如果新的大小大于当前大小,则会添加默认构造的元素(比如 int
的话会填充 0
,char
会填充 '\0'
,等等)。
void resize(size_t new_size);
new_size
是你希望vector
最终的大小。- 如果
new_size
小于当前的大小,vector
会被裁剪到新的大小,丢弃掉超出的元素。 - 如果
new_size
大于当前的大小,vector
会扩展,并按元素类型的默认构造方法填充新的元素。
是的,resize
默认是通过舍弃末尾元素来调整 std::vector
的大小的
2.如何去掉第一个元素呢?
要去掉一个 vector
的第一个元素,可以通过几种方法来实现。以下是几种常见的方式:
方法 1:使用 erase
方法
vector::erase
可以用来删除 vector
中的元素。要删除第一个元素,可以使用 erase
方法删除下标为 0
的元素
vector<int> vec = {1, 2, 3, 4};
vec.erase(vec.begin()); // 删除第一个元素
// vec 现在是 {2, 3, 4}
方法 2:使用 vector::begin
和 vector::end
重新构造一个新的子 vector
如果你想要得到一个没有第一个元素的新 vector
,你可以使用 vector
的构造函数来创建一个新的子 vector
,从而跳过第一个元素。
vector<int> vec = {1, 2, 3, 4};
vector<int> newVec(vec.begin() + 1, vec.end()); // 从第二个元素开始构建新的vector
// newVec 现在是 {2, 3, 4}
方法 3:使用 pop_front
(如果是 deque
)
如果你使用的是 deque
(双端队列),你可以直接使用 pop_front
方法删除第一个元素。vector
没有 pop_front
方法,但如果使用 deque
,这种方法是很方便的。
deque<int> deq = {1, 2, 3, 4};
deq.pop_front(); // 删除第一个元素
// deq 现在是 {2, 3, 4}
选择方法
- 如果你只是想删除第一个元素并更新原始
vector
,使用erase
是最简单的方法。 - 如果你想生成一个新
vector
,其中不包含第一个元素,使用 构造子vector
的方法也很简洁。 - 如果你使用的是
deque
而不是vector
,可以使用pop_front
。
对于 vector
类型,方法 1 和 2 都是常用的方案。
25.2.16
1.数组nums里的nums.begin()和nums.end()返回的是什么
nums.begin()
和 nums.end()
返回的是 vector
(或者其他标准容器)的 迭代器,它们用于指示容器的开始和结束位置。迭代器在 C++ 中类似于指针,用于访问容器中的元素。
nums.begin()
nums.begin()
返回一个 指向容器第一个元素的迭代器。- 如果容器为空,
begin()
会返回一个和end()
相等的迭代器。
例如,假设你有一个 vector<int>
:
vector<int> nums = {10, 20, 30};
auto it = nums.begin();
cout << *it << endl; // 输出:10,因为 it 指向第一个元素
nums.end()
nums.end()
返回一个 指向容器最后一个元素之后的位置的迭代器,也叫做“尾后迭代器”。- 它不指向容器的元素,而是指向一个超出容器范围的一个位置,表示容器的结束。
- 迭代器
end()
不能解引用(即不能通过*it
获取数据),因为它并不指向有效的元素。
例如:
vector<int> nums = {10, 20, 30};
auto it = nums.end();
cout << *(it - 1) << endl; // 输出:30,因为 it - 1 指向最后一个元素
使用 begin()
和 end()
遍历容器
begin()
和 end()
通常用在 范围-based for 循环 或 标准库算法 中,来遍历容器:
范围-based for 循环:
vector<int> nums = {10, 20, 30};
for (auto it = nums.begin(); it != nums.end(); ++it) {
cout << *it << " "; // 输出:10 20 30
}
使用 STL 算法(如 std::sort
):
vector<int> nums = {30, 10, 20};
sort(nums.begin(), nums.end()); // 排序
for (int num : nums) {
cout << num << " "; // 输出:10 20 30
}
总结:
nums.begin()
返回一个指向容器第一个元素的迭代器。nums.end()
返回一个指向容器最后一个元素之后位置的迭代器(尾后迭代器)。- 迭代器是 C++ 标准容器的一个重要概念,用来遍历、访问容器中的元素。
25.2.27
1.数组和列表分别是如何定义的,vector是啥,二维数组和列表是怎么定义的
在 C++ 中,数组、列表(std::list
)、vector
和二维数组的定义方式各不相同。下面我将详细说明这些概念以及如何定义它们。
1. 数组 (Array)
数组是一个固定大小的数据结构,所有元素的类型相同,并且在内存中是连续存储的。
定义:
// 定义一个大小为 5 的整型数组
int arr[5];
// 定义并初始化一个数组
int arr[5] = {1, 2, 3, 4, 5};
- 静态数组:定义时必须指定大小,且大小在定义时确定并不能改变。
- 数组元素访问:可以通过下标来访问数组元素,
arr[0]
是第一个元素,arr[4]
是最后一个元素。
注意:
- C++ 中的数组大小是固定的,一旦定义好,大小无法改变。
- 数组不提供直接的扩展、删除等功能。
2. std::vector
std::vector
是 C++ 标准库中的动态数组,它可以动态调整大小,能够在运行时增加或减少元素,非常灵活。
定义:
#include <vector>
// 定义一个空的 vector
std::vector<int> vec;
// 定义并初始化一个 vector
std::vector<int> vec = {1, 2, 3, 4, 5};
- 动态大小:
vector
可以根据需要自动扩展,允许动态添加或删除元素。 - 常用操作:
push_back()
添加元素,pop_back()
删除元素,size()
返回当前元素个数,at(index)
访问指定元素。 - 访问:可以通过下标
vec[0]
或vec.at(0)
来访问元素。
示例:
std::vector<int> vec = {1, 2, 3};
vec.push_back(4); // 在末尾添加元素
std::cout << vec[0] << std::endl; // 输出 1
3. std::list
std::list
是 C++ 标准库中的一个双向链表,允许在两端插入和删除元素,但与 vector
相比,随机访问较慢。
定义:
#include <list>
// 定义一个空的 list
std::list<int> lst;
// 定义并初始化一个 list
std::list<int> lst = {1, 2, 3, 4, 5};
- 双向链表:
list
支持在任何位置插入和删除元素,但不支持像vector
那样的高效随机访问。 - 常用操作:
push_back()
添加元素,push_front()
在前面插入元素,pop_back()
删除末尾元素,pop_front()
删除开头元素。
示例:
std::list<int> lst = {1, 2, 3};
lst.push_back(4); // 在末尾添加元素
lst.push_front(0); // 在前面添加元素
for (int num : lst) {
std::cout << num << " "; // 输出 0 1 2 3 4
}
4. 二维数组 (2D Array)
二维数组是由多个一维数组组成的数组,也称为矩阵。可以通过指定两层下标来访问二维数组中的元素。
定义:
// 定义一个 3x3 的二维数组
int arr[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 定义并初始化一个 2x3 的二维数组
int arr[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
- 访问元素:可以使用
arr[0][0]
来访问二维数组的元素,第一层下标对应行,第二层下标对应列。
示例:
int arr[2][3] = {{1, 2, 3}, {4, 5, 6}};
std::cout << arr[1][2] << std::endl; // 输出 6
5. 二维 vector
在 C++ 中,vector
也可以用来创建二维结构,即通过创建一个包含 vector
的 vector
。
定义:
#include <vector>
// 定义一个 2x3 的二维 vector
std::vector<std::vector<int>> vec = {
{1, 2, 3},
{4, 5, 6}
};
- 访问元素:可以使用
vec[i][j]
来访问二维vector
中的元素。
示例:
std::vector<std::vector<int>> vec = {{1, 2, 3}, {4, 5, 6}};
std::cout << vec[0][2] << std::endl; // 输出 3
6. 动态二维数组
如果你不知道二维数组的大小并且希望动态分配空间,可以使用 vector
动态创建二维数组。例如,可以创建一个大小为 m x n
的二维 vector
:
定义:
#include <vector>
// 定义一个 m x n 的二维 vector,元素初始值为 0
int m = 3, n = 4;
std::vector<std::vector<int>> vec(m, std::vector<int>(n, 0));
- 这里创建了一个 3 行 4 列的二维
vector
,并将所有元素初始化为0
。
示例:
std::vector<std::vector<int>> vec(3, std::vector<int>(4, 0)); // 3x4 的二维 vector
vec[1][2] = 5; // 设置元素
std::cout << vec[1][2] << std::endl; // 输出 5
总结
- 数组 (Array) 是静态的,大小固定,元素类型相同,存储在连续内存中。
vector
是动态数组,可以动态增加和删除元素,支持高效的随机访问。std::list
是双向链表,支持高效的插入和删除操作,但不支持高效的随机访问。- 二维数组 是多个一维数组的组合,大小固定,访问方式是通过两个索引。
- 二维
vector
是由vector
组成的vector
,允许动态调整大小,适用于不确定大小的矩阵。
通过这些数据结构,可以根据需求选择最合适的方式来存储和操作数据。
2.字符串使用双引号和单引号有什么区别
在 C++ 中,双引号("
)和单引号('
)有不同的用途和意义。下面是它们的主要区别:
1. 双引号 "
-
表示字符串字面量:双引号用于定义字符串常量(string literals),即由多个字符组成的字符串。
- 字符串类型:双引号中的内容是一个字符串,类型为
std::string
或char[]
(字符数组)。 - 自动包含结束符:字符串的末尾会自动添加一个空字符(
\0
),用于标志字符串的结束。
- 字符串类型:双引号中的内容是一个字符串,类型为
示例:
std::string str = "Hello, World!";
这里的 "Hello, World!"
是一个字符串字面量,它是 std::string
类型。
const char* str = "Hello, World!";
这里的 "Hello, World!"
是一个 const char*
类型的字符串。
2. 单引号 '
-
表示字符字面量:单引号用于定义单个字符字面量,即只有一个字符的数据。
- 字符类型:单引号中的内容是一个字符,类型为
char
。 - 不能包含多个字符:单引号只允许包含一个字符。如果包含多个字符,编译器会报错。
- 字符类型:单引号中的内容是一个字符,类型为
示例:
char c = 'H';
- 这里的
'H'
是一个字符字面量,它是char
类型。
3. 区别总结
区别 | 双引号 " " | 单引号 ' ' |
---|---|---|
表示的内容 | 字符串(多个字符) | 单个字符 |
类型 | std::string 或 char[] | char |
结束符 | 自动包含空字符(\0 ) | 没有结束符 |
多个字符 | 允许 | 不允许,只有一个字符 |
4. 实际应用示例
双引号:
std::string str = "Hello";
这里的 str
是一个字符串变量,内容为 "Hello"
。
单引号:
char ch = 'H';
- 这里的
ch
是一个字符变量,内容为'H'
。
不允许多字符的例子:
char invalid = 'Hello'; // 错误!不能在单引号中放置多个字符
5. 总结
- 双引号:用于表示字符串字面量,
std::string
类型,支持多个字符。 - 单引号:用于表示单个字符字面量,
char
类型,只能包含一个字符。
希望这能帮助你理解双引号和单引号的区别!
3.string str = s.substr(startIndex, i-startIndex+1)是什么意思
1. substr(pos, len)
的含义
substr
是 std::string
类的一个成员函数,格式如下:
string substr(size_t pos, size_t len);
- 参数
pos
:从pos
(索引)位置开始截取子串。 - 参数
len
:要截取的长度。 - 返回值:返回截取后的子串。
2. s.substr(startIndex, i - startIndex + 1)
解析
startIndex
是起始索引(pos
)。i - startIndex + 1
计算的是子串的长度(len
)。
由于
i - startIndex
计算的是从startIndex
到i
之间的字符个数,但substr
的len
是基于长度而不是索引,因此要加1
,确保包含i
位置的字符。
3. 例子
假设 s = "abcdef"
,并且:
int startIndex = 1; // 从索引 1 开始
int i = 3; // 目标索引是 3
string str = s.substr(startIndex, i - startIndex + 1);
s.substr(1, 3 - 1 + 1) == s.substr(1, 3)
s
的索引从0
开始:
s = "abcdef"
012345
substr(1, 3)
提取的是 s[1]
开始,长度为 3
的子串,即 "bcd"
。
4."abcdef"获得子串a可以写成s.substr(startIndex, i - startIndex + 1)吗,难道不应该是s.substr(0, 0)
s.substr(0, 0)
是如何工作的?
s.substr(0, 0)
会从字符串s
的第0
个字符开始,截取长度为0
的子串。- 结果是一个空字符串
""
,并不是"a"
。
但要提取 "a"
,应该用 s.substr(0, 1)
:
string s = "abcdef";
string sub = s.substr(0, 1); // 获取 "a"
这才会得到 "a"
,因为 s.substr(0, 1)
从索引 0
开始,截取长度为 1
的子串。
为什么你会看到 s.substr(startIndex, i - startIndex + 1)
?
这种形式通常用于动态确定起始位置和长度。例如:
startIndex
是子串的起始位置。i - startIndex + 1
是根据目标索引i
动态计算出来的长度。
举个例子:
假设字符串 s = "abcdef"
,你想从索引 0
到索引 0
获取子串 "a"
,可以这样写:
int startIndex = 0;
int i = 0;
string sub = s.substr(startIndex, i - startIndex + 1); // 从索引 0 开始,长度为 1
这个写法的 i - startIndex + 1
计算结果为 1
,表示子串的长度为 1
,因此你会得到 "a"
。
总结:
s.substr(0, 0)
提取的是一个空字符串""
,并不包括字符"a"
。s.substr(0, 1)
提取的是从索引0
开始的一个字符"a"
。s.substr(startIndex, i - startIndex + 1)
这种形式用于在动态计算起始位置和长度时非常有用,它可以灵活地处理各种索引和子串长度的情况。