常见哈希表相关题目

找往期文章包括但不限于本期文章中不懂的知识点:

个人主页:我要学编程(ಥ_ಥ)-CSDN博客

所属专栏: 优选算法专题

目录

1.两数之和

面试题01.02.判定是否互为字符重排

217.存在重复元素

219.存在重复元素II

49.字母异位词分组


哈希表我们在数据结构阶段也是重点学习了,并且也已经刷了一部分的题目了。下面还练习一部分题目即可。

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]

示例 3:

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

提示:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案

思路: 暴力解法是很容易想到的,直接双层for循环就可以解决。但是怎么优化呢?双层for循环暴力的原因是每次都是固定一个元素之后去查找该元素之后的所有的元素,这是暴力的查找,有没有什么办法可以达到时间复杂度为O(1)的查找呢?刚好哈希表满足,因此可以使用哈希表来进行优化。固定一个元素查找该元素之前的是否满足相加为target的值,这里的查找是在哈希表中查找,因此最终的时间复杂度就是O(N)。

代码实现:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] ret = new int[2];
        Map hash = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int t = target - nums[i]; // i 的位置已经确定得找到 j 的位置
            // 看看哈希表中是否存在j的值
            if (hash.get(t) != null) {
                ret[0] = i;
                ret[1] = hash.get(t);
                return ret;
            }
            hash.put(nums[i], i); // 将当前数值 与 下标存放到哈希表中
        }
        return ret;
    }
}

面试题01.02.判定是否互为字符重排

思路:

给定两个由小写字母组成的字符串 s1 和 s2,请编写一个程序,确定其中一个字符串的字符重新排列后,能否变成另一个字符串。

示例 1:

输入: s1 = "abc", s2 = "bca"
输出: true 

示例 2:

输入: s1 = "abc", s2 = "bad"
输出: false

说明:

  • 0 <= len(s1) <= 100
  • 0 <= len(s2) <= 100

思路:字符重排,即前面的字符串内部经过重新排序之后,形成的一个新的字符串。即字符的个数以及种类一定是一样的,且每个字符出现的次数也是一样的,那么本题就变成了判断两个字符串中字符出现的次数是否一致。可以先统计字符出现的次数存储在哈希表中,然后再遍历哈希表看看是否对应下标的值是否一致,如果全部一致,则返回true,否则,返回false。

代码实现:

class Solution {
    public boolean CheckPermutation(String s1, String s2) {
        // 1、先判断两者长度是否一致
        if (s1.length() != s2.length()) {
            return false;
        }
        // 2、遍历字符串,看两者出现的次数是否相等
        int[] hash = new int[26];
        int n = s1.length();
        for (int i = 0; i < n; i++) {
            hash[s1.charAt(i)-'a']++;
            hash[s2.charAt(i)-'a']--;
        }
        // 3、判断最终哈希表的结果是否为0
        for (int i = 0; i < 26; i++) {
            if (hash[i] != 0) {
                return false;
            }
        }
        return true;
    }
}

217.存在重复元素

题目:

给你一个整数数组 nums 。如果任一值在数组中出现 至少两次 ,返回 true ;如果数组中每个元素互不相同,返回 false 。

示例 1:

输入:nums = [1,2,3,1]

输出:true

解释:

元素 1 在下标 0 和 3 出现。

示例 2:

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

输出:false

解释:

所有元素都不同。

示例 3:

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

输出:true

提示:

  • 1 <= nums.length <= 105
  • -109 <= nums[i] <= 109

思路:我们只需要遍历数组,判断当前元素是否在前面出现过即可。

代码实现:

class Solution {
    public boolean containsDuplicate(int[] nums) {
        Set hash = new HashSet<>();
        for (int x : nums) {
            // 看当前元素是否出现过
            if (hash.contains(x)) {
                return true;
            }
            hash.add(x);
        }
        return false;
    }
}

219.存在重复元素II

题目:

给你一个整数数组 nums 和一个整数 k ,判断数组中是否存在两个 不同的索引 i 和 j ,满足 nums[i] == nums[j] 且 abs(i - j) <= k 。如果存在,返回 true ;否则,返回 false 。

示例 1:

输入:nums = [1,2,3,1], k = 3
输出:true

示例 2:

输入:nums = [1,0,1,1], k = 1
输出:true

示例 3:

输入:nums = [1,2,3,1,2,3], k = 2
输出:false

提示:

  • 1 <= nums.length <= 105
  • -109 <= nums[i] <= 109
  • 0 <= k <= 105

思路:本题的暴力解法也很容易想到,直接双层for循环即可。优化的话,就是固定当前元素,在哈希表找是否存在当前元素,如果存在,比较两者的下标差的绝对值是否满足小于等于k,如果满足的话,直接返回true即可,不满足就继续去寻找。但要注意的是:如果存在多个相同的元素,但不满足小于等于k时,需要将该元素的下标进行更新(在哈希表中),因为如果不更新的话,后续找到相同的元素时,其下标肯定是大于当前的值,而当前的值也不满足题目条件,那更别说后面的了,所以得更新下标,这样后续才可能满足条件。

代码实现:

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        Map hash = new HashMap<>();
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            // 找当前元素之前是否有相等的元素
            if (hash.containsKey(nums[i]) && Math.abs(hash.get(nums[i]) - i) <= k) {
                return true;
            }
            // 将当前元素加入哈希表
            hash.put(nums[i], i);
        }
        return false;
    }
}

49.字母异位词分组

题目:

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]

输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

示例 2:

输入: strs = [""]

输出: [[""]]

示例 3:

输入: strs = ["a"]

输出: [["a"]]

提示:

  • 1 <= strs.length <= 104
  • 0 <= strs[i].length <= 100
  • strs[i] 仅包含小写字母

思路:题目是让我们把相同字母组成的异位词分成一组,返回一个二维数组,存放着不同组别的字母异位词。判断是否为字母异位词,除了前面使用哈希表的方式之外,还可以使用排序的方式来判断。如果两个字符串属于字母异位词的话,那么他们两个按照ASCII码值的方式排序之后的结果一定是一样的(字面值),我们就可以按照这个方式来进行分组。接着将ASCII码值作为键,不同的字母异位词组作为值(值为一维数组),最终只需要拿到哈希表中的所有值即可。

代码实现:

class Solution {
    public List> groupAnagrams(String[] strs) {
        // 创建一个哈希表,存储相同分组的字符串
        Map> hash = new HashMap<>();
        // 1、将字符串进行分组(按照字母异位词)
        for (String s : strs) {
            // 对字符串s进行排序(按照ASCII码值)
            char[] tmp = s.toCharArray();
            Arrays.sort(tmp);
            String key = new String(tmp);
            // 看对应的哈希表是否为null
            if (!hash.containsKey(key)) {
                hash.put(key, new ArrayList<>()); // 给对应位置分配空间
            }
            hash.get(key).add(s);
        }
        // 2、将分组的结果组装到ArrayList中
        return new ArrayList<>(hash.values());
    }
}

好啦!本期 常见哈希表相关题目 的刷题之旅 就到此结束啦!我们下一期再一起学习吧!

你可能感兴趣的:(优选算法专题,算法,数据结构,哈希表)