首页 > 其他分享 >哈希表

哈希表

时间:2022-12-23 22:12:35浏览次数:37  
标签:right 数组 nums int ++ 哈希 left

哈希表

1. 两数之和

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

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

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

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

解题思路:

  • 使用 hash 表来存放 key-元素值,value-元素下标

  • 遍历数组,如果当前元素与 hash 表中的值恰好之和为 target,那么就成功了,否则将当前元素加入到 hash 表中。

func twoSum(nums []int, target int) []int {
    m := make(map[int]int)
    for i, num := range nums {
        if idx, exists := m[target-num]; exists {
            return []int{i, idx}
        } else {
            m[num] = i
        }
    }
    return []int{}
}

15. 三数之和

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

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

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

输入: 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] 。
注意,输出的顺序和三元组的顺序并不重要。

解题思路:

  • 排序,将数组排序成有序的

  • 固定一个数,然后使用双指针遍历另外两个元素。

  • 去重可以使用 hashmap,也可以使用比较当前元素与前一个元素值的方式。

注意点:

  • 三数之和不要使用 hash 表的方法!!!hash 表的方法会很繁琐,记住就行,三数之和要使用 排序+双指针 的方法!!

  • 得到一个结果之后两个指针需要分别向左,向右移动。这样可以防止出现死循环。

  • 得到的数组最后必须要进行去重,为了防止出现重复的数组。

func threeSum(nums []int) [][]int {
    res := make([][]int, 0)
    history := make(map[string]struct{}) // 去重的 hashmap
    // 排序
    sort.Slice(nums, func(i, j int) bool {
        return nums[i] < nums[j]
    })
    for i := 0; i <= len(nums)-3; i++ {
        left := i + 1
        right := len(nums) - 1
        for left < right {
            if nums[i]+nums[left]+nums[right] < 0 {
                left++
            } else if nums[i]+nums[left]+nums[right] > 0 {
                right--
            } else {
                subNum := []int{nums[i], nums[left], nums[right]}
                /** --------- bug 记录 ----------
                没有去重,导致出现重复的三元组. 现在这里使用 hashmap 来进行去重
                */
                s := encode(subNum)
                if _, exists := history[s]; !exists {
                    history[s] = struct{}{}
                    res = append(res, subNum)
                }
                /** --------- bug 记录 -------------
                刚开始 left++,right-- 没写,导致程序在这里死循环!
                */
                left++
                right--
            }
        }
    }
    return res
}

func encode(nums []int) string {
    return fmt.Sprintf("%v", nums)
}

以下是去重版本2,没有使用 hashmap 进行去重,而是通过判断上一个元素是否与这一个元素相等来进行的去重。

在写这道题的过程中,出现了三处 bug:

  • 没有去重代码

  • 使用去重方法2的时候,应该开始新循环的地方没有写 continue,导致代码继续执行

  • 得到结果的时候,left -- 和 right ++ 没有写,导致程序在这处死循环。

// 去重版本2
func threeSum_(nums []int) [][]int {
    res := make([][]int, 0)
    // 排序
    sort.Slice(nums, func(i, j int) bool {
        return nums[i] < nums[j]
    })
    for i := 0; i <= len(nums)-3; i++ {
        // 第一个元素也需要被去重
        if i > 0 && nums[i] == nums[i-1] {
            continue
        }
        left := i + 1
        right := len(nums) - 1
        for left < right {
            /** --------- bug 记录 ----------
            没有去重,导致出现重复的三元组. 因为重复的原因在于遍历数组的时候,相邻元素可能相等,那么去重就可以跳过相邻的元素。
            */
            // 左面, 右面相邻元素重复,需要跳过以达到去重的目的, 比如left > i + 1的目的是让left不是第一个元素,必须从第二个开始去重,rigth < len(nums)-1 同理
            if left > i+1 && nums[left] == nums[left-1] {
                left++
                continue
                /** ---- bug 记录 -----
                刚开始没有写 continue,导致去重之后继续执行后序代码,与预期不相符合,所以说想要开始新循环的时候一定要写 continue,要养成习惯!!
                */
            }
            if right < len(nums)-1 && nums[right] == nums[right+1] {
                right--
                continue
            }
            if nums[i]+nums[left]+nums[right] < 0 {
                left++
                continue
            } else if nums[i]+nums[left]+nums[right] > 0 {
                right--
                continue
            } else {
                subNum := []int{nums[i], nums[left], nums[right]}
                res = append(res, subNum)
                /** --------- bug 记录 -------------
                刚开始 left++,right-- 没写,导致程序在这里死循环!
                */
                left++
                right--
            }
        }
    }
    return res
}

