Algorithm 在一维数组中寻找有界最近邻

Algorithm 在一维数组中寻找有界最近邻,algorithm,performance,sorting,computer-science,complexity-theory,Algorithm,Performance,Sorting,Computer Science,Complexity Theory,假设我们有一些布尔值数组: A = [0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 0 1 1 1 1 0 0 0 ... 0] 数组是通过对数据流执行分类来构造的。数组中的每个元素都对应于给定一小块数据的分类算法的输出。答案可能包括重新构造数组以提高解析效率 该数组是伪随机的,即1和0的组倾向于成束存在(但不一定总是) 给定一些索引,i,找到最接近A[i]的至少n零组的最有效方法是什么?对于简单的情况,取n=1 编辑:组应至少有n个零。同样,对于简单的情况,

假设我们有一些布尔值数组:

A = [0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0 0 1 1 0 1 1 1 1 0 0 0 ... 0]
数组是通过对数据流执行分类来构造的。数组中的每个元素都对应于给定一小块数据的分类算法的输出。答案可能包括重新构造数组以提高解析效率

该数组是伪随机的,即
1
0
的组倾向于成束存在(但不一定总是)

给定一些索引,
i
,找到最接近
A[i]
的至少
n
零组的最有效方法是什么?对于简单的情况,取
n=1

编辑:组应至少有n个零。同样,对于简单的情况,这意味着至少1个零


