454. 四数相加 II
拿到题目最初的思路就是四重循环暴力求解。从代码随想录的介绍了解了使用哈希表的解法。
先遍历两个数组,将其中任意两值相加存入哈希表中,再遍历剩余两个数组,将其中任意两值相加,在哈希表中查找当前两值之和的相反数的个数。将这些个数加起来即为所求结果。
时间复杂度:
O
(
n
2
)
O(n^{2})
O(n2)
空间复杂度:
O
(
n
2
)
O(n^{2})
O(n2)
// c++
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> hash;
int result = 0;
for(int a : nums1){
for(int b : nums2){
hash[a+b]++;
}
}
for(int c : nums3){
for(int d : nums4){
// if(hash.find(0-c-d)!=hash.end())
result += hash[0-c-d];
}
}
return result;
}
};
383. 赎金信
创建哈希表记录magazine中每个字符的个数,遍历ransomNote中的字符,每个字符对应哈希表的值减一,若哈希表的值出现负值则返回false。
写法一:
使用unordered_map做哈希表。
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
n
)
O(n)
O(n)
// c++
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char, int> hash;
for(int i=0; i<magazine.size(); i++) hash[magazine[i]]++;
for(int i=0; i<ransomNote.size(); i++){
hash[ransomNote[i]]--;
if(hash[ransomNote[i]]<0) return false;
}
return true;
}
};
写法二:
使用一维数组做哈希表。
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
// c++
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int hash[26] = {0};
for(int i=0; i<magazine.size(); i++) hash[magazine[i]-'a']++;
for(int i=0; i<ransomNote.size(); i++){
hash[ransomNote[i]-'a']--;
if(hash[ransomNote[i]-'a']<0) return false;
}
return true;
}
};
使用map的空间开销大于数组,因为map要维护红黑树或者哈希表。而且还要做哈希函数,也是费时的。
15. 三数之和
循环遍历的同时外加双指针法两侧向中间逼近寻找三值和为0的三元组。
时间复杂度:
O
(
n
2
)
O(n^{2})
O(n2)
空间复杂度:
O
(
1
)
O(1)
O(1)
// c++
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for(int i=0; i<nums.size(); i++){
if(nums[i]>0) return result;
if(i>0 && nums[i]==nums[i-1]) continue;
int left = i+1;
int right = nums.size()-1;
while(left < right){
if(nums[i] + nums[left] + nums[right] == 0){
result.emplace_back(vector<int>{nums[i], nums[left], nums[right]});
while(left < right && nums[left]==nums[left+1]) left++;
while(left < right && nums[right] == nums[right-1]) right--;
left++;
right--;
}else if(nums[i] + nums[left] + nums[right] > 0) right--;
else left++;
}
}
return result;
}
};
18. 四数之和
和上题三数之和有异曲同工之妙,外层多加一层循环既可。难点在于去重。
时间复杂度:
O
(
n
3
)
O(n^{3})
O(n3)
空间复杂度:
O
(
1
)
O(1)
O(1)
// c++
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for(int i=0; i<nums.size(); i++){
if(nums[i]>target && nums[i]>=0) break;
if(i>0 && nums[i]==nums[i-1]) continue;
for(int j=i+1; j<nums.size(); j++){
if(nums[i] + nums[j] > target && nums[i] + nums[j] >= 0) break;
if(j>i+1 && nums[j] == nums[j-1]) continue;
int left = j+1;
int right = nums.size()-1;
while(left < right){
if(nums[i] + nums[j] + nums[left] + nums[right] > target) right--;
else if(nums[i] + nums[j] + nums[left] + nums[right] < target) left++;
else{
result.emplace_back(vector<int>{nums[i], nums[j], nums[left], nums[right]});
while(left<right && nums[left]==nums[left+1]) left++;
while(left<right && nums[right]==nums[right-1]) right--;
left++;
right--;
}
}
}
}
return result;
}
};