您现在的位置是:首页 >其他 >代码随想录刷题第7天|哈希表 LeetCode454、LeetCode383、LeetCode15、LeetCode18网站首页其他

代码随想录刷题第7天|哈希表 LeetCode454、LeetCode383、LeetCode15、LeetCode18

星☆空 2023-06-14 16:00:03
简介代码随想录刷题第7天|哈希表 LeetCode454、LeetCode383、LeetCode15、LeetCode18

1、LeetCode454 四数相加

题目链接:454、四数相加

遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。

遍历大C和大D数组,如果 0-(c+d) 在map中出现过,count += map[ 0 - ( c + d ) ]。

这样计算复杂度为O(n^2)。

为什么用map而不用数组,是因为题目里元素的数值可能很大。

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int,int> map;
        for (int a : nums1)
        {
            for ( int b : nums2)
            {
                map[a+b]++;
            }
        }

        int count = 0;
        for (int c : nums3)
        {
            for (int d : nums4)
            {
                auto iter = map.find(0 - c - d);
                if (iter != map.end())
                {
                    count += map[0 - c - d];
                }
            }
        }
        return count;
    }
};

2、LeetCode383 赎金信

题目链接:383、赎金信

有两点要注意:

1.如果ransomNote.size > magazine.size,可以立即判断不成立;

2.一旦record[ransomNote[i] - 'a']-- 小于0, 可以立即判断不成立,不用等遍历结束后,再去寻找是否有小于0的元素。

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.size(); i++)
        {
            record[magazine[i] - 'a']++;
        }
        for (int i = 0; i < ransomNote.size(); i++)
        {
            record[ransomNote[i] - 'a']--;
            if (record[ransomNote[i] - 'a'] < 0)
            {
                return false;
            }
        }

        return true;
    }
};

3、LeetCode15 三数之和

题目链接:15、三数之和

如果用哈希法,不容易去重,采用双指针法更清晰。

如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left++;

如果 nums[i] + nums[left] + nums[right] > 0 说明 此时 三数之和大了,right--;

关键问题在于如何去重。

对于第一个元素,应当判断 nums[i] 与 nums[i-1] 是否相同,例如{-1, -1 ,2} 这组数据。

对于后两个元素,去重逻辑应该放在找到一个三元组之后,对b 和 c去重。

 去重复逻辑如果放在找到一个三元组之前,对于0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组。

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;
            }

            // 正确去重a方法
            if (i > 0 && nums[i] == nums[i-1])
            {
                continue;
            }

            int left = i + 1;
            int right = nums.size() - 1;

            while(right > left)
            {
                 // 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而 
                漏掉了 0,0,0 这种三元组
                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]});
                    // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
                    while (right > left && nums[left] == nums[left+1])
                    {
                        left++;
                    }
                    while (right > left && nums[right] == nums[right-1])
                    {
                        right--;
                    }
                    left++;
                    right--;
                }
            }

        }
        return result;
    }
};

4、LeetCode18 四数之和

题目链接:18、四数之和

一级剪枝: if ( nums[k] >target && nums[k] >= 0 )  break;

一级去重: if ( k > 0 && nums[k] == nums[k-1] ) continue;

二级剪枝: if ( nums[k] + nums[i] > target && nums[k] + nums[i] >= 0 ) break;

二级去重: if ( i > k + 1 && nums[i] == nums[i-1] ) continue;

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 || target >= 0) )
            {
                break;
            }

            if (k > 0 && nums[k] == nums[k-1])
            {
                continue;
            }

            for (int i = k + 1; i < nums.size(); i++)
            {
                if ( nums[k] + nums[i] > target && nums[k] + nums[i] >= 0)
                {
                    break;
                }

                if (i > k+1 && nums[i] == nums[i-1])
                {
                    continue;
                }

                int left = i + 1;
                int right = nums.size() - 1;
                while(right > left)
                {
                    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
                    {
                        result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
                        while (right > left && nums[right] == nums[right - 1]) right--;
                        while (right > left && nums[left] == nums[left + 1]) left++;

                        right--;
                        left++;
                    }
                }
            }
        }
        return result;
    }
};

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。