【问题标题】:Find count of a repeated value in a sorted array查找排序数组中重复值的计数
【发布时间】:2014-05-13 22:39:23
【问题描述】:

我只是想知道这段代码是否可以进一步改进。这是一个简单的类,它接受一个排序数组和一个值作为参数,并试图找出这个值在数组中出现的次数。

据我所知,代码的复杂度为 O(log n + k) [假设 k 是 n 的子集]。这段代码可以进一步改进吗?

public class SearchSortedArray {
// Find number count in an array. Total Complexity = O(log n + k) [assuming k is the subset of n] 
public static int findNumberCountInAnArray(List<Integer> array, Integer findValue) {
    //Search Index
    Integer searchIndex = findIndex(array, findValue, 0);
    //Find Count
    return countArray(array, searchIndex);
}

// Search Index. Complexity = O(log n)
private static Integer findIndex(List<Integer> array, Integer findValue, int offset) {
    if(array.size() == 0) {
        return null;
    }
    if(findValue < array.get(array.size()/2)) {
        return findIndex(array.subList(0, array.size()/2), findValue, 0);
    } else if(findValue > array.get(array.size()/2)) {
        offset = offset + array.size()/2;
        return findIndex(array.subList(array.size()/2, array.size()), findValue,  offset);
    }
    return array.size()/2+offset;           
}

// Find count. Complexity = O(k) [assuming k is the subset of n] 
private static int countArray(List<Integer> array, Integer searchIndex) {
    if(null == searchIndex) {
        return 0;
    }
    Integer searchValue = array.get(searchIndex);
    Integer searchIndexStore = searchIndex;
    int count = 0;
    while(searchIndex < array.size() && searchValue == array.get(searchIndex)) {
        count++;
        searchIndex++;
    }
    searchIndex = searchIndexStore;
    while(searchIndex > 0 && searchValue == array.get(searchIndex-1)) {
        count++;
        searchIndex--;
    }
    return count;
}
}

这里是主类

// Test main class. 
public class TestMain {
public static void main(String[] args) {
    Integer[] sample1 = {1, 1, 1, 2, 3, 4, 4, 4, 4, 5, 5, 5}; 
    ArrayList<Integer> arraySample1 = new ArrayList<Integer>(Arrays.asList(sample1));
    // Find the number of times 5 is repeated in the array?
    System.out.println(SearchSortedArray.findNumberCountInAnArray(arraySample1, 5));

    Integer[] sample2 = {1, 1, 2, 3, 3, 4, 5, 8, 8, 9, 9, 10, 10, 14, 18};
    ArrayList<Integer> arraySample2 = new ArrayList<Integer>(Arrays.asList(sample2));   
    // Find the number of times 10 is repeated in the array?
    System.out.println(SearchSortedArray.findNumberCountInAnArray(arraySample2, 10));
  }
}

谢谢。

【问题讨论】:

  • 这可以在 O(2 lg n) = O(lg n) 时间内通过两次二分搜索来完成,与与 key 相等的实际项目数无关。
  • 仅供参考 - O(log n) + O(k) 将是 O(log n + k)。第一个可能在语法上不正确(我不确定你是否可以添加这样的大 O)。
  • 感谢@Dukeling 的纠正。
  • 为什么你有所有的电话到Math.absarray.size()/2 已经是肯定的了。
  • 是的,这是一个错误,感谢@Teepeemm 的更正

标签: java arrays algorithm big-o binary-search


【解决方案1】:

使用两个而不是一个二分搜索:

  1. 首先找到值findValue 的第一次出现。我们称该索引为lo。我相信这就是您的 findIndex 函数的作用。
  2. 然后查找大于findValue 的值的第一次出现,如果不存在该值,则查找n。我们称该索引为hi

现在结果是hi - lo

运行时间:O(log n)。请注意,如果 k 的期望值很小,即在 log(n) 的一个小常数因子内,您的代码实际上可能会更好,因为线性搜索比二分搜索更有缓存效率。

【讨论】:

  • 您可以使用this binary search technique 做得更好。这将 k 大小的线性搜索替换为二分搜索,使其变为 O(log k)。虽然,如果 k 小于 10 左右,它仍然是低效的。
  • 谢谢@Niklas B。我明白了。
猜你喜欢
  • 2016-03-02
  • 1970-01-01
  • 2017-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多