Arrays 最小化操作数以使数组的所有元素相等
给定一个由n个元素组成的数组,只允许执行2种操作,以使数组中的所有元素相等Arrays 最小化操作数以使数组的所有元素相等,arrays,algorithm,Arrays,Algorithm,给定一个由n个元素组成的数组,只允许执行2种操作,以使数组中的所有元素相等 将任何元素乘以2 将元素除以2(整数除法) 您的任务是最小化执行的上述操作的总数,以使数组的所有元素相等 范例 数组=[3,6,7]最小运算是2,因为6和7可以除以2得到3 我甚至想不出暴力解决方案 约束条件 1. 通过二进制扩展将所有数字视为0和1的字符串 例如:3、6、7分别表示为11、110、111 除以2相当于删除最右边的0或1,乘以2相当于从右边添加一个0 对于由0和1组成的字符串,让我们将其“head”定义为
0
和1
的字符串3、6、7分别表示为11、110、111
除以2
相当于删除最右边的0
或1
,乘以2
相当于从右边添加一个0
对于由0
和1
组成的字符串,让我们将其“head”定义为一个子字符串,该子字符串是字符串的左几个项,以1
结尾。
例如:1100101
有头1
,11
,11001
,1100101
任务变成查找所有给定字符串的最长公共头,然后确定在此公共头之后要添加多少个0
例如:
假设您有以下字符串:
10101001
,101011
,10111
,1010001
查找10101001
和101011
的最长公共头,即10101
李>
查找10101
和10111
的最长公共头,即101
李>
查找101
和1010001
的最长公共头,即101
然后您确定所有的数字都应该变成101 00…
格式的数字
要确定在101
之后要添加多少0
,请查找每个字符串中紧跟在101
之后的连续0
:
对于10101001
:1
对于101011
:1
对于10111
:0
对于1010001
:3
仍然需要找到一个使|k-1 |+| k-1 |+| k-0 |+| k-3 |
最小化的整数k
。这里我们找到k=1
。所以每个数字最后都应该是1010
正如另一个答案所解释的,回溯是不必要的。为了好玩,我们对该方法进行了一点实现。(请参阅底部的联机运行链接):
首先,我们需要一个函数来确定数字中的二进制位数:
def getLength(i: Int): Int = {
@annotation.tailrec
def rec(i: Int, result: Int): Int =
if(i > 0)
rec(i >> 1, result + 1)
else
result
rec(i, 0)
}
然后我们需要一个函数来确定两个等长数字的公共前缀
@annotation.tailrec
def getPrefix(i: Int, j: Int): Int =
if(i == j) i
else getPrefix(i >> 1, j >> 1)
以及任意数字的列表:
def getPrefix(is: List[Int]): Int = is.reduce((x,y) => {
val shift = Math.abs(getLength(x) - getLength(y))
val x2 = Math.max(x,y)
val y2 = Math.min(x,y)
getPrefix((x2 >> shift), y2)
})
然后我们需要后缀的长度,而不计算后缀的leeding零:
def getSuffixLength(i: Int, prefix: Int) = {
val suffix = i ^ (prefix << (getLength(i) - getLength(prefix)))
getLength(suffix)
}
现在,我们可以找到最少的操作数,并将其与我们要同步到的值一起返回:
def getMinOperations(is: List[Int]) = {
val prefix = getPrefix(is)
val maxZeros = getLength(is.max) - getLength(prefix)
(0 to maxZeros).map{zeros => (is.map{getOperations(_, prefix, zeros)}.sum, prefix << zeros)}.minBy(_._1)
}
对于你的边界,输入大小基本上是线性的
此版本可在此处找到:
提及约束条件时,请不要忘记发布约束条件,因为它们非常重要!蛮力可以很快是的,这是正确的解决方案。一旦你观察到解的形状(前缀后面跟着零),这真的很容易。@WhatsUp如何有效地找到k?鉴于你的限制,甚至可以用bruteforce来做:试试从0
到20
的每一个k
,比方说。我已经用这个实现来代替我的答案。我已经用蛮力做到了,如果速度不够快,你可以在前缀后面按0的数字分组,因为这是唯一重要的事情,并将其转化为一个因素。这个答案符合问题的要求吗?只允许两种类型的操作;乘二除二。二进制扩展将需要更多的运算,额外的计算,如加法或减法,也将超出初始问题要求的范围。结果是正确的,但旅程似乎越界了。也许我误解了这个问题?
def getMinOperations(is: List[Int]) = {
val prefix = getPrefix(is)
val maxZeros = getLength(is.max) - getLength(prefix)
(0 to maxZeros).map{zeros => (is.map{getOperations(_, prefix, zeros)}.sum, prefix << zeros)}.minBy(_._1)
}
def getSuffixLength(i: Int, prefix: Int) = {
val suffix = i ^ (prefix << (getLength(i) - getLength(prefix)))
getLength(suffix)
}
def getMinOperations(is: List[Int]) = {
val prefix = getPrefix(is)
val maxZeros = getLength(is.max) - getLength(prefix)
val baseCosts = is.map(getSuffixLength(_,prefix)).sum
val suffixLengths: List[(Int, Int)] = is.foldLeft(Map[Int, Int]()){
case (m,i) => {
val x = getSuffixLength(i,prefix) - getLength(i) + getLength(prefix)
m.updated(x, 1 + m.getOrElse(x, 0))
}
}.toList
val (minOp, minSol) = (0 to maxZeros).map{zeros => (suffixLengths.map{
case (x, count) => count * Math.abs(zeros + x)
}.sum, prefix << zeros)}.minBy(_._1)
(minOp + baseCosts, minSol)
}
O(|list|*ld(maxNum) + (ld(maxNum))^2)