目录
一、数组与双指针
1.两数之和
暴力解法
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int n = nums.size();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) {
return {i, j};
}
}
}
return {};
}
};
哈希解法
无序快速查找
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map <int,int> hashtable; //建立无序哈希表
for (int i=0; i<nums.size();++i){
auto it = hashtable.find(target-nums[i]); //在哈希表内查值,是否有target-nums[i]的值
if (it != hashtable.end()){ //如果他没有在哈希表的尾部,则返回他的值
return {it->second,i}; //访问value it->first访问key
}
hashtable[nums[i]] = i; //加入值 hashtable[key] = value
}
return {};
}
};
2.有序数组合并
暴力解法 :直接合并两个数组进行排序
但这种方法没有用到排序的特征
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
for (int i=0; i<n; i++){
nums1[m+i] = nums2[i];
}
sort(nums1.begin(),nums1.end()); //从小到大
}
};
双指针
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int p1=0;
int p2=0;
int cur;
int nums3[m+n]; //创建一个m+n的空数组
while(p1<m || p2<n){
if (p1 == m){ //1、nums1用完了
cur = nums2[p2];
p2++;
}
else if (p2 == n){ //2、nums2用完了
cur = nums1[p1];
p1++;
}
else if (nums1[p1]<nums2[p2]){ //3、nums1的数小
cur = nums1[p1];
p1++;
}
else {
cur = nums2[p2]; //4、nums2的数小
p2++;
}
nums3[p1+p2-1] = cur; //p1+p2-1正好是每次依次增大的索引
for (int i=0;i<m+n;i++){
nums1[i] = nums3[i]; //将nums3的值赋予给nums1
}
}
}
};
3.寻找两个正序数组的中位数
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
int nums3[m+n];
int p1=0;
int p2=0;
int cur;
while( p1<m || p2<n ){
if (p1==m){
cur = nums2[p2];
p2++;
}
else if (p2==n){
cur = nums1[p1];
p1++;
}
else if (nums1[p1]<nums2[p2]){
cur = nums1[p1];
p1++;
}
else {
cur = nums2[p2];
p2++;
}
nums3[p1+p2-1] = cur;
}
int c=m+n;
if (c%2 == 1){
return nums3[(c-1)/2];
}
else {
double d = (nums3[c/2-1] + nums3[c/2])/2.0;
//!!一定是除2.0结果才会转化为浮点数,卡了好长时间
return d;
}
}
};
4. 求三个数之和
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> ans; #动态容器用来返回数组
// 枚举 a
for (int first = 0; first < n; ++first) {
// 需要和上一次枚举的数不相同 去重
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < n; ++second) {
// 需要和上一次枚举的数不相同 去重
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue; //合理运用continue才能找全
}
// 需要保证 b 的指针在 c 的指针的左侧
while (second < third && nums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
ans.push_back({nums[first], nums[second], nums[third]});
}
}
}
return ans;
}
};
5. 颜色分类
单指针
两次循环遍历
class Solution {
public:
void sortColors(vector<int>& nums) {
int n=nums.size();
int ptr = 0;
for (int i=0; i<n;i++){
if (nums[i]==0){
swap(nums[i],nums[ptr]);
ptr++;
}
}
for (int i=0; i<n;i++){
if (nums[i]==1){
swap(nums[i],nums[ptr]);
ptr++;
}
}
}
};
双指针
一次循环遍历,需要注意用到while来避免,两个指针交换,只顾nums[n+1]而不管之前是否交换。
class Solution {
public:
void sortColors(vector<int>& nums) {
int n=nums.size();
int p1 = 0;
int p2 = n-1;
for (int i=0; i<n;i++){
while (i <= p2 && nums[i] == 2) {
swap(nums[i], nums[p2]);
--p2;
}
if (nums[i] == 0) {
swap(nums[i], nums[p1]);
++p1;
}
}
}
};
6、最小覆盖子串
思路
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char, int> hs, ht; //声明哈希表
for (auto& c : t) ht[c] ++ ; //建立ht的哈希表
string res;
int cnt = 0;
for (int i = 0, j = 0; i < s.size(); i ++ ) {
hs[s[i]] ++ ; //建立hs哈希表
if (hs[s[i]] <= ht[s[i]]) cnt ++ ;
while (hs[s[j]] > ht[s[j]]) hs[s[j ++ ]] -- ;
if (cnt == t.size()) {
if(res.empty() || i - j + 1 < res.size())
res = s.substr(j, i - j + 1);
}
}
return res;
}
};