哈希表与索引和统计

Posted Al_tair

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了哈希表与索引和统计相关的知识,希望对你有一定的参考价值。

哈希表与索引和统计

大家好呀,我是小笙!

哈希表与索引

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
  • 只会存在一个有效答案

**进阶:**你可以想出一个时间复杂度小于 O(n2) 的算法吗?

class Solution 
    public int[] twoSum(int[] nums, int target) 
        HashMap<Integer,Integer> find = new HashMap<>();
        int n = nums.length;
        for(int i=0;i<n;i++)
            if(find.containsKey(target-nums[i]) && find.get(target-nums[i])!=i)
                return new int[]i, find.get(target-nums[i]);
            
            find.put(nums[i],i);
          
        return new int[0];
    

167.两数之和 II - 输入有序数组

给定一个已按照 非递减顺序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target

函数应该以长度为 2 的整数数组的形式返回这两个数的下标值*。*numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。

示例 2:

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

示例 3:

输入:numbers = [-1,0], target = -1
输出:[1,2]

提示:

  • 2 <= numbers.length <= 3 * 104
  • -1000 <= numbers[i] <= 1000
  • numbers非递减顺序 排列
  • -1000 <= target <= 1000
  • 仅存在一个有效答案
class Solution 
    public int[] twoSum(int[] numbers, int target) 
        HashMap<Integer,Integer> find = new HashMap<>();
        int n = numbers.length;
        for(int i=0;i<n;i++)
            if(find.containsKey(target-numbers[i]) && find.get(target-numbers[i]) != i)
                if(i<find.get(target-numbers[i]))
               		return new int[]i+1,find.get(target-numbers[i])+1;
                else
                    return new int[]find.get(target-numbers[i])+1,i+1;
                
            
            find.put(numbers[i],i);
         
      return new int[0];
    

599.两个列表的最小索引总和

假设Andy和Doris想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示。

你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅。 如果答案不止一个,则输出所有答案并且不考虑顺序。 你可以假设总是存在一个答案。

示例 1:

输入:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
输出: ["Shogun"]
解释: 他们唯一共同喜爱的餐厅是“Shogun”。

示例 2:

输入:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["KFC", "Shogun", "Burger King"]
输出: ["Shogun"]
解释: 他们共同喜爱且具有最小索引和的餐厅是“Shogun”,它有最小的索引和1(0+1)。

提示:

  1. 两个列表的长度范围都在 [1, 1000]内。
  2. 两个列表中的字符串的长度将在[1,30]的范围内。
  3. 下标从0开始,到列表的长度减1。
  4. 两个列表都没有重复的元素。
class Solution 
    public String[] findRestaurant(String[] list1, String[] list2) 
        if(list1 == null || list2 == null) return null;
        HashMap<String,Integer> map = new HashMap<>();   // list1数组值 and 该数组下标
        ArrayList<String> value = new ArrayList<>();  // 输出的String数组值
        int m = list1.length,n = list2.length,MIN = Integer.MAX_VALUE;
        for(int i=0;i<m;i++)
            map.put(list1[i],i);
        
        for(int i=0;i<n;i++)
            if(map.containsKey(list2[i]))
                if((i+map.get(list2[i]))<MIN)
                    value.clear();
                    MIN = i+map.get(list2[i]);
                    value.add(list2[i]);
                else if((i+map.get(list2[i]))==MIN)
                    value.add(list2[i]);
                
            
        
        return value.toArray(new String[value.size()]);
    

// 执行用时:8 ms, 在所有 Java 提交中击败了82.29%的用户
// 内存消耗:39.1 MB, 在所有 Java 提交中击败了26.04%的用户

219.存在重复元素 II

给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 ij,使得 nums [i] = nums [j],并且 ij 的差的 绝对值 至多为 k

示例 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
class Solution 
    public boolean containsNearbyDuplicate(int[] nums, int k) 
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) 
            Integer index = map.get(nums[i]);  // 精华Integer 默认赋值null 区别于 int没有默认
            if (index == null) 
                map.put(nums[i], i);
             else if (i - index <= k) 
                return true;
             else 
                map.put(nums[i], i);
            
        
        return false;
    

