代码随想录算法训练营第七天|454.四数相加II,383. 赎金信 ,15. 三数之和,18. 四数之和

454. 四数相加

题目链接:383. 赎金信

题目思路:可以把四组数组两两相加,记录下前两组所有的{和:和的次数},存入字典中。然后将后两组每个数两两相加后,从字典中查询是否存在两数和的相反数,若有,count加一。

class Solution(object):
    def fourSumCount(self, nums1, nums2, nums3, nums4):
        first_two = dict()
        for num1 in nums1:
            for num2 in nums2:
                first_two[num1 + num2] = first_two.get(num1 + num2, 0) + 1

        count = 0
        for num3 in nums3:
            for num4 in nums4:
                to_find = -(num3 + num4)
                if to_find in first_two:
                    count += first_two.get(to_find) 
        return count

383. 赎金信

题目链接:383. 赎金信 - 力扣(LeetCode)

题目思路:与上次242. 有效的字母异位词 - 力扣(LeetCode)的思路一样。

class Solution(object):
    def canConstruct(self, ransomNote, magazine):
        record = [0]*26
        for i in magazine:
            record[ord(i)-ord('a')] += 1
        for i in ransomNote:
            if record[ord(i)-ord('a')] == 0:
                return False
            record[ord(i)-ord('a')] -= 1
        return True

看解析,也可以直接用count,一行出答案。

class Solution(object):
    def canConstruct(self, ransomNote, magazine):
        return all(ransomNote.count(c) <= magazine.count(c) for c in set(ransomNote))

尝试使用C++

上学时有一门课需要用到C++,都是现学现用,基础不好,要多练练。

注意:C++要用“;”,需要定义变量类

class Solution {
public:
    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.三数之和

题目链接:15. 三数之和 - 力扣(LeetCode)

题目大意:给定一个整数数组,返回所有和为0且不重复的三元组。

题目方法:双指针

去重思路

如果i和前一个的数相同,就跳过。因为对于前一个值来说,left和right所找的范围涵盖了所有它后面的那些数,这包含了当前的数所要找的另外left和right的范围,所以上一个数已经把当前的数可能找到的结果涵盖了。

left:如果当前和left的后一位相同,则再往前,不然,由于i是固定的,如果left还是一样的,那么三元组也固定了,造成重复。

right:如果当前right和前一位相同,就再往前。

代码实现

class Solution {
public:
    vector> threeSum(vector& nums) {
        vector> 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;} //i跳出while循环
                                                        // 加1
            int left = i + 1;
            int right = nums.size() - 1;
            while (left < right){
                int sum = nums[i] + nums[left] + nums[right];
                if ( sum < 0){
                    left++;
                }
                else if (sum > 0){
                    right--;
                }
                else{
      result.push_back(vector{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;
        }

    
};

18. 四数之和

题目链接:18. 四数之和 - 力扣(LeetCode)

题目大意:给定一个整数数组,返回所有和为target且不重复的四元组。

题目思路:在三数之和的基础上再套一层for循环。

  1. 套for循环的逻辑:三数之和是靠着left和right根据当前和与零的比较而滑动,对于四数之和也是一样,毕竟不能有条理地同时滑动三个数。在外面套一层的含义是对于每一个外层的k,都要进行之前三数之和的操作,想明白这点便可大胆地做。
  2. 去重操作:对于每个k,其它三个指针动态寻找,所找的范围是在k之后的所有数,因此和i一样,如果它当前的数值和前一位相同,就跳过一个。因为之前的搜寻范围覆盖了当前的搜寻范围,一封会找到和之前相同的数组。对于i,left和right,跳过的操作和三数之和相同。
  3. 剪枝操作:在三数之和中,只要最左边的数(i)大于target(0),就会停止搜索,但四数之和的比较对象是target,可以为负数。一个负数能大于target,但两个负数相加就有可能小于target。因此只有当最左边的数大于0,且大于target时,才能停止搜索。

代码实现

class Solution {
public:
    vector> fourSum(vector& nums, int target) {
        vector> result;
        sort(nums.begin(), nums.end());
        for (int k = 0; k < nums.size(); k++){
            if (nums[k] > 0 && nums[k] > target) {break;} 
            // 统一通过最后的return返回
            if (k > 0 && nums[k] == nums[k-1]){
                continue;
            }
            for (int i = k + 1; i < nums.size(); i++){
                if (nums[i] + nums[k] > 0 && nums[i] + nums[k] > target){
                    break;
                }
                if (i > k + 1 && nums[i] == nums[i-1]){
                    continue;}
                int left = i + 1;
                int right = nums.size() - 1;
                while (left < right){
                    int sum = (long)nums[k] + nums[i] +nums[left] + nums[right];
                    if (sum < target) left++;
                    else if (sum > target) right--;
                    else{
result.push_back(vector{nums[k], nums[i], nums[left], nums[right]});
                    while (left < right && nums[left] == nums[left + 1])left++;
                    while(left

与【四数相加】比较

  1. 【四数相加】是四个数组,不要求数组中的每一个数的index不一样,而【四数之和】的index不能重复,需要通过指针由外向里滑动,并且不同index但元素相同的数组也要去重,要考虑它前/后一个数与它相等时,需要往哪里移动。
  2. 【四数相加】不要求返回具体的数,只需要找出所有和为target的数组的次数,因此可以两两分组分开求值,运用哈希表方便查询。【四数之和】需要找到后返回数值,再设置指针的移动。

你可能感兴趣的:(代码随想录训练营,算法,哈希表,python,c++)