1.两数之和
这个题应该算是几数之和里面最简单的问题了,就直接用unordered_map就行。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int>temp(2,-1);
unordered_map<int, int> mymap;
for(int i = 0; i < nums.size(); ++i){
int numberToFind = target - nums[i];
if(mymap.count(numberToFind) > 0){
temp[0] = i;
temp[1] = mymap[numberToFind];
break;
}
mymap[nums[i]] = i;
}
return temp;
}
};
2.三数之和
这个题用哈希表也能做,不过很麻烦,因为答案中不能包含重复的三元组,用哈希表之后去重就很恼火了,所以用三指针,不过要先排序,具体思路看之后的代码,像这种题吧时间复杂度就很难基本不可能降到O(n),所以不要浪费时间去想这种算法。
/**
* 解题思路:使用双指针法,或者说叫三指针法,这个题第一印象肯定是用哈希表,但是用哈希表太麻烦了
* 使用三指针,指针i指向现在的a元素,left和right负责移动遍历a对应的可能性,为了让时间控制在O(n)
* 我们需要先排序,然后再利用双指针,left和right分别开始指向i+1的位置和末尾位置,如果三数之和大了
* 则移动right,小了移动left,直至三数之和等于0或者leftright相遇。
*/
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size(), i = 0;
vector<vector<int>> ans;
while ( i + 2 < n) {
int left = i + 1;
int right = n - 1;
if (i > 0 && nums[i] == nums[i - 1]) {
i++;
continue;
}
while (left < right) {
if (nums[i] + nums[left] + nums[right] == 0) {
ans.push_back({nums[i], nums[left], nums[right]});
left++;
right--;
while (left < right && nums[left] == nums[left - 1]) left++;
while (left < right && nums[right] == nums[right + 1]) right--;
}
else if (nums[i] + nums[left] + nums[right] > 0)
right--;
else
left++;
}
i++;
}
return ans;
}
};
3.四数之和
四数之和和前面的三数之和也差不多,又多用了一个指针,去重也多了一个,反正边界条件自己要想清楚,当然时间复杂度也多了n,其实几数之和都可以这样做,其实双指针最大的作用就是降低一个n的时间复杂度(不过有时候可能要先排序)。
/**
* 解题思路:这道题用四指针法吧,先用first和last两个指针指向外围,然后用left和right两个指针指向里面循环查找
* 符合条件的元素。当然用指针法一般还是要先考虑排序,这里要排序,然后是考虑如何完整的遍历数组,这里采用的方法是把
* first和last指针指向分为三种情况,一种是对称位置,其余两种分别是first和last不对称的前进了一步,当然也要去重,
* 对四个元素都要考虑去重,具体看代码吧。
*/
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int n = nums.size();
int first = 0, last = n - 1;
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
while (first + 3 < n) {
if (first + 3 > last) {
first++;
last = n - 1;
}
int left = first + 1, right = last - 1;
if (first > 0 && nums[first] == nums[first - 1]) {
first++;
continue;
}
if (last < n - 1 && nums[last] == nums[last + 1]) {
last--;
continue;
}
while (left < right) {
if ((long)nums[first] + nums[last] + nums[left] + nums[right] > target) {
right--;
}
else if ((long)nums[first] + nums[last] + nums[left] + nums[right] < target) {
left++;
}
else {
ans.push_back({nums[first], nums[left], nums[right], nums[last]});
left++;
right--;
while (left < right && nums[left] == nums[left - 1]) left++;
while (left < right && nums[right] == nums[right + 1]) right--;
}
}
last--;
}
return ans;
}
};
4.四数相加Ⅱ
这个题倒又回到哈希表身上了,反正想到了就行。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> Sum12;
for (auto i : nums1)
for (auto j : nums2)
Sum12[i + j]++;
int ans = 0;
for (auto i : nums3) {
for (auto j : nums4) {
if (Sum12.count(-i-j)); {
ans += Sum12[-i-j];
}
}
}
return ans;
}
};
总结
几数相加这个问题要分情况,如果只是两数相加或只是求相加满足条件的元组数可以用哈希表,如果要返回的是一个存储相应值的元组,因为存在去重的原因,所以用双指针比较好。