哈希表?我直接刷爆

csdn

哈希表

数据结构简介…


高频面试题

242.有效的字母异位词

🚀题目链接:LeetCode242.有效的字母异位词

题目:
给定两个字符串 st ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:st 中每个字符出现的次数都相同,则称 st 互为字母异位词。

示例 1:

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

示例 2:

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

🍬C++ AC代码:

class Solution {
public:
    bool isAnagram(string s, string t) {
        if (s.size() != t.size())
            return false;
        map<char, int> char_map;
        for (int i = 0; i < s.size(); i++)
            char_map[s[i]]++;
        for (int i = 0; i < t.size(); i++) {
            if (char_map[t[i]] == 0)
                return false;
            char_map[t[i]]--;
        }
        return true;
    }
};

Tips:

  • mapkey为单词中的字母,value为字母出现的次数。

  • ⭐第一次遍历统计字符串s中每个字母出现的次数,第二次遍历字符串t,每出现一个字母就在原来的统计量上 − 1 -1 1,同时C++的map有一个特点,当map中访问的key不存在时会自动生成一个键值对,默认值为0,因此每次可以先判断字母的统计量是否为0再减一来检查异位词。

  • ⭐这种方法排除了第二个字符串的某个字母在第一个字符串中没有出现的可能,同时也排除了第二个字符的某个字母数量比第一字符串多的可能。

  • ⭐当然还有一种情况,就是第一个字符串的某个字母数量比第二个字符串多的情况,但如果两个字符串长度相同,某个字符数量多,必然意味着其他字符的数量第一个字符串会比第二个字符串少,这种情况在上面已经考虑进去了,只需要在最开始判断一下两个字符串长度,如果长度不相等直接返回false

  • ⭐本题最多有26个不同的字母,我们也可以直接使用一个数组来充当map,数组下标为字母的ASCII码值,通常把用数组冲当map的方式叫做散列,是一种很常用的技巧:

    class Solution {
    public:
    	bool isAnagram(string s, string t) {
        	int map[26] = {0};
        	for (int i = 0; i < s.size(); i++)
            	map[s[i] - 'a']++;
        	for (int i = 0; i < t.size(); i++)
            	map[t[i] - 'a']--;
        	for (int i = 0; i < 26; i++)
            	if (map[i] != 0)
                	return false;
        	return true;
    	}
    };
    
    • s[i] - 'a'两个字母直接相减,实际上是ASCII码值相减,计算出字母相较于a的偏移量,将码值映射到0~26的范围中。

Java AC代码:

class Solution {
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length())
            return false;
        Map<Character, Integer> charMap = new HashMap<>();
        for (int i = 0; i < s.length(); i++)
            charMap.put(s.charAt(i), charMap.getOrDefault(s.charAt(i), 0) + 1);
        for (int i =0; i < t.length(); i++) {
            if (charMap.getOrDefault(t.charAt(i), 0) == 0)
                return false;
            charMap.replace(t.charAt(i), charMap.get(t.charAt(i)) - 1);
        }
        return true;
    }
}

Tips:

  • ⭐Java的map使用起来没有C++那么方便,而且用在本题中算法的效率也不是很高,建议直接使用一个数组来代替map

    class Solution {
    	public boolean isAnagram(String s, String t) {
        	int[] map = new int[26];
        		for (int i = 0; i < s.length(); i++)
            		map[s.charAt(i) - 'a']++;
        		for (int i = 0; i < t.length(); i++)
            		map[t.charAt(i) - 'a']--;
        		for (int i = 0; i < 26; i++)
            		if (map[i] != 0)
                		return false;
        		return true;
    	}
    }
    

🍦Python AC代码:

class Solution(object):
    def isAnagram(self, s, t):
        dic1, dic2 = {}, {}
        for ch in s:
            dic1[ch] = dic1.get(ch, 0) + 1
        for ch in t:
            dic2[ch] = dic2.get(ch, 0) + 1
        return dic1 == dic2

Tips:

  • ⭐Python中使用{}表示一个字典(dict),相当于map,并且可以直接用==判断两个字典是否相同。

2.两数之和

🚀题目链接:LeetCode1.两数之和

题目:
给定一个整数数组 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]

示例 3:

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

🍬C++ AC代码:

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

