Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 面试问题-在时间间隔列表中,哪些数字出现次数最多_Algorithm_Intervals - Fatal编程技术网

Algorithm 面试问题-在时间间隔列表中,哪些数字出现次数最多

Algorithm 面试问题-在时间间隔列表中,哪些数字出现次数最多,algorithm,intervals,Algorithm,Intervals,我只听说过这个问题,所以我不知道确切的限制。您将得到一个正整数列表。每两个连续值形成一个闭合区间。查找在大多数间隔中出现的数字。如果两个值出现的次数相同,请选择最小的一个 示例:[4,1,6,5]结果是[1,4],[1,6],[5,6],其中1,2,3,4,5分别出现两次。正确答案应该是1,因为它是最小的 不幸的是,我不知道如果不采用O(n^2)方法,如何实现这一点。我能想到的唯一优化方法是合并连续的降序或升序间隔,但这并不能真正起作用,因为[4,3,2]会计算两次3 编辑:有人用此链接评论(但

我只听说过这个问题,所以我不知道确切的限制。您将得到一个正整数列表。每两个连续值形成一个闭合区间。查找在大多数间隔中出现的数字。如果两个值出现的次数相同,请选择最小的一个

示例:
[4,1,6,5]
结果是
[1,4],[1,6],[5,6]
,其中
1,2,3,4,5
分别出现两次。正确答案应该是1,因为它是最小的

不幸的是,我不知道如果不采用O(n^2)方法,如何实现这一点。我能想到的唯一优化方法是合并连续的降序或升序间隔,但这并不能真正起作用,因为
[4,3,2]
会计算两次3


编辑:有人用此链接评论(但随后删除)了一个解决方案。我觉得这是最优雅的,尽管它没有考虑到我输入的某些元素是某些间隔的开始和结束。

根据它们的起始值对间隔进行排序。然后从左(全局最小值)到右(全局最大值)滑动一行。在每个集合点(间隔的开始或结束)计算与滑动线的交点数(在
O(log(n))
)。此算法的时间复杂度为
O(n log(n))
n
是间隔数)。

如果范围数组中的最大数小于数组的最大大小限制,我的解决方案将以复杂度O(n)工作

1-我创建了一个新数组来处理范围并使用它来查找 在所有间隔中出现最多的数字。为了简单起见,让我们使用 你的例子。输入=[1,4]、[1,6]、[5,6]。让我们叫新的 数组进程,并将其长度设为6,然后将其初始化为0 进程=[0,0,0,0,0,0]

2-然后循环所有间隔,并用(+1)和标记开始 我的范围后面的单元格以(-1)结束

  • 对于范围[1,4]进程=[1,0,0,0,-1,0]

  • 对于范围[1,6]进程=[2,0,0,0,-1,0]

  • 对于范围[5,6]进程=[2,0,0,0,0]

3-p进程数组将作为累加数组使用。初始化 变量让我们称之为EXPENCE=process[0],它将等于2 就我们而言。通过这个过程,不断积累你能积累的东西 注意?元素1,2,3,4,5,6将出现=2,因为其中每个元素 它们在给定范围内出现两次

4-最大化当您在流程阵列中循环时,您将发现 解决方案

公开课考试{

public static void main(String[] args) {

    int[] arr = new int[] { 4, 1, 6, 5 };
    System.out.println(solve(arr));


}

public static int solve(int[] range) {
    // I assume that the max number is Integer.MAX_VALUE

    int size = (int) 1e8;
    int[] process = new int[size];

    // fill process array
    for (int i = 0; i < range.length - 1; ++i) {
        int start = Math.min(range[i], range[i + 1]);
        int end = Math.max(range[i], range[i + 1]);

        process[start]++;
        if (end + 1 < size)
            process[end + 1]--;
    }
    // Find the number that appears in most intervals (smallest one)
    int appear = process[0];
    int max = appear;
    int solu = 0;
    for (int i = 1; i < size; ++i) {
        appear += process[i];

        if (appear > max){
            solu = i;
            max = appear;
        }

    }
    return solu;
}
publicstaticvoidmain(字符串[]args){
int[]arr=新的int[]{4,1,6,5};
System.out.println(solve(arr));
}
公共静态int solve(int[]范围){
//我假设max number是Integer.max\u值
int size=(int)1e8;
int[]进程=新的int[size];
//填充进程数组
对于(int i=0;i最大值){
solu=i;
最大值=出现;
}
}
返回solu;
}

}

将这些视为括号:
开始和间隔,
结束。现在检查每对[a,b]的边界,并对每个位置的间隔开始/结束标记进行计数:较低的数字从左侧获得间隔开始;数字越大,间隔越近。对于给定的输入:

Process [4, 1]
result: [0, 1, 0, 0, 0, -1]
Process [1, 6]
result: [0, 2, 0, 0, 0, -1, 0, -1]
Process [6, 5]
result: [0, 2, 0, 0, 0, -1, 1, -2]
现在,只需对该列表进行累加;最大值的位置是您想要的答案

result: [0, 2, 0, 0, 0, -1, 1, -2]
cumsum: [0, 2, 2, 2, 2,  1, 2,  0]
请注意,最终总和必须为0,并且不能为负。最大值为2,它首先出现在位置1处。因此,1是出现最大(2)数量的最小整数

不,输入一次,数字范围一次。请注意,使用一个简单的值表,可以节省存储空间。处理表的外观如下所示:

[(1,  2)
 (4, -1)
 (5,  1)
 (6, -2)]
如果输入的开始和停止间隔都是一个数字,那么需要首先处理开始。例如,[4,3,2]看起来像

[(2,  1)
 (3,  1)
 (3, -1)
 (4, -1)]
注意:根据输入的大小维护排序插入列表是O(n^2)时间;之后对列表进行排序是O(n log n)。或者是O(n)空格

我的第一个建议是,在数字本身上建立索引,即O(n)时间,但O(r)输入值范围上的空间。
[

主要的观察结果是,结果将是输入中的一个数字(证据留给读者作为简单的练习,yada-yada)

我的解决方案将受到@Prune解决方案的启发。重要的一步是将输入数字映射到输入中所有不同数字的顺序

我将使用C++ STD。我们可以先把所有的数字装入一个集合。然后我们可以从它创建地图,它把一个数字映射到所有数字中的顺序。< /P>

int solve(input) {
  set<int> vals;
  for (int n : input) {
    vals.insert(n);
  }
  map<int, int> numberOrder;
  int order = 0;
  for (int n : vals) {  // values in a set are ordered
    numberOrder[n] = order++;
  }
int求解(输入){
设置VAL;
for(int n:输入){
插入(n);
}
地图编号器;
整数阶=0;
对于(int n:vals){//集合中的值是有序的
numberOrder[n]=订单++;
}
然后我们创建进程数组(类似于@Prune的解决方案)

int进程[map.size()+1];//添加到结束元素之后
int curr=输入[0];
对于(int i=0;i  int process[map.size() + 1];  // adding past-the-end element
  int curr = input[0];
  for (int i = 0; i < input.size(); ++i) {
    last = curr;
    curr = input[i];
    process[numberOrder[min(last, curr)]]++;
    process[numberOrder[max(last, curr)] + 1]--;
  }
  int appear = 0;
  int maxAppear = 0;
  for (int i = 0; i < process.size(); ++i) {
    appear += process[i];
    if (appear > maxAppear) {
      maxAppear = appear;
      maxOrder = i;
    }
  }
  for (pair<int, int> a : numberOrder) {
    if (a.second == maxOrder) {
      return a.first;
    }
  }
}