数组中的十进制主数

时间:2012-03-07 10:18:16

标签: arrays algorithm

最近我遇到了这个采访问题:

在数组中给出n个实数。如果数组中的数字超过n / 10次,则数组中的数字称为十进制显性。给出O(n)时间算法以确定给定数组是否具有十进制显性。

现在我可以想出几种方法来解决这个问题,以及对这个问题的任何概括(即找出在数组中出现K次的任何数字)

可以在第1遍中创建哈希表,然后计算第2遍中的出现次数,即O(n),但也使用O(n)空间,

有一种方式using 9 buckets

但是,我们有什么方法可以在一个恒定的空间里做到这一点?有什么建议??

[编辑]我没有检查过9桶解决方案,读者可能想通过下面的n.m.评论

6 个答案:

答案 0 :(得分:8)

我已经概述了一种基于Boyer-Moore多数投票算法here的方法。

你记得(最多)(m-1)元素,这些元素最近比其他元素和相关数量更常见。当看到记住的元素时,其计数会增加。当看到一个未记忆的元素时,如果有一个空闲的插槽,你会记住它并将其计数设置为1,否则你从记忆元素的所有计数中减去1。忘记了计数为0的记忆元素。任何比例高于1/m的元素都是记忆元素之一。如果您不知道有m-1个元素出现超过n/m次的先验,则需要第二遍来计算记住元素的出现次数。

编辑:在访问指定的页面后,我发现它是完全相同的解决方案,但它没有考虑到记住的非支配者。

  

一旦完成,任何计数大于1的计数变量在列表中都有超过10个自身实例。

不正确,但最后会记住所有小数统治者的计数>= 1。 我没有通过那里的代码,所以它可能包含错误,但算法是正确的,除了缺少检查通行证。

如果我们有第二遍,状态演变

,则正确处理拟议的反例
0 1 2 3 4 5 6 7 8
1 1 1 1 1 1 1 1 1   // coming 9
0 0 0 0 0 0 0 0 0   // all forgotten, no slots occupied, coming 10
10 - - - - - - - -
 1 - - - - - - - -  // coming 0
10 0 - - - - - - - 
 1 1 - - - - - - -

最后,有两个插槽被占用,10和0都被记住,计数为1. 10不是十进制显性,但是0是,并且它是唯一的,因为将由第二次检查通行证。

答案 1 :(得分:1)

public static int[] KthDominants(int[] arr, int kth)
    {
        var data = new Dominants(arr.Length, kth);
        for (int i = 0; i < arr.Length; i++)
        {
            data.Push(arr[i]);
        }
        return data.ToArray();
    }

Dominants类将kth-1计数器存储在Dictionary中。它使用System.Linq来处理集合。

public class Dominants
{
    int _size;
    int _kth;
    int _grade;
    Dictionary<int, int> _counters;

    public Dominants(int size, int kth)
    {
        _size = size;
        _kth = kth;
        _counters = new Dictionary<int, int>();
    }

    public void Push(int key)
    {
        if (_counters.ContainsKey(key))
            _counters[key]++;
        else
        {
            // The trick is that the dominant element remains same 
            // if you delete any k distinct items from the array.
            if (_counters.Count < _kth)
                _counters.Add(key, 1);
            else
            {
                foreach (var i in _counters.Keys.ToArray())
                {
                    if (_counters[i] > 1)
                        _counters[i]--;
                    else
                        _counters.Remove(i);
                }
                _grade++;
            }
        }
    }

    public int[] ToArray()
    {
        var cnt = _size / _kth - (_grade + 1);
        return _counters
            .Where(i => i.Value > cnt)
            .Select(i => i.Key)
            .ToArray();
    }
}

github

答案 2 :(得分:1)

您可以使用 3-way-partition 快速选择来查找数组的第(n / 10)个最大元素,然后检查它是否为十进制 - 优势;如果没有,则在右子阵列中重现。

这可以在线性预期时间内就地完成,因此不是严格恒定的空间。

答案 3 :(得分:1)

使用3向qSort Java实现打印

public class DecimalDominants {
    public static void sort(Comparable[] arr) {
        sort(arr, 0, arr.length - 1);
    }

    private static void sort(Comparable[] arr, int lo, int hi) {
        if (lo >= hi) return;
        int lt = lo, gt = hi;
        Comparable v = arr[lo];
        int i = lo;
        while (i <= gt) {
            int cmp = arr[i].compareTo(v);
            if (cmp < 0) swap(arr, lt++, i++);
            else if (cmp > 0) swap(arr, i, gt--);
            else i++;
        }
        int times = gt - lt + 1;
        if (times > arr.length / 10) System.out.printf("%s repeats %d times\n", v, times);
        sort(arr, lo, lt - 1);
        sort(arr, gt + 1, hi);
    }

    private static void swap(Comparable[] arr, int i, int j) {
        Comparable swap = arr[i];
        arr[i] = arr[j];
        arr[j] = swap;
    }

    public static void main(String[] args) {
        Integer[] arr = {1, 2, 1, 2, 1, 2, 1, 4, 3, 2, 4, 2, 3, 5, 6, 7, 8, 9, 3, 2, 4, 5, 2, 3, 6, 7, 8, 3, 2, 5};
        System.out.println("print numbers which repeat more then " + arr.length / 10);
        sort(arr);
    }
}

答案 4 :(得分:0)

  1. 执行循环并将值存储/添加到实数数组int []中。

  2. 执行另一个循环,如果数组列表值大于1,则将数组列表值除以10。

答案 5 :(得分:0)

具有线性时间复杂度和恒定空间复杂度的三向排序。 最糟糕的情况是,该递归调用将进行10次

def three_way_partition(arr, start, end, dominants):
    if (end - start + 1) >= int(len(arr)/10):
        lt = start
        gt = end
        i = lt
        while True:
            if arr[i] < arr[lt]:
                arr[lt], arr[i] = arr[i], arr[lt]
                i += 1
                lt += 1
            elif arr[i] > arr[lt]:
                arr[gt], arr[i] = arr[i], arr[gt]
                gt -= 1
            else:
                i += 1
            if i > gt:
                break
        if gt - lt + 1 > int(len(arr)/10):
            dominants.append(arr[lt])
        three_way_partition(arr, start, lt-1, dominants)
        three_way_partition(arr, gt + 1, end,  dominants)


def decimal_dominants(arr):
    dominants = []
    three_way_partition(arr, 0, len(arr)-1, dominants)
    return dominants