只找到一个百万(s)数的重复数字

时间:2015-10-11 12:42:45

标签: java algorithm duplicates adobe puzzle

最近在adobe采访中向我提出了这个难题: - 有一个包含数百万个无序正数的数组,其中所有元素都是不同的,除了一个恰好出现两次的数字。动机是以最佳方式找到两次出现的数字。

P.S。绝对没有订单/模式适用于数组。

面试官拒绝了任何形式的可能性,因为这需要花费很多时间,他想要提出质疑,然后提出一个更聪明的解决方案。

3 个答案:

答案 0 :(得分:4)

第一种方法是对数组进行排序,然后遍历排序数据,直到找到两个相同的连续数字。这可以在O(n log n)时间和O(1)空间轻松完成。

如果面试官随后询问是否有更好的方法,那么您将讨论可能对数据的任何限制(订单/模式不是必然意味着对数据没有任何限制)。你还应该通过最优来质疑他们实际上意味着什么 - 如果没有数量的测量,这个词本身意味着很少。

有些人优化时间,有些人为空间优化,有些人(如我自己)甚至优化代码可读性: - )

在讨论限制方面,一个例子是数字的范围是否限制在几百万。然后,创建一个计数数组并在O(n)时间处理所有数据将是一件简单的事情:

dim array[several million] as zero
for each number:
    array[number]++
    if array[number] == 2:
        print number
        stop

即使没有这样的限制,32位数字范围也可以使用40亿左右的数组(大约500M),这是你经常交易空间的经典例子。

请记住,面试问题不是要弄清楚你是否有针对特定问题的解决方案,他们就是这样,面试官可以看到你的思维过程。通常情况下,你最大的资产不是对算法的百科全书知识,而是你能够聪明地思考问题以及如何解决问题。

答案 1 :(得分:4)

通过将数值散列到集合中的单个顺序传递数组将告诉我重复。这是O(n),但是使用HashSet的内存和数据结构。 Hashing的最坏情况在第一个和最后一个位置是重复的。

甚至高达25M整数的排序很快,约为2秒,并且 - 尽管O(n log n) - 具有相对恒定的时间,并且比最差的散列情况快得多。 OTOH,哈希可以击败排序,以及下一个方法: -

最快的是使用BitMap来记录数字(~1秒),虽然这可能需要相当大的内存量((0x7FFF_FFFF + 1)/ 8 - 即非负整数除以每字节的位数) ,但这里的分配很简单。同样,最糟糕的情况是在第一个和最后一个地方重复。

这是我用来比较的代码。我应该小心谨慎,就像Java中的大多数天真基准一样。但它表明代码可读性不是任何方法的问题。

public class Duplicate {
    public static void main(String[] args) throws Exception {
        Random r = new Random( 100L );
        int[] a = new int[25000000];
        Set<Integer> set  = new HashSet<>(a.length/2);
        boolean dupl = true;
        for( int i = 0; i < a.length; ){
            int x = Math.abs( r.nextInt() );
            if( set.add( x ) ){
                a[i++] = x;
            }
        }
        a[a.length-1] = a[0]; // Worst case for HashSet and BitSet
        set = null;

        System.out.println( "hash " + new Date() );
        set  = new HashSet<>();
        for( int i = 0; i < a.length; ++i ){
            if( ! set.add( a[i] ) ){
                System.out.println( a[i] );
                break;
            }
        }
        set = null;

        System.out.println( "bitmap " + new Date() );
        BitSet bs = new BitSet( 0x7FFF_FFFF ); 
        for( int i = 0; i < a.length; ++i ){
            if( bs.get( a[i]-1 ) ){
                System.out.println( a[i] );
                break;
            }
            bs.set( a[i]-1 );
        }

        System.out.println( "sort "  + new Date());
        Arrays.sort( a );
        for( int i = 1; i < a.length; ++ i ){
            if( a[i] == a[i-1] ){
                System.out.println( a[i] );
                break;
            }
        }
        System.out.println( "done " + new Date() );
    }
}

稍后请注意,Java 8具有Arrays.sortParallel。鉴于你有硬件,这将进一步减少排序时间。 - 另请注意,位设置方法基于规范“正数”。如果要包含负数,这会使事情变得复杂,但我怀疑采访者想要了解候选人的“流利性”w.r.t. Java的java.util资源。

答案 2 :(得分:0)

由于数据未排序,您必须根据剩余(n-1)检查每个数字,从而检查O(n ^ 2)。他们要求这种算法的时间复杂度小于O(n ^ 2)。为此,您需要树或哈希表。如果您对该数据进行排序&amp;然后应用任何算法,那将是更耗时的过程。对于树和树哈希表你需要O(n)。因为它们最适合安排数据和找到数据。