合并有交集的集合

问题

给定一个字符串的集合,格式如:
{{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.如果有改动, 则所以包含这个索引的都需要改动

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值