Java smoosh方法有O(n)算法吗?
我正在尝试完成一个smoosh()方法,该方法将接受一个int数组。完成后,数组仍应包含相同的数字,但如果数组中有两个或多个连续的重复数字,它们将替换为该数字的一个副本。因此,, 完成smoosh()后,数组中没有两个连续的数字是相同的 数组末尾的所有未使用元素都设置为-1 例如,如果输入数组是Java smoosh方法有O(n)算法吗?,java,algorithm,Java,Algorithm,我正在尝试完成一个smoosh()方法,该方法将接受一个int数组。完成后,数组仍应包含相同的数字,但如果数组中有两个或多个连续的重复数字,它们将替换为该数字的一个副本。因此,, 完成smoosh()后,数组中没有两个连续的数字是相同的 数组末尾的所有未使用元素都设置为-1 例如,如果输入数组是 [ 1 1 0 0 4 4 5 0 0 0 7 ] 上面写着 [ 1 0 4 5 0 7 ] smoosh()完成后 方法签名为: 公共静态无效smoosh(int[]int) 我可以这样做: f
[ 1 1 0 0 4 4 5 0 0 0 7 ]
上面写着
[ 1 0 4 5 0 7 ]
smoosh()完成后
方法签名为:
公共静态无效smoosh(int[]int)
我可以这样做:
for (int i=0; i<ints.length-1; i++) {
if (ints[i+1]==ints[i])
ints[i]=-1;
}
for (int i=0; i<ints.length-1; i++) {
if (ints[i]==-1) {
for (int j=i+1; j<ints.length; j++) {
if (ints[j]!=-1) {
//swap ints[j] and ints[i] and then break;
}
}
}
}
for(inti=0;i基本上如下所示。这个O(n)-时间,O(1)-空间“算法”实际上是Python代码,因为这是教授基本算法的一种非常好的语言,只要你避免所有复杂的东西,比如lambdas
实际上,我正在用它来教我8岁的儿子,因为他对我整天在工作中所做的事表示了兴趣
array = [1, 1, 0, 0, 4, 4, 5, 0, 0, 0, 7]
print array
count = len (array)
last = array[0] - 1
toidx = 0
for fromidx in range (0, count):
if array[fromidx] != last:
array[toidx] = array[fromidx]
toidx = toidx + 1
last = array[fromidx]
while toidx < count:
array[toidx] = -1
toidx = toidx + 1
print array
按照您的规格要求
它基本上在数组中运行两个索引,fromix
索引无论如何都会前进一个。toidx
索引只有在fromidx
处的值与上次传输的值不同时才会前进。上次传输的初始值被设置为与第一个元素不同的值,以确保第一个元素被转移
换言之,在该条件为真的每次迭代中,from
索引处的值被复制到toidx
索引中,toidx
索引增加,last
值被更新。如果fromidx
处的值与上次传输的值相同,则toidx
索引不被复制更新
然后,在最后,所有剩余的值都设置为-1
因为您的规范要求数组的其余部分填充-1,所以我在上面的代码中就是这么做的
但是,示例结果不包含负值,因此,如果需要截断数组而不是填充-1
,则基本上可以用数组截断来替换,而循环的末尾是,因此它的大小现在是toidx
在Python中,您可以通过以下方式实现:
array = array[0:toidx]
不需要内部循环。只需跟踪上次访问的值,然后开始跳过,直到找到“新”编号。例如,在伪代码中
previous = null;
newarray = array();
newpos = 0;
for (i = 0; i < oldarray.length; i++) {
if (oldarray[i] == previous) {
continue; // got a duplicate value, so skip it.
} else {
newarray[newpos++] = oldarray[i];
previous = oldarray[i];
}
}
for (i = newpos; i < oldarray.length; i++) {
newarray[i] = -1; // fill in any empty slots
}
previous=null;
newarray=array();
newpos=0;
对于(i=0;i
现在您只剩下O(n)。如果您使用链接列表
,您可以使用列表迭代器
进行循环,将前一个值的值存储在列表中并调用列表迭代器。如果它等于当前值,请删除它。如果代码不完整,则有一个O(n)就地算法,但没有时间为您编写if。提示-您需要跟踪两个不同的索引….+1-用于使用python。OP将通过将其翻译为Java来了解更多信息。+1-感谢您的精彩解释!因此,基本上您在进行比较时使用单独的索引进行移动。非常好的主意!不完全是s与其他答案相比,我赢得了这个答案……:P但我自己辩护说,我更喜欢清晰、实用的解决方案,它只起作用。(并不是说学习“接近金属”的算法没有任何价值)@用户1660652,顺便说一句,这是在不了解库的实现的情况下使用库的问题。ArrayList.remove本身就是一个O(n)操作,因为它在该点上方的数组元素周围移动。通过在迭代器中执行此操作,此解决方案是O(n^2),而不是O(n).现在Kiyura是正确的,有时使用给定的工具会更好,但您确实需要理解其中的含义。请参阅@paxdiablo,如果我参考了ArrayList.remove
,您肯定是正确的。我没有。我的解决方案是O(n)。实际上,我不确定ListIterator.remove
是否为O(1)w.r.t.ArrayList;它可能需要一个LinkedList实例为常数时间。我忘记了这一部分。抱歉!我编辑了我的答案来反映这一点。Kiyura,ArrayList.remove()
肯定是O(n),它里面有一个arraycopy(无论如何,在openjdk源代码中)将其余元素向下移动。LinkedList是remove
的更好选择,尽管将get
从O(1)更改为O(n)是要付出代价的。当然,所有这些都无关紧要,除非列表的大小很大,或者使用了很多:-)除非是这样,否则我会像您一样使用Java集合。只有当您确定这是一个特定的性能问题时,我才会求助于自己的滚动。
previous = null;
newarray = array();
newpos = 0;
for (i = 0; i < oldarray.length; i++) {
if (oldarray[i] == previous) {
continue; // got a duplicate value, so skip it.
} else {
newarray[newpos++] = oldarray[i];
previous = oldarray[i];
}
}
for (i = newpos; i < oldarray.length; i++) {
newarray[i] = -1; // fill in any empty slots
}