EDIT2:此搜索将执行
o(n)
次,其中
n
是数组的大小。(具体地说,它的
n/c
,其中
c
是某个固定的持续时间。

如果在大小为n的数组上有n个查询,那么简单的方法将花费O(n^2)时间

您可以通过合并观察结果来优化这一点,即不同的组大小的数量按sqrt(n)的顺序排列,因为如果我们有一组大小为1、一组大小为2、一组大小为3,依此类推,我们得到的最不同的组大小是1+2+3+…+n是n*(n+1)/2,因此按n^2的顺序排列,但数组的大小为n,因此不同组大小的数量按sqrt(n)的顺序排列

  • 创建一个大小为n的整数数组,以指示哪些组大小出现了多少次

  • 为0组创建一个列表,每个元素应包含组大小和起始索引

  • 扫描阵列,将0组添加到列表中,并更新当前组大小

  • 为不同的组大小创建一个数组,每个条目应包含组大小和一个带有组开始索引的数组

  • 通过扫描当前组大小的数组,创建一个整数数组或一个映射,告诉您哪个组大小位于哪个索引

  • 浏览0组列表并填充在4处创建的起始索引数组

  • 我们最终得到一个数组,该数组占用O(n)个空间,需要O(n)个时间来创建并按顺序包含所有当前组大小,此外,每个条目都有一个数组,其中包含该大小组的开始索引

    为了回答一个查询,我们可以对大于或等于给定最小组大小的所有组的开始索引进行二进制搜索。这需要O(log(n)*sqrt(n))并且我们做了n次,因此总体上需要
    O(n*log(n)*sqrt(n))=O(n^1.5*log(n))
    这比O(n^2)好

    我认为你可以通过创建一个结构来将其归结为O(n^1.5),该结构具有所有不同的组大小,但不仅包含该大小的组,还包含大于该大小的组。这将是创建该结构的时间复杂性,并且回答所有n个查询将更快O(n*log(sqrt(n))*log(n))我想,所以没关系

    例如:

    [0 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0, 1, 0, 0]   -- 0 indexed array
    
    hashmap = {1:[0], 2:[15, 18], 7:[5]}
    
    search(i = 7, n = 2) {
       binary search in {2:[15, 18], 7:[5]}
       return min(15, 5)
    }
    

    在这个解决方案中,我组织数据,以便您可以使用二进制搜索
    O(logn)
    来查找至少具有一定大小的最近组

    我首先从数组中创建一组零,然后将每组零放入包含大小
    s
    或更大的所有组的列表中,这样当您想要查找最近的一组大小为
    s
    或更大的组时,您只需在列表中运行一个二进制搜索,该列表包含大小为
    s
    或更大的所有组

    缺点是在将组放入列表的预处理过程中,
    O(n*m)
    (我想,请检查我)的时间和空间效率,
    n
    是零组的数量,
    m
    是组的最大大小,尽管实际上效率可能更好

    代码如下:



    publicstaticvoidmain(字符串[]args){
    字节[]byteArray=null;
    List groups=Group.getGroupsOfZeros(byteArray);
    GroupsBySize GroupsBySize=新的GroupsBySize(组);
    int指数=12;
    int-atLeastSize=5;
    g组=groupsBySize.GetNearestGroupofAtlestSize(索引,AtlestSize);
    System.out.println(“最近的组为“+g.x1+”:“+g.x2+”),大小为“+g.size”);
    }
    
    找到最接近A[i]的至少n个零的组的最有效方法是什么

    如果我们不受预处理时间和资源的限制,最有效的方法似乎是
    O(1)
    时间和
    O(n*sqrt n)
    空间,存储所有可能查询的答案。(要实现这一点,请运行下面的算法,列出所有可能的查询,即数组中与每个索引成对的每个不同的零组大小。)

    如果一次向我们提供所有的
    n/c
    查询,我们可以在
    O(n log n)
    时间内生成完整的结果集

    从左侧遍历一次,从右侧遍历一次。对于每次遍历,从一个平衡的二叉树开始,查询按零组大小排序(查询中的
    n
    ),其中每个节点都有一个已排序的查询索引列表(所有
    i
    s以及此特定的
    n

    在每次迭代中,当注册一个零组时,更新所有查询,使
    n
    等于并小于此零组大小,从节点中删除所有相等和较低的索引,并保留它们的记录(由于索引列表已排序,我们只需在其等于或低于当前索引时删除列表的标题),并将零组的当前索引也存储在节点中(“上次看到的”零组索引)。如果节点中没有剩余
    i
    s,请将其删除

    遍历之后,将每个节点的“上次看到的”零组索引分配给该节点中剩余的
    i
    s
    public static class Group {
        final public int x1;
        final public int x2;
        final public int size;
    
        public Group(int x1, int x2) {
            assert x1 <= x2;
            this.x1 = x1;
            this.x2 = x2;
            this.size = x2 - x1 + 1;
        }
    
        public static final List<Group> getGroupsOfZeros(byte[] arr) {
            List<Group> listOfGroups = new ArrayList<>();
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] == 0) {
                    int x1 = i;
                    for (++i; i < arr.length; i++)
                        if (arr[i] != 0)
                            break;
                    int x2 = i - 1;
                    listOfGroups.add(new Group(x1, x2));
                }
            }
            return Collections.unmodifiableList(listOfGroups);
        }
    
        public static final Group binarySearchNearest(int i, List<Group> list) {
            { // edge cases
                Group firstGroup = list.get(0);
                if (i <= firstGroup.x2)
                    return firstGroup;
                Group lastGroup = list.get(list.size() - 1);
                if (i >= lastGroup.x1)
                    return lastGroup;
            }
            int lo = 0;
            int hi = list.size() - 1;
            while (lo <= hi) {
                int mid = (hi + lo) / 2;
                Group currGroup = list.get(mid);
                if (i < currGroup.x1) {
                    hi = mid - 1;
                } else if (i > currGroup.x2) {
                    lo = mid + 1;
                } else {
                    // x1 <= i <= x2
                    return currGroup;
                }
            }
    
            // intentionally swapped because: lo == hi + 1
            Group lowGroup = list.get(hi);
            Group highGroup = list.get(lo);
            return (i - lowGroup.x2) < (highGroup.x1 - i) ? lowGroup : highGroup;
        }
    }
    
    public static class GroupsBySize {
        private List<List<Group>> listOfGroupsBySize = new ArrayList<>();
    
        public GroupsBySize(List<Group> groups) {
            for (Group group : groups) {
                // ensure internal array can groups up to this size
                while (listOfGroupsBySize.size() < group.size) {
                    listOfGroupsBySize.add(new ArrayList<Group>());
                }
                // add group to all lists up to its size
                for (int i = 0; i < group.size; i++) {
                    listOfGroupsBySize.get(i).add(group);
                }
            }
        }
    
        public final Group getNearestGroupOfAtLeastSize(int index, int atLeastSize) {
            if (atLeastSize < 1)
                throw new IllegalArgumentException("group size must be greater than 0");
            List<Group> groupsOfAtLeastSize = listOfGroupsBySize.get(atLeastSize - 1);
            return Group.binarySearchNearest(index, groupsOfAtLeastSize);
        }
    }
    
    public static void main(String[] args) {
        byte[] byteArray = null;
    
        List<Group> groups = Group.getGroupsOfZeros(byteArray);
        GroupsBySize groupsBySize = new GroupsBySize(groups);
    
        int index = 12;
        int atLeastSize = 5;
        Group g = groupsBySize.getNearestGroupOfAtLeastSize(index, atLeastSize);
    
        System.out.println("nearest group is (" + g.x1 + ":" + g.x2 + ") of size " + g.size);
    }