1. 完成 15. 三数之和
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {sort(nums.begin(), nums.end());// 待返回的三元组vector<vector<int>> triples;for(int i = 0; i < nums.size(); i++){// 检测重复的 nums[i]if(i > 0 && nums[i] == nums[i-1]) continue;int l = i + 1;int r = nums.size() - 1;while(l < r) {// 检测重复的 nums[l] 并防止越界while(l > i + 1 && l < nums.size() && nums[l] == nums[l-1]) l++;// 检测重复的 nums[r] 并防止越界while(r < nums.size() - 1 && r > i && nums[r] == nums[r+1]) r--;// 防止 l, r 错位if(l >= r) break;// 均不重复再按照两数之和的思路// 等同于判断 nums[l] + nums[r] > -nums[i]if(nums[i] + nums[l] + nums[r] > 0) r--;// 等同于判断 nums[l] + nums[r] < -nums[i]else if(nums[i] + nums[l] + nums[r] < 0) l++;// nums[l] + nums[r] == nums[i], 三元组符合,添加入结果else {triples.push_back({nums[i], nums[l], nums[r]});l++; r--;}}}return triples;}
};
2. 八股部分
-
模板特化(Template Specialization)和偏特化(Partial Template Specialization)的概念
- 模板特化
- 定义:模板特化是指为特定的模板参数类型提供一个定制化的模板实现。当使用模板时,编译器通常会根据提供的模板参数生成对应的代码。但对于某些特殊的参数类型,通用的模板实现可能效率低下或者不符合要求,这时就可以通过模板特化来提供一个专门针对这些特殊类型的实现。例如,对于一个通用的
compare
模板函数,用于比较两个值的大小,它可能对大多数类型(如int
、double
等)都能正常工作,但对于像char*
(C 风格字符串)这样的类型,通用模板的比较方式(可能是比较指针的值)就不符合预期(我们期望比较字符串的内容),这时就需要对char*
类型进行模板特化。
- 定义:模板特化是指为特定的模板参数类型提供一个定制化的模板实现。当使用模板时,编译器通常会根据提供的模板参数生成对应的代码。但对于某些特殊的参数类型,通用的模板实现可能效率低下或者不符合要求,这时就可以通过模板特化来提供一个专门针对这些特殊类型的实现。例如,对于一个通用的
- 偏特化
- 定义:偏特化是模板特化的一种形式,它不是针对一个完全特定的类型进行特化,而是针对一组满足特定条件的类型进行特化。例如,对于一个模板类,我们可以对指针类型进行偏特化,而不管这个指针具体指向什么类型。或者对于模板类的多个参数,我们可以对其中部分参数进行特化,而不是全部参数。偏特化提供了一种更灵活的方式来处理模板参数,使得可以针对一些有共同特征的类型组提供专门的实现。
- 模板特化
-
如何进行模板特化和偏特化
- 模板特化的实现步骤
- 函数模板特化
- 步骤一:定义通用模板函数:首先,定义一个通用的模板函数,例如:
- 函数模板特化
- 模板特化的实现步骤
template<typename T>
bool compare(T a, T b) {return a > b;
}
- 步骤二:进行特化:对于需要特化的类型,比如
char*
,定义一个特化版本的函数模板。特化版本的函数模板声明格式为template<> bool compare<char*>(char* a, char* b)
,注意这里没有模板参数<typename T>
,而是直接指定了特化的类型char*
。完整的特化函数实现如下:
template<>
bool compare<char*>(char* a, char* b) {return strcmp(a, b) > 0;
}
- 类模板特化
- 步骤一:定义通用模板类:例如,定义一个简单的
Array
模板类来存储数组元素:
- 步骤一:定义通用模板类:例如,定义一个简单的
template<typename T, int N>
class Array {
public:T data[N];T& operator[](int i) {return data[i];}
};
- 步骤二:进行特化:假设我们要对
int
类型且大小为 5 的Array
进行特化,特化类模板的声明格式为template<> class Array<int, 5>
。完整的特化类实现如下:
template<>
class Array<int, 5> {
public:int data[5];int& operator[](int i) {return data[i];}void specialFunction() {// 可以添加一些仅针对这个特化版本的函数std::cout << "This is a special function for Array<int, 5>" << std::endl;}
};
- 模板偏特化的实现步骤
- 类模板偏特化(以指针类型为例)
- 步骤一:定义通用模板类:同上面的类模板定义,例如:
- 类模板偏特化(以指针类型为例)
template<typename T, int N>
class Array {
public:T data[N];T& operator[](int i) {return data[i];}
};
- 步骤二:进行偏特化:对指针类型进行偏特化,偏特化的声明格式为
template<typename T, int N> class Array<T*, N>
。在这个偏特化版本中,我们可以针对指针类型的特点进行不同的实现,例如:
template<typename T, int N>
class Array<T*, N> {
public:T* data[N];T*& operator[](int i) {return data[i];}
};
- 这里可以看到,对于指针类型的偏特化,
data
成员变成了T*
类型的数组,而operator[]
函数的返回类型也相应地变为T*&
,以适应指针类型的操作。这种偏特化可以方便地处理所有指针类型的情况,而不管指针具体指向什么类型。