Leetcode.454 四数相加Ⅱ:
454. 四数相加 II - 力扣(LeetCode)
对于本题,虽然使用四层循环嵌套可以解决,但是效率过慢,为,因此,可以将给定的四个数组,分成两组,即:为一组,为一组,由于题目的要求是找到满足的元组的数量,对于这个问题,可以抽象的看成,查找在中,是否有满足的元素。
因此,可以利用定义一个哈希表,通过两次循环嵌套,存放所有元素组合出现的次数。
再去利用两层循环在进行查找相应的元素。例如,在定义好的哈希表中,的元组出现了次,因此,需要在中进行逐次遍历,查找是否在哈希表中出现过,若出现过,则说明存在符合条件的元组,此时再定义一个变量,令即可。具体代码对应如下:
class Solution {
public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {unordered_map<int,int> umap;int count = 0;for(int i = 0; i < nums1.size(); i++){for(int j = 0; j < nums2.size(); j++){umap[nums1[i]+nums2[j]]++;}}for(int i = 0; i < nums3.size(); i++){for(int j = 0; j < nums4.size(); j++){if(umap.find(0-(nums3[i]+nums4[j])) != umap.end()){count += umap[0-(nums3[i]+nums4[j])];}}}return count;}
};
运行结果如下:
Leetcode.382 赎金信:
383. 赎金信 - 力扣(LeetCode)
本题与上篇文章代码随想录(day6)——哈希表-CSDN博客中的题目. - 力扣(LeetCode)相似。都是利用哈希表来统计一个字符串中各个字母出现的次数,再拿去另一个字符串中进行比对。不过对于本题还是需要注意一些细节:
由于题目中说明,给定的两个字符串全都由小写英文字母构成,因此,直接定义一个大小为的整型数组即可。
题目中提到了,需要判断能不能由中出现过的字符组成,并且,中出现次的字符在只能使用次,例如,为,为,由于中出现的次数为,中出现的次数为,因此判定。所以,在创建数组进行判断之前,首先判定一次两个字符串的长短关系,如果则直接判定为即可。
并且由题干中给出了的样例来看,可以得出一个结论:中出现的字符的种类可以中出现的字符的种类,中单个字符出现的次数必须中单个字符出现的次数
介于上面的原理,可以先遍历一次,统计其出现的字符的种类以及单个字符出现的次数即:,然后再去遍历,令如果任意位置出现了,则说明出现了中没有的字符或者出现某个字符的次数出现这个字符的次数,返回。对应代码如下:
class Solution {
public:bool canConstruct(string ransomNote, string magazine) {if(ransomNote.size() > magazine.size()){return false;}int hash[26] = {0};for(int i = 0; i < magazine.size(); i++){hash[magazine[i]-'a']++;}for(int j = 0; j < ransomNote.size(); j++){hash[ransomNote[j]-'a']--;if( hash[ransomNote[j]-'a'] < 0){return false;}}return true;}
};
运行结果如下:
从入门到入土——Leetcode.15 三数之和:
15. 三数之和 - 力扣(LeetCode)
对于三数之和这道题,相对于两数之和的难度有明显的上升,如果说两数之和作为梦开始的地方,那么三数之和可以说是梦结束的地方。这是因为本题相对于两数之和只需要控制两个变量进行判断变成了需要控制三个变量,并且,题目中要求了答案中不可以包含重复的三元组,例如就属于两个重复的三元组。
虽然文章的标题为哈希表,但是对于三数之和,以及后面的四数之和,使用双指针的方法能更加容易的解决问题。具体方法如下:
首先利用创建一个二维数组,用于接收合适的三元组。
例如对于题目中给定的数组,首先进行一次排序,即:
再排序完成后,由于题目要求需要找到三个数的和,因此,要么数组中的元素全为,要么数组中同时存在正数,负数,所以,如果数组的第一个数已经,则不可能存在三个数相加等于的情况,因此直接返回即可。
对于本题所使用的双指针法,大致思路如下:
首先利用循环对每一个元素都进行一次双指针的判定,例如对于数组中的第一个元素,令其作为三元组的第一个元素,其下一个元素用表示,数组的最后一个元素用表示。
如果出现了的情况,由于数组在开始进行了排序,只需要令即可。
如果出现了的情况,则令。
如果出现了,则说明找到和符合条件的三元组,随后将这个三元组利用进行保存。
题目的大致解题思路如上,但是,由于题目要求不能出现的重复的三元组,因此,需要对每个元素进行去重判定,具体操作如下:
首先是针对每次循环中,头个元素的去重判定:
首先需要明确,如果确定了三元组中的两个数重复,则三元组一定重复,所以,对于第一个数据而言,需要判定其前一个数是否与自己相等,例如:
如图所示,其前一个数据与自身相等,则一定会造成重复。在这里,或许读者会有一位,为什么要求判定与前一个元素是否相同,即而不是去判定。对于这个问题,上图可以给出解释,如果去后一个数相等,则对于下面的情况:
如果按照进行判定重复,则在返回的正确的三元组中,会丢失一组数据,即。因此,在判定是否重复时,需要按照进行判定。如果满足重复的条件,则直接利用判定下一个元素即可。
而对于其余的两个元素,即所代表的元素,则也需要进行去重操作,例如对于下面的操作:
例如,对于图中的三元组,在找到后由于后面的元素和前面的元素都造成了重复,因此,如果,则令,如果,则令。具体效果如下:
此时,相邻的元素不造成重复,因此在去重完成后,令,来寻找下一组满足条件的三元组。
具体代码如下:
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {//对数组整体排序sort(nums.begin(),nums.end());vector<vector<int>> result;for(int i = 0; i < nums.size();i++){//检测首个元素是否>0if(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){right--;}else if(nums[i]+nums[left]+nums[right] < 0){left++;}else{result.push_back(vector<int>{nums[i],nums[left],nums[right]});//对于双指针进行去重while(left < right && nums[right] == nums[right-1]){right--;}while(left < right && nums[left] == nums[left+1]){left++;}right--;left++;}}}return result;}
};
Leetcode.18 四数之和:
18. 四数之和 - 力扣(LeetCode)
对于本题,主题思路与三数之和大致相同。具体如下:
在三数之和中,如果第一个元素,则说明不存在三元组使得三元组中元素的和,但是需要注意,在本题中,是给定一个,可以。因此,在进行判断时,需要进行两次判断,即:&&,如果满足,则说明,在数组中不存在合适的四元组使得其中四个数之和等于,随后需要对这个元素进行去重,去重的方法相同,即。
随后,令,即:
将这两个数加和进行一次判断,即&&。随后,再对位置的数据进行去重操作。
此时,前面的两个数据可以看作一个整体,最后再使用三数之和中的双指针法,即:
最后进行类似于三数之和一样的操作。本处不再展开说明,只给出代码:
class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> result;sort(nums.begin(),nums.end());for(int k = 0; k < nums.size(); k++){if(nums[k] > target && nums[k] >= 0){break;}if(k > 0 && nums[k] == nums[k-1]){continue;}for(int i = k+1; i < nums.size(); i++){if(nums[i] + nums[k] > target && nums[i]+nums[k] >= 0){break;}if(i > k+1 && nums[i] == nums[i-1]){continue;}int left = i+1;int right = nums.size()-1;while(left < right){if((long)nums[i] + nums[k] +nums[left] +nums[right] > target){right--;}else if((long)nums[i] + nums[k] +nums[left] +nums[right] < target){left++;}else{result.push_back(vector<int>{nums[i],nums[k],nums[left],nums[right]});while(left < right && nums[right] == nums[right-1]){right--;}while(left < right && nums[left] == nums[left+1]){left++;}right--;left++;}}}}return result;}
};
运行结果如下: