问题
给定一个字符串的集合,格式如:
{{a,b,c}, {b,d},{e,f},{g},{d,h}}
要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应
输出
{{a,b,c,d,h},{e,f}, {g}}
工作一年第一次遇到到的相对比较难的算法题, 看了网上的思路, 然后自己实现了下
思路
初始化一个值全为-1, 大小跟给定的字符串集合大小一样的数组(下文叫定位数组)。然后把所有字符串转换成这种形式(字符串和字符串所出现在的集合的索引) 下文叫索引数组的集合
a 0
b 0,1
c 0
d 1,4
e 2
f 2
g 3
h 4
先对索引数组的集合进行排序(没有排序会影响结果), 然后循环索引数组的集合操作定位数组( 如果索引数组大小为1, 且定位数组的当前值的位置的值为-1, 则在定位数组的当前值的位置插入当前值, 如果当前值位置的值不为-1, 则不做操作;如果索引数组有多个元素, 则依次循环每个索引,找到索引数组在定位数组里面的最小值插入
a 0 [ 0, -1, -1, -1, -1]
c 0 [ 0, -1, -1, -1, -1]
b 0,1 [ 0, 0, -1, -1, -1]
d 1,4 [ 0, 0, -1, -1, 0]
e 2 [ 0, 0, 2, -1, 0]
f 2 [ 0, 0, 2, -1, 0]
g 3 [ 0, 0, 2, 3, 0]
h 4 [ 0, 0, 2, 3, 0]
最后这个结果数组 [0, 0, 2, 3, 0] 就是我们想要的
- 位置为 0,1,4 为一组,所以 {a,b,c},{b,d},{d,h} 是一组。
- 位置 2 一组, 即 {e,f}
- 位置 3 一组, 即 {g}
scala实现
废话不多说,上代码。这里是用Scala语言实现的
def fix(): Unit = {
val data: Array[Set[String]] = Array(
Set("a", "b", "c")
, Set("b", "d" )
, Set("e", "f")
, Set("g")
, Set("d", "h")
)
// 初始化一个跟groupWithSrc一样大小的数组, 全为-1
val array = List.fill[Int](data.length)(-1).toArray
val map = mutable.HashMap[String, ArrayBuffer[Int]]()
for (i <- data.indices) {
data(i).foreach(s => {
if (map.containsKey(s)) { // 如果已经存在
map(s).append(i) // 在原来的基础上增加现在的索引
} else {
map.put(s, ArrayBuffer(i))
}
})
}
val values = map.values
.toList.sortWith((a, b) => a.mkString("") < b.mkString("")) // 排序
println(values)
values.foreach(v => {
val indexs: ArrayBuffer[Int] = v.sortWith((a, b) => a < b)
indexs.foreach(i => {
val arrayI = array(i)
if (indexs.size == 1) {
if (arrayI == -1) { // 如果index只有一个而且位置为-1则直接插入
array(i) = i
}
} else { // 如果index不止一个
val indValues = indexs.map(array(_)).filter(_ != -1)
val min = if (indValues.isEmpty) i else indValues.min // 找到所有索引位置最小的值, 如果没有就当前值
if (arrayI == -1) { //如果位置为-1 则直接插入
array(i) = min
} else { // 如果位置已经有值, 则比对原值是否比现在值小, 插入小的
array(i) = if (arrayI < min) arrayI else {
values.foreach(arr => { // 如果有改动, 则所有包含这个索引的都需要改动
if (arr.contains(i)){
arr.foreach(ei => array(ei) = min)
}
})
min
}
}
}
})
})
val tmap = new mutable.HashMap[Int, ListBuffer[Int]]()
for (i <- array.indices) {
val e = array(i)
if (tmap.containsKey(e)) {
tmap(e).append(i)
} else {
tmap.put(e, ListBuffer(i))
}
}
var newBuffer = new ListBuffer[Set[String]]
tmap.values.foreach(v => {
var set: Set[String] = Set()
v.foreach(set ++= data(_))
newBuffer.append(set)
})
println(newBuffer)
}
最后打印结果
注意的点
1.索引数组的集合一定要排序
2.如果当前位置有值, 一定要看是否是当前索引数组的最小值, 如果不是要重新插入最小值。
3.如果有改动, 则所以包含这个索引的都需要改动