454. 四数相加 II

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

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

输入: 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

解题思路:

本题乍一看好像与三数之和相同,只不过由三个数变成了四个数,仔细一看发现不一样,三数之和是在一个数组中,所以使用固定一个数,移动另外两个数的方式。而这道题是在四个数组中,所以使用 hashmap 的方法,先计算两项和出现的次数,然后将两项和合并,计算总共出现的次数。

func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int) int {
    // 先计算两项和, 再计算另外两项和, 然后再计算它俩的和
    m1 := make(map[int]int) //两项和出现的次数
    for i := 0; i < len(nums1); i++ {
        for j := 0; j < len(nums2); j++ {
            m1[nums1[i]+nums2[j]]++
        }
    }
    m2 := make(map[int]int)
    for i := 0; i < len(nums3); i++ {
        for j := 0; j < len(nums4); j++ {
            m2[nums3[i]+nums4[j]]++
        }
    }
    count := 0
    for sum1, count1 := range m1 {
        for sum2, count2 := range m2 {
            if sum2+sum1 == 0 {
                count += count2 * count1
            }
        }
    }
    return count
}

标签:right,数组,nums,int,++,哈希,left
From: https://www.cnblogs.com/geraldkohn/p/17001731.html

相关文章

  • redis hset 哈希表操作添加json串为单引号且客户端窗口需要最大化,字符串不能断行
    redishset哈希表操作添加json串为单引号且客户端窗口需要最大化,字符串不能断行语法:1.HGETkeyfield获取存储在哈希表中指定字段的值。DEMO:单个查询hget"微服务名称:......
  • 基础算法汇总之哈希表
    一.什么是哈希表哈希表也叫做散列表,是一种可以根据关键key值直接访问的数据结构;简单说就是把关键的key值映射到数组中一个位置来访问记录,这样可以加快反应速度。这里面计算......
  • [OpenCV实战]45 基于OpenCV实现图像哈希算法
    目前有许多算法来衡量两幅图像的相似性,本文主要介绍在工程领域最常用的图像相似性算法评价算法:图像哈希算法(imghash)。图像哈希算法通过获取图像的哈希值并比较两幅图像的......
  • 数据结构之哈希表
    wikipedia上的解释​​http://zh.wikipedia.org/wiki/%E5%93%88%E5%B8%8C%E8%A1%A8​​下图示意了哈希表(HashTable)这种数据结构。哈希表如上图所示,首先分配一个指针......
  • UI自动化测试之openCV(均值哈希算法、差值哈希算法、感知哈希算法、三直方图算法相似度
    上图为图片相似度对比素材。均值哈希算法代码如下:#-*-coding:utf-8-*-importcv2#Hash值对比defcmpHash(hash1,hash2,shape=(10,10)):n=0......
  • 哈希表总结
    哈希表理论讲解元素通过确定的映射关系找到其在表中的存储位置,这个映射关系叫做哈希函数(散列函数),==这张表就叫做哈希表(散列表)优势:适用于快速的查找,时间复杂度为O(1)......
  • DS哈希查找—二次探测再散列
    题目描述定义哈希函数为H(key)=key%11。输入表长(大于、等于11),输入关键字集合,用二次探测再散列构建哈希表,并查找给定关键字。输入测试次数t每组测试数据格式如下:哈希......
  • 局部敏感哈希-Locality Sensitive Hashing-LSH
    问题定义对于一个给定的query,从数据库中召回所有dist<thres的docs。问题求解Naive的方法需要O(n)的时间复杂度,LSH只需要O(1)即可实现。具体来说分为三步:1)抽取Embeddin......
  • [停更一周,我干了什么] [C++/QT] 一个基于avl树,trie树,哈希散列表的英汉词典
    目录​​结构关系​​​​对三种数据结构的理解​​​​1.AVL(自平衡二叉排序树)​​​​四种旋转场景​​​​AVL树的删除操作的妙处​​​​测试效果​​​​2.Trie树(字......
  • 哈希算法学习笔记
    1.哈希表1-1.介绍本质上是一种高级的数组。原理是通过设计哈希函数将一些难以维护的值映射成为易于维护的值以加快查找速度。但如果哈希函数设计的不够巧妙,可能会导致......