11

我有一个长度为 10 的数组,其中填充了数字 0-9。

这些数字(大部分)按顺序排列。但是,起始索引处的数字可以是任何数字,并且数字是升序还是降序是未知的(一旦达到最小/最大数字,数字就会环绕 - 一旦达到 9,则为 0,反之亦然)。

这些数字中恰好有一个不按顺序排列(就好像它被拔出并随机插入到数组中一样)。

例子:

[4, 3, 1, 0, 9, 8, 7, 2, 6, 5]

索引 7 处的数字 2 出现故障。索引 1 和 2 之间的数字“差距”是可以的,数字 3 或 1 都不会被认为是乱序的。

查明乱序号索引的最佳方法是什么?

更多示例 - 不合适的数字标有 *:

[2, 3, *0, 4, 5, 6, 7, 8, 9, 1]
[5, 6, 7, 9, *8, 0, 1, 2, 3, 4]
[7, 6, 5, 4, 3, *8, 2, 1, 0, 9]
[0, *5, 1, 2, 3, 4, 6, 7, 8, 9]
[4, 3, *0, 2, 1, 9, 8, 7, 6, 5] 
4

8 回答 8

3

查看所有其他元素,并计算差异。

如果大多数差异为正,则顺序为升序。如果大多数为负数,则为下降;它可以像其他情况一样确定,我不会进一步研究它。

当然,您需要环绕并计算第 (N-1) 个和第 0 个元素之间的差异,或者其他什么。

从现在开始看模数 N 的差异。

如果 diff 为 2,这是没有额外或缺失元素的常规情况;忽略它。

如果 diff 为 3,则表示从这里的某个地方拉出了一个元素。但我们不是在寻找它的老地方,而是在寻找它的新地方;也忽略这个。

如果 diff 为 1,则乱序元素在这些数字之间。

如果您有任何其他差异,那么您必须让其中两个彼此相邻。乱序元素是产生这两种差异的元素。

在两个连续数字交换的情况下,任何一个都可以被认为是乱序的。产生的差异将是 (1,3) 或 (3,1) 彼此相邻。此方法选择两个可能的答案之一。

对于有问题的数组:

array -> 2 3 0 4 5 6 7 8 9 1(2)        
          \ / \ / \ / \ / \ /
diffs ->  -2   5   2   2   -7(=3 mod 10)
             *

在进一步的示例中,我不会说明相等 mod 10 以节省空间。

array -> 5 6 7 9 8 0 1 2 3 4(5) 
          \ / \ / \ / \ / \ /
diffs ->   2   1   3   2   2
               *

array -> 7 6 5 4 3 8 2 1 0 9(7)        
          \ / \ / \ / \ / \ /
diffs ->  -2  -2  -1  -2  -3
                   *

array -> 0 5 1 2 3 4 6 7 8 9(0)        
          \ / \ / \ / \ / \ /
diffs ->   1   2   3   2   2
           *

array -> 4 3 0 2 1 9 8 7 6 5(4)       
          \ / \ / \ / \ / \ /
diffs ->  -4  -9  -3  -2  -2
             *    

更多示例:

array -> 0 2 1 3 4 5 6 7 8 9(0)        swapped adjacent elements, case 1
          \ / \ / \ / \ / \ /
diffs ->   1   3   2   2   2
           *

array -> 0 1 3 2 4 5 6 7 8 9(0)        swapped adjacent elements, case 2
          \ / \ / \ / \ / \ /
diffs ->   3   1   2   2   2
               *

array -> 0 2 3 4 5 6 7 1 8 9(0)        element removed and inserted at odd pos
          \ / \ / \ / \ / \ /
diffs ->   3   2   2   1   2
                       *

array -> 0 2 3 4 5 6 1 7 8 9(0)        element removed and inserted at even pos
          \ / \ / \ / \ / \ /
diffs ->   3   2   6   7   2
                     *

array -> 0 7 1 2 3 4 5 6 8 9(0)        element removed and inserted at odd pos
          \ / \ / \ / \ / \ /
diffs ->   1   2   2   3   2
           *            

array -> 0 1 7 2 3 4 5 6 8 9(0)        element removed and inserted at even pos
          \ / \ / \ / \ / \ /
diffs ->   7   6   2   3   2
             *
于 2013-05-20T05:43:59.050 回答
3

要查找无序的数字,您必须查看数组中的每个元素。因此,您必须以复杂度 O(n) 遍历整个数组。

当你遍历数组时,你应该

  • 计算前一个数字与当前数字之差的绝对值。
  • 计算当前数字与下一个数字之差的绝对值

如果上述两个差值均大于 1 且不等于 n-1(当差值为 n-1 时,即您的数组翻转的点),则该数字是无序的。

于 2013-05-20T02:58:15.367 回答
2

以下人为设计的示例没有唯一的解决方案。您需要决定在这些情况下会发生什么:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9 // first item move to end

2, 1, 3, 4, 5, 6, 7, 8, 9, 0 // adjacent items swapped 

