簡體   English   中英

從排序數組中查找小於O(n)的唯一數字

[英]Finding unique numbers from sorted array in less than O(n)

我接受了采訪,有以下問題:

在小於O(n)的時間內從排序的數組中查找唯一的數字。

 Ex: 1 1 1 5 5 5 9 10 10 Output: 1 5 9 10 

我給出了解決方案,但那是O(n)。

編輯:排序的數組大小約為200億,唯一數字約為1000。

我不認為它可以在少於O(n)的情況下完成。 假設數組包含1 2 3 4 5 :為了獲得正確的輸出,必須查看數組的每個元素,因此O(n)。

分而治之

  • 查看排序序列的第一個和最后一個元素(初始序列是data[0]..data[data.length-1] )。
  • 如果兩者相等,則序列中唯一的元素是第一個(無論序列有多長)。
  • 如果不同,則將序列分開並重復每個子序列。

在平均情況下以O(log(n))求解,而在最壞的情況下(當每個元素不同時)求解O(n)。

Java代碼:

public static List<Integer> findUniqueNumbers(int[] data) {
    List<Integer> result = new LinkedList<Integer>();
    findUniqueNumbers(data, 0, data.length - 1, result, false);
    return result;
}

private static void findUniqueNumbers(int[] data, int i1, int i2, List<Integer> result, boolean skipFirst) {

    int a = data[i1];
    int b = data[i2];

    // homogenous sequence a...a
    if (a == b) {
        if (!skipFirst) {
            result.add(a);
        }
    }
    else {
        //divide & conquer
        int i3 = (i1 + i2) / 2;
        findUniqueNumbers(data, i1, i3, result, skipFirst);
        findUniqueNumbers(data, i3 + 1, i2, result, data[i3] == data[i3 + 1]);
    }
}

如果您排序的大小為n數組有m不同的元素,則可以執行O(mlogn)

注意,當m << n (eg m=2 and n=100)時,這將是有效的

算法:

初始化:當前元素y = first element x[0]

步驟1:二進制搜索x最后一次出現的y (可以在O(log(n))時間內完成。讓它的索引為i

步驟2: y = x[i+1]並轉到步驟1

編輯:在m = O(n)情況下,該算法將會運行得很糟糕。 為了減輕它,你可以與常規的O(n)算法並行運行它。 元算法由我的算法和並行運行的O(n)算法組成。 當兩個算法中的任何一個完成時,元算法停止。

由於數據由整數組成,因此在任意兩個值之間可能存在有限數量的唯一值。 因此,首先查看數組中的第一個和最后一個值。 如果a[length-1] - a[0] < length - 1 ,則會有一些重復值。 a[0]a[length-1]放入一個像散列集一樣的常量訪問時容器中。 如果這兩個值相等,那么您可以知道數組中只有一個唯一值,您就完成了。 您知道數組已排序。 因此,如果兩個值不同,您現在可以查看中間元素。 如果中間元素已經在值集中,則您知道可以跳過數組的整個左側部分,並且只能遞歸地分析右側部分。 否則,遞歸地分析左右兩部分。

根據數組中的數據,您將能夠在不同數量的操作中獲取所有唯一值的集合。 如果所有值都相同,則在恆定時間O(1)得到它們,因為在僅檢查第一個和最后一個元素之后您將知道它。 如果“相對較少”的唯一值,您的復雜性將接近於O(log N)因為在每個分區之后,您將“經常”能夠丟棄至少一半分析的子陣列。 如果值都是唯一的並且a[length-1] - a[0] = length - 1 ,您還可以在恆定時間內“定義”該集合,因為它們必須是從a[0]a[length-1] a[0]連續數字a[length-1] 但是,為了實際列出它們,您必須輸出每個數字,並且它們中有N個。

也許有人可以提供更正式的分析,但我估計這個算法在唯一值的數量上大致是線性的而不是數組的大小。 這意味着如果只有很少的唯一值,即使對於一個龐大的數組,也可以在很少的操作中得到它們(例如,如果只有一個唯一值,則無論數組大小如何都在恆定時間內)。 由於唯一值的數量不比數組的大小大,我聲稱這使得該算法“優於O(N)”(或嚴格地說:“不比O(N)差,在許多情況下更好” )。

import java.util.*;

/**
 * remove duplicate in a sorted array in average O(log(n)), worst O(n)
 * @author XXX
 */
public class UniqueValue {
    public static void main(String[] args) {
        int[] test = {-1, -1, -1, -1, 0, 0, 0, 0,2,3,4,5,5,6,7,8};
        UniqueValue u = new UniqueValue();
        System.out.println(u.getUniqueValues(test, 0, test.length - 1));
    }

    // i must be start index, j must be end index
    public List<Integer> getUniqueValues(int[] array, int i, int j) {
        if (array == null || array.length == 0) {
            return new ArrayList<Integer>();
        }
        List<Integer> result = new ArrayList<>();
        if (array[i] == array[j]) {
            result.add(array[i]);
        } else {
            int mid = (i + j) / 2;
            result.addAll(getUniqueValues(array, i, mid));

            // avoid duplicate divide
            while (mid < j && array[mid] == array[++mid]);
            if (array[(i + j) / 2] != array[mid]) {
                result.addAll(getUniqueValues(array, mid, j));
            }
        }
        return result;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM