欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

散列

程序员文章站 2022-03-15 20:52:44
...

散列

理想散列表是一个包含关键字的具有固定大小的数组,它能够以常熟时间执行插入,删除和查找操作。

  • 映射规则叫散列函数
  • 散列冲突

冲突解决

  • 拉链发
    将同一个值的关键字保存在同一个表中,查找的时候,除了根据计算出来的散列值找到对应位置外,还需要在链表上进行搜索。而在单链表上的查找速度是很慢的
  • 开放定址法
    如果冲突发生,就选择另外一个可用的位置,无论是哪种开放定址法,它都要求表足够大:
    1、线性探测法,可能造成一次聚集
    2、平方探测法,可能产生二次聚集
    3、双散列,hash1(X)+2hash2(X)
  • 再散列
    如果插入新的数据时散列表已满,或者散列表所剩容量不多该怎么办?这个时候就需要再散列

应用

  • 文件校验
  • 数字签名

两数之和(LeetCode 上第 1 号问题)

题目描述

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

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

题目解析

使用散列表来解决该问题。
首先设置一个map容器用来记录元素的值与索引,然后遍历数组nums。

  • 每次遍历时使用临时变量 tmp 用来保存目标值与当前值的差值
  • 在此次遍历中查找 record,查看是否有与 tmp 一致的值,如果查找成功则返回查找值的索引值与当前变量的值。
  • 如果未找到,则再 record 保存该元素与索引值 i

代码实现

func TwoSum(nums []int, t int)(int,int){
	record := make(map[int]int)
	for i:=0;i<len(nums);i++{
		tmp := t - nums[i]
		j,ok := record[tmp]
		if ok{
			return i,j
		}
		record[nums[i]] = i
	}
	return -1,-1
}

无重复字符的最长字串( LeetCode 上第 3 号问题)

题目描述

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

题目解析

建立一个HashMap,建立每个字符和其最后出现位置之间的映射,然后再定义两个变量res和left。

  • res 用来记录最长无重复字串的长度
  • left 指向该无重复子串左边的起始位置的前一个
    接下来遍历整个字符串,对于每个遍历到的字符,如果该字符已经在HashMap中存在了,并且如果其映射值大于 left 的话,那么更新 left 为当前映射值,然后映射值更新为当前坐标 i ,这样保证了 left 始终为当前边界的前一个位置,然后计算窗口长度的时候,直接用 i-left 即可, 用来更新结果 res。

代码更新

//利用滑动窗口
func LengthOfLongestSubstring(s string)int{
	start,end := 0,0; res := 0;n := len(s)
	//借助一个容器 来判断子串中是否有重复
	m := map[byte]byte{}
	for start < n && end < end{
		if _,ok := m[s[end]];!ok{
			m[s[end]] = s[end]
			end++ //移动滑动窗口
			res = int(math.Max(float64(res),float64(end-start)))
		}else{
				//有重复的,滑动窗口移动
				delete(m,s[start])
				start++
		}
	}
	return res
}
优化滑动窗口
func LengthOfLongestSubstring(s string)int{
	res := 0; left := -1; n := len(s)
	m := map[string]int{}
	for i := 0; i<n; i++{
		if _,ok := m[string(s[i])];ok{
			//重复的,
			left = int(math.Max(float64(m[string(s[i])]),float64(left)))
		}
		res = int(math.Max(float64(res),float64(i-left)))
		m[string(s[i])] = i
	}
	return res
}

三数之和( LeetCode 上第 15 号问题)

题目描述

给定一个包含 n 个整数的数组 nums, 判断 nums 中是否存在三个元素a, b, c,使得a+b+c=0? 找出所有满足条件且不重复的三元组。

题目解析

一开始可以选择一个数,然后再去找另外两个数,这样只要找到两个数且和为第一个选择的数的相反数就行了。也就是需要枚举a 和 b, 将 c 存入map即可。

代码实现

func ThreeSum(nums []int)[][]int{
	sort.Ints(nums)
	n := len(nums)
	result := [][]int{}
	for i:=0;i<n-1 && nums[i]<=0; i++{
		if i>0 && nums[i] == nums[i-1]{continue}
		// j start指针, k end指针
		j := i+1; k := n-1
		t := 0-nums[i]
		for j<k{
			sum := nums[j] + nums[k]
			if sum == t{
				result = append(result,[]int{nums[i],nums[j],nums[k]})
				j++ //右移
				for j<k && nums[j-1] == nums[j]{
					j++
				}
				k-- //左移
				for j<k && nums[k+1] == nums[k]{
					k--
				}
			}else if sum>t{
				k--
				for j<k && nums[k+1] == nums[k]{
					k--
				}
			}else{
				j++
				for j<k && nums[j-1] == nums[j]{
					j++
				}
			}
		}
	}
	return result
}

最接近的三数之和( LeetCode 上第 16 号问题)

题目描述

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

代码实现

import (
	"math"
	"sort"
)
func ThreeSumClosest(nums []int,t int)int{
	sort.Ints(nums)
	res := nums[0] + nums[1] + nums[2]
	for i:=0; i<len(nums)-2; i++{
		m,n := i+1, len(nums)-1
		for m < n{
			sums := nums[i] + nums[m] + nums[n]
			if math.Abs(float64(sums-t))<math.Abs(float64(res-t)){
				res = sums
			}
			if sums > t{
				n--
			}else if sums < t{
				m++
			}else{
				return sums
			}
		}
	}
	return res
}

重复的DNA序列(LeetCode 上第 187 号问题)

题目描述

所有 DNA 由一系列缩写为 A,C,G 和 T 的核苷酸组成,例如:“ACGAATTCCG”。在研究 DNA 时,识别 DNA 中的重复序列有时会对研究非常有帮助。

编写一个函数来查找 DNA 分子中所有出现超过一次的 10 个字母长的序列(子串)。