/**
LeetCode 632.最小区间
解题思路:排序、离散化
把所有数字按照数值大小从小到大排序,但是每个携带属于哪个k(行)
然后把排序后的数字,离散化。例如: [34,56,10000]离散后,为[0,1,2]
若有相同的数字要记录不同的k(属于哪个行)。
然后每个离散后的数字以此为起点,找一个满足条件的区间
*/
func smallestRange(nums [][]int) []int {
rowLen := len(nums)
nodes := make([]*node, 0)
for i:=0; i<rowLen; i++ {
colLen := len(nums[i])
for j:=0; j<colLen; j++ {
node := &node{nums[i][j], i}
nodes = append(nodes, node)
}
}
//排序
sort.Sort(nodeHandler{nodes:nodes, By: func(p, q *node) bool {
return p.v < q.v
}})
nodeLen := len(nodes)
//离散化后数据
mapSli := make([]Map, 0)
//val->离散化的下标
mapping := make(map[int]int, 0)
//离散下标记录
mapCnt := 0
//离散化
for i:=0; i<nodeLen; i++ {
if _, ok := mapping[nodes[i].v]; !ok {
Map := Map{Pos:make([]int, 0), Val:nodes[i].v}
Map.Pos = append(Map.Pos, nodes[i].p)
mapSli = append(mapSli, Map)
mapping[nodes[i].v] = mapCnt
mapCnt++
} else {
mapSli[mapping[nodes[i].v]].Pos = append(mapSli[mapping[nodes[i].v]].Pos, nodes[i].p)
}
}
//找出最小区间
L, R := mapSli[0].Val, mapSli[mapCnt-1].Val
for j:=0; j<mapCnt; j++ {
r := check(j, rowLen, mapSli)
if r == -1 {
continue
}
idx := mapSli[j].Val
if r != -1 {
r = mapSli[r].Val
if R-L > r-idx {
L, R = idx, r
} else if R-L == r-idx {
if idx < L {
L, R = idx, r
}
}
}
}
return []int{L ,R}
}
func check(l , k int, mapSli []Map) int {
mapp := make(map[int]int, 0)
sliLen := len(mapSli)
for i:=l; i<sliLen; i++ {
posLen := len(mapSli[i].Pos)
for j:=0; j<posLen; j++ {
if _, ok := mapp[mapSli[i].Pos[j]]; !ok {
mapp[mapSli[i].Pos[j]] = 1
}
if len(mapp) == k {
return i
}
}
}
return -1
}
type node struct {
v, p int
}
type nodeHandler struct {
nodes []*node
By func(p, q *node) bool
}
func (n nodeHandler) Less(i, j int) bool {
return n.By(n.nodes[i], n.nodes[j])
}
func (n nodeHandler) Swap(i, j int) {
n.nodes[i], n.nodes[j] = n.nodes[j], n.nodes[i]
}
func (n nodeHandler) Len() int {
return len(n.nodes)
}
type Map struct {
Pos []int
Val int
}