454:四数相加II
把四个数组分为两个元组,先计算前两个中的X=a+b的值,将其存到哈希map中,并用umap[X]++计算X出现的次数。然后遍历后两个数组计算Y=0-(c+d)的值,(由于a+b+c+d=0),如果找到的话记录值并依次加到count,最后返回count。
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int,int> umap;
for(int i=0;i<nums1.size();i++){
for(int j=0;j<nums2.size();j++){
int X=nums1[i]+nums2[j];
umap[X]++;
}
}
int count =0;
for(int i=0;i<nums3.size();i++){
for(int j=0;j<nums4.size();j++){
int Y=0-(nums3[i]+nums4[j]);
if (umap.find(Y) != umap.end()) {
count+=umap[Y];
}
}
}
return count;
}
383:赎金信
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。
思路一:暴力法
在字符串magazines里面寻找是否有ransom中的字符,有则去除ransom中的该字符,遍历结束后检查ransom是否被清空,若清空则返回true,否则返回false。
bool canConstruct(string ransomNote, string magazine) {
for(int i=0;i<magazine.size();i++){
for(int j=0;j<ransomNote.size();j++){
if(ransomNote[j]==magazine[i]){
ransomNote.erase(ransomNote.begin()+j);
break;
}
}
}
if(ransomNote.size()==0){
return true;
}
return false;
}
思路二:哈希表法
用数组来存储比map更节省内存。通过recode数据记录 magazine里各个字符出现次数,遍历ransomNote,在record里对应的字符个数做–操作,如果数组中存在负数即小于零,说明ransomNote字符串总存在magazine中没有的字符,返回false,否则返回true。
bool canConstruct(string ransomNote, string magazine) {
int record[26] = {0};
if (ransomNote.size() > magazine.size()) {
return false;
}
for (int i = 0; i < magazine.length(); i++) {
record[magazine[i]-'a'] ++;
}
for (int j = 0; j < ransomNote.length(); j++) {
record[ransomNote[j]-'a']--;
if(record[ransomNote[j]-'a'] < 0) {
return false;
}
}
return true;
}
15:三数之和
vector<vector<int>> threeSum(vector<int>& nums)
{
int size = nums.size();
if (size < 3) return {}; // 特判
vector<vector<int> >res; // 保存结果(所有不重复的三元组)
std::sort(nums.begin(), nums.end());// 排序(默认递增)
for (int i = 0; i < size; i++) // 固定第一个数,转化为求两数之和
{
if (nums[i] > 0) return res; // 第一个数大于 0,后面都是递增正数,不可能相加为零了
// 去重:如果此数已经选取过,跳过
if (i > 0 && nums[i] == nums[i-1]) continue;
// 双指针在nums[i]后面的区间中寻找和为0-nums[i]的另外两个数
int left = i + 1;
int right = size - 1;
while (left < right)
{
if (nums[left] + nums[right] > -nums[i])
right--; // 两数之和太大,右指针左移
else if (nums[left] + nums[right] < -nums[i])
left++; // 两数之和太小,左指针右移
else
{
// 找到一个和为零的三元组,添加到结果中,左右指针内缩,继续寻找
res.push_back(vector<int>{nums[i], nums[left], nums[right]});
left++;
right--;
// 去重:第二个数和第三个数也不重复选取
// 例如:[-4,1,1,1,2,3,3,3], i=0, left=1, right=5
while (left < right && nums[left] == nums[left-1]) left++;
while (left < right && nums[right] == nums[right+1]) right--;
}
}
}
return res;
}
18:四数之和
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int size = nums.size();
if (size < 3) return {}; // 特判
vector<vector<int> >res; // 保存结果(所有不重复的三元组)
sort(nums.begin(), nums.end());// 排序(默认递增)
for(int k=0;k<size;k++){
// 剪枝处理
if (nums[k] > target && nums[k] >= 0) {
break; // 这里使用break,统一通过最后的return返回
}
// 对nums[k]去重
if (k > 0 && nums[k] == nums[k - 1]) {
continue;
}
for (int i = k+1; i < size; i++) // 固定第一个数,转化为求两数之和
{
//剪枝
if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {
break;
}
// 去重:如果此数已经选取过,跳过
if (i > k+1 && nums[i] == nums[i-1]) continue;
// 双指针在nums[i]后面的区间中寻找和为0-nums[i]的另外两个数
int left = i + 1;
int right = size - 1;
while (left < right)
{
if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target){
right--; // 两数之和太大,右指针左移
}
else if((long) nums[k] + nums[i] + nums[left] + nums[right] < target) {
left++; // 两数之和太小,左指针右移
}
else
{
// 找到一个和为零的三元组,添加到结果中,左右指针内缩,继续寻找
res.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
left++;
right--;
// 去重:第二个数和第三个数也不重复选取
// 例如:[-4,1,1,1,2,3,3,3], i=0, left=1, right=5
while (left < right && nums[left] == nums[left-1]) left++;
while (left < right && nums[right] == nums[right+1]) right--;
}
}
}
}
return res;
}