220.存在重复元素 III

给你一个整数数组 nums 和两个整数 kt 。请你判断是否存在 两个不同下标 ij,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k

如果存在则返回 true,不存在返回 false

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 0 <= nums.length <= 2 * 104
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 104
  • 0 <= t <= 231 - 1
class Solution 
    public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) 
        // 1. 使用有序集合来维护大小为k的滑动窗口
        int n = nums.length;
        TreeSet<Long> set = new TreeSet<Long>();                            // long为了防止溢出

        // 2. 处理逻辑:遍历每个元素,滑动窗口包含了nums[i]的前k个元素,检查是否落在了[nums[i] - t,nums[i] + t]的区间内
        for (int i = 0; i < n; i++) 
            // 2.1 判断有序集合中是否存在符合条件的元素
            Long ceiling = set.ceiling((long) nums[i] - (long) t);          // ceiling():方法返回在这个集合中大于或者等于给定元素的最小元素,如果不存在这样的元素,返回null.
            if (ceiling != null && ceiling <= (long) nums[i] + (long) t)   // 存在这样一对元素就直接返回
                return true;
            

            // 2.2 不存在的话暂时添加到有序集合中
            set.add((long) nums[i]);

            // 2.3 维护大小为k的滑动窗口,删除超出范围的最早的元素
            if (i >= k) 
                set.remove((long) nums[i - k]);
            
        
        // 3. 都不满足返回false
        return false;
    

哈希表与统计

594.最长和谐子序列

和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1

现在,给你一个整数数组 nums ,请你在所有可能的子序列中找到最长的和谐子序列的长度。

数组的子序列是一个由数组派生出来的序列,它可以通过删除一些元素或不删除元素、且不改变其余元素的顺序而得到。

示例 1:

输入:nums = [1,3,2,2,5,2,3,7]
输出:5
解释:最长的和谐子序列是 [3,2,2,2,3]

示例 2:

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

示例 3:

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

提示:

  • 1 <= nums.length <= 2 * 104
  • -109 <= nums[i] <= 109
class Solution 
    public int findLHS(int[] nums) 
        int MAX = 0;
        HashMap<Integer,Integer> map = new HashMap<>();
        int n = nums.length;
        for(int i = 0;i < n;i++)
            if(map.containsKey(nums[i]))
                map.replace(nums[i],map.get(nums[i]),map.get(nums[i])+1);
            else
                map.put(nums[i],1);
            
        
        for(int num:map.keySet())
            if(map.containsKey(num+1))
                MAX = Math.max(MAX,map.get(num)+map.get(num+1));
            
        
        return MAX;
    

350.两个数组的交集 II

给你两个整数数组 nums1nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

示例 1:

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

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000

进阶:

  • 如果给定的数组已经排好序呢?你将如何优化你的算法?
  • 如果 nums1 的大小比 nums2 小,哪种方法更优?
  • 如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
class Solution 
    public int[] intersect(int[] nums1, int[] nums2) 
        int m = nums1.length,n = nums2.length;
        if(m*n == 0) return null;
        HashMap<Integer,Integer> map = new HashMap<>();
        ArrayList<Integer> list = new ArrayList<>();
        for(int i=0;i<m;i++)
            if(!map.containsKey(nums1[i]))
                map.put(nums1[i],1);
            else
                map.replace(nums1[i],map.get(nums1[i]),map.get(nums1[i])+1);
            
        
        for(int i=0;i<n;i++)
            if(map.containsKey(nums2[i]) && map.get(nums2[i])!=0)
                list.add(nums2[i]);
                map.replace(nums2[i],map.get(nums2[i]),map.get(nums2[i])-1);
            
        
        return list.stream().mapToInt(Integer::intValue).toArray();
    

以上是关于哈希表与索引和统计的主要内容,如果未能解决你的问题,请参考以下文章

选择适当的数据结构(哈希表与后缀树)来索引大量相似的字符串

Hot1001. 两数之和

两数之和(哈希解法)

哈希表简单应用—两数之和

LeetCode 1. 两数之和 Two Sum (Easy)

leetcode 1.两数之和(暴力&哈希)