当前位置: 首页 > news >正文

【代码随想录】哈希表-golang

哈希表 from 代码随想录

hash表解法可以是slice,map…,目的是将时间复杂度降为O(1)

有效的字母异位词

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

排序

思路:直接重新声明字符的字节形式,然后对其进行排序比较

func isAnagram(s, t string) bool {
    if len(s) != len(t) {
        return false
    }
    s1 := []byte(s)
    s2 := []byte(t)
    sort.Slice(s1,func(i,j int) bool{return s1[i] < s1[j]})
    sort.Slice(s2,func(i,j int) bool{return s2[i] < s2[j]})
    return string(s1) == string(s2)
}

哈希表

时间复杂度O(n) n为s的长度
空间复杂度O(s) s为字符集大小

数组

思路:从另一个角度考虑,t 是 s 的异位词等价于「两个字符串中字符出现的种类和次数均相等」。由于字符串只包含 26 个小写字母,声明两个长度为26的数组,遍历s和t后比较两个数组

func isAnagram(s, t string) bool {
    var c1, c2 [26]int
    for _, ch := range s {
        c1[ch-'a']++
    }
    for _, ch := range t {
        c2[ch-'a']++
    }
    return c1 == c2
}

map

思路:先初始化一个map,遍历s去存入然后再遍历t去删除

func isAnagram(s, t string) bool {
    if len(s) != len(t) {
        return false
    }
    s1 := map[rune]int{}
    for _,val := range s {
        s1[val]++
    }
    for _,val := range t {
        s1[val]--
        if s1[val] < 0 {
            return false
        }
    }
    return true

}

两个数组的交集

给定两个数组,编写一个函数来计算它们的交集。

两个集合

如果使用哈希集合存储元素,则可以在 O(1)的时间内判断一个元素是否在集合中,从而降低时间复杂度
时间复杂度和空间复杂度均为O(m+n),其中 m 和 n 分别是两个数组的长度

func intersection(nums1 []int, nums2 []int)(intersection []int) {
    hash1 := map[int]struct{}{}
    hash2 := map[int]struct{}{}
    for _,val := range nums1{
        hash1[val] = struct{}{}
    }
    for _,val := range nums2{
        hash2[val] = struct{}{}
    }
    if len(hash1) > len(hash2){
        hash1,hash2 = hash2,hash1
    }
    for key,_ := range hash1{
        if _,exist := hash2[key];exist{
            intersection = append(intersection,key)
        }
    }
    return 
}

快乐数

编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

func isHappy(n int) bool {
    m := map[int]bool{}
    for ; n!=1 && !m[n];n,m[n] = step(n),true{}
    return n == 1
}
c
func step(n int)int{
    sum := 0
    for n > 0 {
        sum += (n%10) * (n%10)
        n = n/10
    }
    return sum
}

两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。

思路:可以采取暴力解法,双层for循环结束战斗,但是时间复杂度是O(n2),可以采取hash map用空间换时间来降低时间复杂度

func twoSum(nums []int, target int) []int {
    s1 := map[int]int{}
    for index,val := range nums{
        if prevIndex,ok := s1[target - val];ok{
            return []int{prevIndex,index}
        }else{
            s1[val] = index
        }
    }
    return []int{}
}

四数相加II

在这里插入图片描述

将四个数组归为两组 a + b + c + d = 0 --> a + b = -c - d
所以声明一个hashmap将a+b 存入map然后用 -c -d 去命中map
时间复杂度O(n2) 空间复杂度O(n2)

func fourSumCount(nums1 []int, nums2 []int, nums3 []int, nums4 []int)(ans int)  {
    s1 := map[int]int{}
    for _,a := range nums1 {
        for _,b := range nums2{
            s1[a+b]++
        }
    }
    for _,c := range nums3 {
        for _,d := range nums4{
            ans += s1[-c-d]
        }
    }
    return
}

赎金信

给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。如果可以构成,返回 true ;否则返回 false。’

(题目说明:为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,组成单词来表达意思。杂志字符串中的每个字符只能在赎金信字符串中使用一次。)

思路:类似相同字符串那题?
先通过长度过滤,然后将magazine 中的字符存进hashmap中 val++,遍历赎金信去命中hashmap val-- 如果小于0返回false,未命中返回false,最后返回true

时间复杂度O(m+n),空间复杂度O(n)

hashmap 第一次自解

func canConstruct(ransomNote string, magazine string) bool {
    if len(ransomNote) > len(magazine) {
        return false
    }
    s1 := map[rune]int{}
    for _,val := range magazine{
        s1[val]++
    }
    for _,val := range ransomNote{
        if _,ok := s1[val];ok{
            s1[val]--
            if s1[val] < 0{
                return false
            }
        }else{
            return false
        }
    }
    return true
}

数组,leetcode答案 26长度的数组,用 n - 'a’定位