对于所有其他情况,幸运的是,“乱序”项目与其邻居的距离将超过 1(因为上面的#2)

for (i = 0; i < arr.length; i++) {
    int priorIndex = (i-1) % arr.length;
    int nextIndex = (i+1) % arr.length;
    int diffToPriorValue = abs(arr[i] - arr[priorIndex]);
    int diffToNextValue = abs(arr[i] - arr[nextIndex]);
    if (diffToPriorValue > arr.length/2)
        diffToPriorValue = arr.length - diffToPriorValue; // wrap-around
    if (diffToNextValue > arr.length/2)
        diffToNextValue = arr.length - diffToNextValue; // wrap-around
    if (diffToPriorValue != 1 && diffToNextValue != 1)
        return i;
return -1;
于 2013-05-20T04:01:56.227 回答
2

这是一个类似于 Khalid 的解决方案。

如果两个元素可以彼此相邻而无需换行,则它们被认为是相邻的。所以90被认为是相邻的元素。

该算法循环遍历每组三个连续元素,并检查第一个和第三个是否相邻。如果它们是相邻的,那么中间的值一定是乱序的。

我将给定的列表加入到自身中,从而创建一个大小为 20 的数组。这处理了将数字移动到列表开头或结尾的特殊情况。

# checks if two given numbers are adjacent or not, independent of wrapping
def adjacent?(a, b)
  (a - b).abs == 1 || [a, b].sort == [0, 9]
end

# finds the misplaced number in a list
def misplaced_number(list)
  middle_index = 1
  (list + list).each_cons(3).find { |first, second, third|
    adjacent?(first, third)
  }[middle_index]
end

通过以下测试进行了检查。由于模棱两可,第二次也是最后一次测试失败了。

test([2, 3, 0, 4, 5, 6, 7, 8, 9, 1], 0)
test([5, 6, 7, 9, 8, 0, 1, 2, 3, 4], 8) # [FAIL: result = 9]
test([7, 6, 5, 4, 3, 8, 2, 1, 0, 9], 8)
test([0, 5, 1, 2, 3, 4, 6, 7, 8, 9], 5)
test([4, 3, 0, 2, 1, 9, 8, 7, 6, 5], 0)
test([2, 4, 5, 6, 7, 8, 9, 0, 1, 3], 2) # [FAIL: result = 3]

def test(list, expected)
  result = misplaced_number(list)
  assert result == expected_value, "Got #{result} but expected #{expected} from list #{list}"
end
于 2013-05-20T10:01:14.483 回答
2

首先,我将从定义什么是“乱序”开始:

Suppose we have a list of numbers A

If there exist A[i] in A,
Such that A[i-1] <= A[i] <= A[i+1], then A[i] is "in order"
Otherwise, A[i] is "out of order"

算法

FOR i: 1..SIZE(A) DO

    PRINT " "
    PRINT A[i]

    IF A[i-1] <= A[i] <= A[i+1]
    THEN
        CONTINUE
    ELSE
        PRINT "*"
        REMOVE A[i]
    END-IF

END-FOR

测试

INPUT: { 2, 3, 0, 1, 2, 3, 5, 6, 7, 8, 9, 1 }

OUTPUT: { 2, 3, 3, 5, 6, 7, 8, 9 }

CONSOLE: 2 3 0* 1* 2* 3 5 6 7 8 9 1*
于 2013-05-20T08:18:31.623 回答
1

所以在 Haskell 中结合 srikanta 和 nm 的:

import Data.List (findIndex)

f s = maybe (-1) (+1) . findIndex (==1)
    $ zipWith (\a b -> abs (a - b)) s (drop 2 s ++ take 2 s)


*Main> f [2,3,0,4,5,6,7,8,9,1]
2
*Main> f [5,6,7,9,8,0,1,2,3,4]
3
...
于 2013-05-22T16:15:42.177 回答
1
#include <stdio.h>

int main(void)
{
int array[10] = { 4, 3, 1, 0, 9, 8, 7, 2, 6, 5};

size_t idx;
int diff, state,this,next;

#define COUNT (sizeof array/sizeof array[0])
#define FOLD(n,i) ((i)%(n))
#define FETCH(a,i) a[FOLD(COUNT,(i))]

this = FETCH(array,COUNT-1);
next = FETCH(array,0);
diff = next - this;
state = (diff < -1 || diff >1) ? 1: 0;
for (idx = 0; idx < COUNT; idx++) {
        this = next;
        next = FETCH(array,idx+1);
        diff = next - this;
        state = (state<<1) & 3;
        state |= (diff < -1 || diff >1) ? 1: 0;
        if (state==3) putc('*', stdout);
        printf("%d ", this );
        }
putc('\n', stdout);
return 0;
}

输出:

4 3 1 0 9 8 7 *2 6 5
于 2013-05-23T00:02:09.110 回答
0
int element, backdiff, forwarddiff;
boolean elementFound = false;

if(abs(a[0] - a[1]) == 2 )
    return "Out of Order Element is @ position" + (a[0] - a[1] > 0 ? 0 : 1);
for (i=1;i<n;i++){
    if(!elementFound){
        backdiff = abs(a[i-1] - a[i]);
        forwarddiff = abs(a[i+1] - a[i]);
        if( (backdiff == 1 && forwarddiff == 1) || 
            (backdiff == n-1 && forwarddiff == 1) ||
                (backdiff == 1 && forwarddiff == n-1) )
            continue;
        if(forwarddiff == 2 || backdiff == 2)
            element = abs(a[i]-(a[i-1]+a[i+1]));
            elementFound = true;

        if(forwarddiff > 2 || backdiff > 2)
            return "Out of Order Element is @ position" + (forwarddiff > 2 ? (i+1) : i);

    } else {
        if(a[i] == element)
            return "Out of Order Element is @ position" + (i);
    }   
}
于 2013-10-03T01:11:20.740 回答