Java smoosh方法有O(n)算法吗?

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

我正在尝试完成一个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)

我可以这样做:

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
}