func canConstruct(ransomNote, magazine string) bool {
    if len(ransomNote) > len(magazine) {
        return false
    }
    cnt := [26]int{}
    for _, ch := range magazine {
        cnt[ch-'a']++
    }
    for _, ch := range ransomNote {
        cnt[ch-'a']--
        if cnt[ch-'a'] < 0 {
            return false
        }
    }
    return true
}

三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

思路:双指针,固定首个元素然后后两个元素用双指针进行查找,过程中注意检查重复值问题(一旦一个元素重复会造成最后的结果出现重复数组)

func threeSum(nums []int) [][]int {
    n := len(nums)
    sort.Ints(nums)
    ans := make([][]int, 0)
 
    // 枚举 a
    for first := 0; first < n; first++ {
        // 需要和上一次枚举的数不相同
        if first > 0 && nums[first] == nums[first - 1] {
            continue
        }
        // c 对应的指针初始指向数组的最右端
        third := n - 1
        target := -1 * nums[first]
        // 枚举 b
        for second := first + 1; second < n; second++ {
            // 需要和上一次枚举的数不相同
            if second > first + 1 && nums[second] == nums[second - 1] {
                continue
            }
            // 需要保证 b 的指针在 c 的指针的左侧
            for second < third && nums[second] + nums[third] > target {
                third--
            }
            // 如果指针重合,随着 b 后续的增加
            // 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
            if second == third {
                break
            }
            if nums[second] + nums[third] == target {
                ans = append(ans, []int{nums[first], nums[second], nums[third]})
            }
        }
    }
    return ans
}

四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。

思路:在三数之和的基础上再加上一层for循环

参考答案思路未剪枝版

func fourSum(nums []int, target int)(ans [][]int)  {
    n := len(nums)
    sort.Ints(nums)
    for first := 0;first < n-3 ; first ++ {
        if first > 0 && nums[first] == nums[first - 1]{
            continue
        }
        for second := first + 1;second < n-2 ;second ++ {
            if second > first + 1 && nums[second] == nums[second - 1]{
                continue
            }
            for left,right := second + 1,n - 1;left < right; {
                if sum := nums[first] + nums[second] + nums[left] + nums[right] ;sum == target{
                    ans = append(ans, []int{nums[first], nums[second], nums[left], nums[right]})
                    for left ++ ;left < right && nums[left] == nums[left-1];left++{}
                    for right -- ;left < right && nums[right] == nums[right+1];right--{}
                }else if sum < target{
                    left ++
                }else {
                    right --
                }
            }
        }
    }
    return ans
}

完整版 - 在 first 和 seocnd的for循环中开始剪枝

func fourSum(nums []int, target int)(ans [][]int)  {
    n := len(nums)
    sort.Ints(nums)
    for first := 0;first < n-3 ; first ++ {
    	//去重 + 剪枝
        if first > 0 && nums[first] == nums[first - 1] || nums[first] + nums[n-1] + nums[n-2] + nums[n-3] < target{
            continue
        }
        for second := first + 1;second < n-2 ;second ++ {
        	//去重 + 剪枝
            if second > first + 1 && nums[second] == nums[second - 1] || nums[first] + nums[second] + nums[n-2] + nums[n-1] < target{
                continue
            }
            for left,right := second + 1,n - 1;left < right; {
                if sum := nums[first] + nums[second] + nums[left] + nums[right] ;sum == target{
                    ans = append(ans, []int{nums[first], nums[second], nums[left], nums[right]})
                    for left ++ ;left < right && nums[left] == nums[left-1];left++{}
                    for right -- ;left < right && nums[right] == nums[right+1];right--{}
                }else if sum < target{
                    left ++
                }else {
                    right --
                }
            }
        }
    }
    return ans
}

相关文章:

  • 南京seo按天计费/哈尔滨关键词优化方式
  • 东莞营销型网站建设/营销网络是什么
  • 北京网站建设有限公司/市场营销策略有哪4种
  • dedecms 食品网站/个人网站设计作品
  • 怎么做类似站酷的网站/中国网站建设公司前十名
  • 光泽网站建设/海淀搜索引擎优化seo
  • AWS CodeDeploy的疑难问题小记
  • 抖音聊天”上线,字节最后的社交梦?
  • 【ElasticSearch01】ElasticSearch入门
  • proc文件系统下各参数解析
  • ARM 看门狗定时器
  • Linux:git工具
  • 折半查找算法[二分查找法]算法的实现和解决整数溢出问题~
  • InfluxDB的查询优化
  • 1-货物摆放
  • 2023.1.16 (一) 上午 关于人口老龄化的研究——老龄化的式子表示及建国以来的老龄化情况
  • 5. 统计学基础2:协方差、相关系数、协方差矩阵
  • 【C++】二叉树进阶OJ题