Tips:

  • map.find()用于查找某个key是否在map中,如果存在则返回对应位置的迭代器,如果不存在,返回迭代器map.end()
  • ⭐迭代器可以简单理解为用来遍历集合的工具,迭代器的迭代的对象是集合里面存放对象的引用的拷贝。
  • ⭐这里用nums[i]作为key,下标i作为value,是因为map通过计算哈希(Hash)值来查找key,时间复杂度 O ( 1 ) O(1) O(1),而查找value的复杂度就不是常数级别了。

Java AC代码:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> hashTable = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (hashTable.get(target - nums[i]) != null)
                return new int[]{hashTable.get(target - nums[i]), i};
            hashTable.put(nums[i], i);
        }
        return null;
    }
}

Tips:

  • ⭐Java中的map.get(key)方法用来返回对应的value,如果key不存在,则返回null

🍦Python AC代码:

class Solution(object):
    def twoSum(self, nums, target):
        dic = {}
        for i in range(len(nums)):
            if dic.get(target - nums[i]) is not None:
                return [dic[target - nums[i]], i];
            dic[nums[i]] = i;
        return None

Tips:

  • ⭐Python中dict.get(key)方法用于返回字典中key对应的value,如果key不存在,则返回None

3.三数之和

🚀题目链接:LeetCode15.三数之和

题目:
给你一个整数数组 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

示例 3:

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

🍬C++ AC代码:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int> > res;
        set<vector<int> > temp_res;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); i++) {
            if (i != 0 && nums[i] == nums[i - 1])
                continue;
            unordered_set<int> hash_set;
            for (int j = i + 1; j < nums.size(); j++) {
                if (hash_set.find(nums[j]) == hash_set.end())
                    hash_set.insert(-nums[i] - nums[j]);
                else
                    temp_res.insert({nums[i], -nums[i] - nums[j], nums[j]});
            }
        }
        res.assign(temp_res.begin(), temp_res.end());
        return res;
    }
};

Tips:

  • ⭐“两数之和”利用map可以让时间复杂度从 O ( n 2 ) O(n^2) O(n2)减小到 O ( n ) O(n) O(n),类似的,“三数之和”我们可以枚举其中两个值,第三个值用map进行优化。
  • ⭐与"两数之和"不同的是本题我们不需要返回下标,因此我们可以使用set来代替mapset的底层也是借助map来实现的,不过它只能存key,不能存value,存入的值会自动去重。
  • ⭐为了避免找到重复的三元组,在一开始先对nums进行了一个排序,并且将满足条件的三元组先存入set,借助三元组有序这一特点取重,最后再将set转换成vector返回。
  • res.assign(temp_res.begin(), temp_res.end())set转换成vector

Java AC代码:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        Set<ArrayList<Integer>> res = new HashSet<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length; i++) {
            if (i != 0 && nums[i] == nums[i - 1])
                continue;
            Set<Integer> set = new HashSet<>();
            for (int j = i + 1; j < nums.length; j++) {
                if (!set.contains(nums[j]))
                    set.add(-nums[i] - nums[j]);
                else {
                    ArrayList<Integer> tempList = new ArrayList<>();
                    tempList.add(nums[i]);
                    tempList.add(-nums[i] - nums[j]);
                    tempList.add(nums[j]);
                    res.add(tempList);
                }
            }
        }
        return new ArrayList<List<Integer>>(res);
    }
}

Tips:

  • ⭐与C++的思路相同,Java中setlist只需要在list构造方法中传入setnew ArrayList<List<Integer>>(res)

🍦Python AC代码:

class Solution(object):
    def threeSum(self, nums):
        nums.sort()
        res = set()
        for i, v in enumerate(nums[:-2]):
            if i >= 1 and v == nums[i - 1]:
                continue
            dic = set()
            for x in nums[i+1:]:
                if x not in dic:
                    dic.add(-v-x)
                else:
                    res.add((v, -v-x, x))
        return map(list, res)

Tips:

  • for i, v in enumerate(nums[:-2])表示同时遍历下标与数组值,[:-2]表示遍历到数组的倒数第二个位置。
  • for x in nums[i+1:]表示从数组的第i + 1个值开始遍历。
  • ⭐Python中用map(list, res)set类型的res转换成list类型。

┊我们碰巧成为自己,但我们可以不止于此。┊
- 埃莱娜·费兰特《偶然的创造》 ​​​-

footer

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值