代码随想录刷题顺序 哈希表

目录

242. 有效的字母异位词

349. 两个数组的交集

202. 快乐数

1. 两数之和

454. 四数相加 II

383. 赎金信

15. 三数之和

18. 四数之和


给定两个字符串 st ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 st 中每个字符出现的次数都相同,则称 st 互为字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

set集合

set好慢。。。

class Solution {
public:
    bool isAnagram(string s, string t) {
        multiset<int> ss;
        multiset<int> tt;
        int size_s = s.size();
        int size_t = t.size();

        for (int i = 0; i < size_s; i++)
        {
            ss.insert(s[i]);      
        }
        for (int i = 0; i < size_t; i++)
        {
            tt.insert(t[i]);      
        }

        for (int i = 'a'; i <= 'z'; i++)
        {
            if (ss.count(i) != tt.count(i))
            {
                return false;
            }
        }
        return true;    
    }   
};

数组

比set快多了

class Solution {
public:
    bool isAnagram(string s, string t) {
        int ss[26] = {0};
        int tt[26] = {0};
        
        for (int i = 0; i < s.size(); i++)
        {
            ss[s[i] - 'a']++;
        }
        for (int i = 0; i < t.size(); i++)
        {
            tt[t[i] - 'a']++;
        }

        for (int i = 0; i < 26; i++)
        {
            if (ss[i] != tt[i])
            {
                return false;
            }
        }
        return true;
    }
};

349. 两个数组的交集

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

用set,因为set可以去重

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> t;
        vector<int> res;
        for (int i = 0; i < nums1.size(); i++)
        {
            t.insert(nums1[i]);
        }

        for (int i = 0; i < nums2.size(); i++)
        {
            if (t.count(nums2[i]) != 0) 
            {
                res.push_back(nums2[i]);
                t.erase(nums2[i]); //删除当前数,避免答案重复
            }
        }
        return res;
    }
};

202. 快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n快乐数 就返回 true ;不是,则返回 false

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:

输入:n = 2
输出:false

若n不是快乐数时会陷入无限的循环,即会重复计算结果。所以本题的关键在于判断结果是否有重复的存在。

class Solution {
public:
    int getSum(int n)
    {
        int res = 0;
        while (n)
        {
            int t = n % 10;
            res += t * t;
            n /= 10; 
        }
        return res;
    }

    bool isHappy(int n) {
        unordered_set<int> res;

        while (1)
        {
            int sum = getSum(n);
            if (sum == 1)
            {
                return true;
            }
            
            if (res.count(sum) != 0) //找到重复计算结果
            {
                return false;
            }else
            {
                res.insert(sum);
            }
            
            n = sum;
        }
    }
};

1. 两数之和
 

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

用map的key来记录数组元素,value来记录数组下标。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map <int, int> map;
        for (int i = 0; i < nums.size(); i++)
        {
            auto t = map.find(target - nums[i]); 
            if (t != map.end())
            {
                return {i, t->second};
            }
            map[nums[i]] = i; //插入
        }
        return {};
    }
};

454. 四数相加 II

给你四个整数数组 nums1nums2nums3nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

  • 0 <= i, j, k, l < n
  • nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

示例 1:

输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
输出:2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

和上一题差不多,可以先遍历前两个数组,将它们元素的和保存到map的key中,value记录不同和的个数。之后再遍历后两个数组的和。

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> map; //key存放1,2数组元素的和,value存放和出现的个数
        for (int i = 0; i < nums1.size(); i++)
        {
            for (int j = 0; j < nums2.size(); j++)
            {
                map[nums1[i] + nums2[j]]++;
            }
        }

        int cnt = 0;
        for (int i = 0; i < nums3.size(); i++)
        {
            for (int j = 0; j < nums4.size(); j++)
            {
                auto t = map.find(0 - (nums3[i] + nums4[j]));
                if (t != map.end())
                {
                    cnt += t->second;
                }
            }
        }
        return cnt;
    }
};

383. 赎金信

给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false

magazine 中的每个字符只能在 ransomNote 中使用一次。

示例 1:

输入:ransomNote = "a", magazine = "b"
输出:false

示例 2:

输入:ransomNote = "aa", magazine = "ab"
输出:false

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int res[26] = {0};
        for (int i = 0; i < magazine.size(); i++)
        {
            res[magazine[i] - 'a']++;
        }

        for (int i = 0; i < ransomNote.size(); i++)
        {
            int j = ransomNote[i] - 'a';
            if (res[j] != 0)
            {
                res[j]--;
            }else
            {
                return false;
            }
        }
        return true;
    }
};

15. 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

本题使用哈希表求解比较困难,所以采用双指针法来求解。

大题思路:

去重:

因为本题要求答案三元组中不可以有重复的元素,如{-1,-1,2}和{2,-1,-1},但可以有三元组组内的元素重复,如{0,0,0}。

在我们已经从小到大排好序的前提下,我们应该使用nums[i]与nums[i+1]比较是否相等,还是比较nums[i]与nums[i-1]是否相等?

若我们使用这个去重逻辑则当出现类似{-1,-1,2}这样的答案三元组时,此时i指向-1这个元素,因为i与该元素的下一个元素相比较,发现相等则会跳过这个三元组,i此时会指向2这个元素。这样的去重逻辑会将有重复元素的三元组全部去重,不符合题目要求。所以我们应当采用第二种去重逻辑。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int> > res; //二维数组存储结果
        sort(nums.begin(), nums.end());

        for (int i = 0; i < nums.size(); i++) //通过遍历a来确定left和right
        {
            if (nums[i] > 0) //因为数组此时是从小到大的,若当前的nums[i]比0还大,则和一定>0
            {
                return res;
            }

            if (i > 0 && nums[i] == nums[i - 1]) //对a进行去重
            {
                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
                {
                    res.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    //对left和right去重(和a那里不大一样)
                    while (left < right && nums[left] == nums[left + 1])
                    {
                        left++;
                    }
                    while (left < right && nums[right] == nums[right - 1])
                    {
                        right--;
                    }
                    left++;
                    right--;
                }
            }
        }
        return res;
    }
};





18. 四数之和

和上一题一样

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int> > res;
        sort(nums.begin(), nums.end());

        for (int i = 0; i < nums.size(); i++)
        {
            //这里与三数之和不大一样,因为此时的target可能为负数,所以如:target=-10时,而{-4,-3,-2,-1}不能因为-4>-10就跳过
            if (nums[i] > target && target >= 0)
            {
                break;
            }

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

            for(int j = i + 1; j < nums.size(); j++)
            {
                if (nums[j] > target - nums[i] && target >= 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 ((long) nums[i] + nums[j] + nums[left] + nums[right] > target)
                    {
                        right--;
                    }else if ((long) nums[i] + nums[j] + nums[left] + nums[right]  < target)
                    {
                        left++;
                    }else
                    {
                        res.push_back(vector<int>{nums[i], nums[j], 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 res;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值