【问题标题】:Problem with finding a sole number in an unsorted array在未排序的数组中查找唯一数字的问题
【发布时间】:2020-12-02 16:16:48
【问题描述】:

一种接收数组的方法,该数组是未排序的,由一对相邻的相等数字以及恰好一个没有一对的数字组成。比如——

int [] a = {6,6,18,18,-4,-4,12,9,9};
int [] c = {8,-7,-7,3,3,0,0,10,10,5,5,4,4};

代码必须返回索引和数字本身。

现在的问题是关于时间复杂度的问题,我知道可以通过 O(logn) 来解决这个问题,但我的代码一半有效:

public static int findSingle (int [] a) {
    int high = a.length-1;
    int low = 0;
    int mid = 0;
    int found = 0;
    mid = ((high-low)/2);
    while (mid >= 1) {
        if (a[mid] != a[mid-1])
            low = mid +1;
        mid =((high - low)/2);
        if (mid == 1)
            found = a[mid];
        if (a[mid] == a[mid-1])
            high = mid-1;
        mid = ((high - low)/2);
    }
    return found;
}

现在给定这个数组:

int [] d = {8,8,-7,3,3,0,0,10,10,5,5,4,4};

它说数字在第8个元素,这显然不是真的,在某些数组中它也会出错。有什么问题?

编辑:我注意到我应该将“中”指定为高 + 低/2,但无论如何都不能解决问题。

【问题讨论】:

  • 在这种情况下,您可以对未排序的数组使用二进制搜索,但此代码中存在一些明显的错误。我正在寻找答案。
  • dbl,我说的指令是在数组中找到唯一的数字,时间复杂度为logn。 ThisIsAQuestion,谢谢。
  • 当您说“which is unsorted”时,您的意思是 all 条目可能未排序(例如,{3,1,-2,-2,1,99,3} 是可能的),或者那——就像你的例子一样——这些对是总是相邻的,是pairs是未排序的?
  • @TripeHound,数组总是有对,而且它们总是彼此靠近。例如,{4,4,-2,-2,5} 可行,但 {4,5,4,-2,-2} 不可行。
  • 你需要找到那个号码的号码和索引,哪个没有配对条目?

标签: java arrays methods


【解决方案1】:

您在正确的轨道上,但您的代码存在一些问题。

while (mid >= 1)

为什么 mid 小于或等于 1 您的退出条件?你希望你的退出条件是当你发现你的值可能在你的数组中的任何地方,而不仅仅是在开始时。我将根据highlow 更改退出条件,就像在正常的二分搜索中一样。

mid = ((high-low)/2);

首先,这个公式没有找到highlow中间的数字。这应该是((high+low)/2)。此外,这些列表的性质使得保持mid 的奇偶校验一致非常重要。我将确保mid 保持不变,即使在设置mid 时添加mid += mid%2;

low = mid +1;
...
high = mid-1;

同样,highlow 的奇偶性非常重要。两者都应该始终保持平衡。我们知道mid 是偶数,所以highlow 不应该被mid 偏移+/-1。

if (mid == 1)
    found = a[mid];

这是您代码中最大的问题。首先,您是要查找单个数字的索引还是单个数字的值?您说您正在查找索引,但您的代码正在查找 a[mid] 这是一个值。我下面的代码找到了索引,但这很容易改变。其次,只有在mid 为 1 时才执行此操作。这意味着您的代码将始终返回 0 或 a[1]

还有一些注意事项。没有理由在每个循环中设置两次mid 并检查a[mid] != a[mid-1]a[mid] == a[mid-1]。相反,每个循环设置一次 mid,检查其中一个条件,然后使用 if/else。此外,没有理由使用found。相反,只需在循环退出时使用 highlow 的值,现在它已正确退出。

最终代码:

public static int findSingle (int [] a) {
    int high = a.length-1;
    int low = 0;
    int mid = 0;

    while (high != low) {
        mid = ((high + low) / 2);
        mid += mid%2;

        if (a[mid] != a[mid-1])
            low = mid;
        else
            high = mid - 2;
    }
    return high;
}

我还没有彻底测试过,但从我看过的几个测试用例来看,它似乎是有效的。

编辑:

原来有一个错误(感谢 Alex Rudenko)。固定版本:

public static int findSingle (int [] a) {
    int high = a.length-1;
    int low = 0;
    int mid = 0;
    while (high != low) {
        mid = ((high + low) / 2);
        mid -= mid%2;
        if (a[mid] == a[mid+1])
            low = mid + 2;
        else
            high = mid;
    }
    return high;
}

【讨论】:

  • 祝福你,它确实有效。我的初始代码需要返回值和索引,但我明白为什么它没有返回索引。我不明白的是为什么返回高位会起作用?
  • @Ohande 代码到达return high 行的唯一时间是high == low 这意味着highlow 都在您正在查找的一个数字的索引上因为,就像在传统的二分搜索中一样。如果我的回答对您有所帮助,请不要忘记接受答案和/或投票!
  • 我是用笔和纸做笔记后得到的。我确实赞成你的投票,只是我的声誉显然很低,所以它没有显示它,但它说它已经被记录了!谢谢!另外,要找到索引的值,最好的方法是什么?我想了一个实例来表示它,比如前面代码中的'found'。
  • @AlexRudenko 好收获!我已经使用通过该测试用例的解决方案编辑了我的答案。
  • @dbl 我已经编辑了 OP 的问题以增加清晰度。该算法的复杂度为 O(log(n)),因为循环中的每次迭代都会消除单个数字可能存在的一半位置。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-06-07
  • 1970-01-01
  • 2015-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多