Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.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
Arrays 查找包含多数元素的最长子数组_Arrays_Algorithm - Fatal编程技术网

Arrays 查找包含多数元素的最长子数组

Arrays 查找包含多数元素的最长子数组,arrays,algorithm,Arrays,Algorithm,我试图解决这个算法问题: 为了方便起见,我将问题陈述总结如下 给定长度为n的列表中长度(floor)(n/2)的数组 时限:1.5秒 例如: 如果给定数组为[1,2,1,2,3,2] 答案是5,因为从位置1到5(0索引)的长度为5的子数组[2,1,2,3,2]的数字2出现了3次>地板(5/2)。请注意,我们无法获取整个数组,因为3=地板(6/2) 我的尝试: 首先想到的是一个明显的蛮力(但正确)解决方案,它修复子数组的开始和结束索引,并循环检查它是否包含多数元素。然后我们获取包含多数元素的最

我试图解决这个算法问题:

为了方便起见,我将问题陈述总结如下

给定长度为n的列表中长度(floor)(n/2)的数组

时限:1.5秒

例如:

如果给定数组为[1,2,1,2,3,2]

答案是5,因为从位置1到5(0索引)的长度为5的子数组[2,1,2,3,2]的数字2出现了3次>地板(5/2)。请注意,我们无法获取整个数组,因为3=地板(6/2)


我的尝试:

首先想到的是一个明显的蛮力(但正确)解决方案,它修复子数组的开始和结束索引,并循环检查它是否包含多数元素。然后我们获取包含多数元素的最长子数组的长度。这在O(n^2)中起作用很明显,这不会超过时间限制

我还考虑将元素划分为按排序顺序包含索引的存储桶

使用上述示例,这些桶将是:

1:0,2,

2:1,3,5

3:4

然后,对于每个bucket,我会尝试将索引合并在一起,以找到包含k作为多数元素的最长子数组,其中k是该bucket的整数标签。 然后我们可以取k的所有值的最大长度。我没有尝试这个解决方案,因为我不知道如何执行合并步骤。
有人能告诉我解决这个问题的更好方法吗

编辑:


由于Phamtrong和hk6279的回答,我解决了这个问题。虽然我接受了Phamtrong的回答,因为他首先提出了这个想法,但我强烈推荐查看hk6279的回答,因为他的回答详细阐述了Phamtrong的想法,而且更详细(并且有一个很好的正式证明!).

注意:尝试1是错误的,因为@hk6279给出了一个反例。感谢您指出这一点

尝试1: 答案相当复杂,因此我将讨论一个简短的想法

让我们逐一处理每个唯一的数字

处理从左到右出现的每个数字
x
,在索引
i
处添加一个段
(i,i)
,指示当前子数组的开始和结束。之后,我们需要查看该段的左侧,并尝试将该段的左邻接合并到
(i,i)
,(因此,如果左边是
(st,ed)
,如果它满足条件,我们尝试使它变成
(st,i)
,如果可能的话,并继续合并它们,直到我们无法合并,或者没有左邻

我们将所有这些段都保存在一个堆栈中,以便更快地查找/添加/删除

最后,对于每个细分市场,我们尽量扩大它们,并保持最大的结果

时间复杂度应为
O(n)
,因为每个元素只能合并一次

尝试2

让我们逐一处理每个唯一的数字

对于每个唯一的数字
x
,我们维护一个计数器数组。从0到数组末尾,如果遇到一个值
x
,我们将增加计数,如果没有,我们将减少计数,因此对于这个数组 [0,1,2,0,0,3,4,5,0,0]和数字
0
,我们有这个数组计数器

[1,0,-1,0,1,0,-1,-2,-1,0]

因此,为了生成以特定索引
i
结束的有效子阵列,
counter[i]-counter[start-1]
的值必须大于0(如果您将数组视为从1和-1项生成,则可以很容易地解释这一点;
1表示出现x时,-1,否则为
;问题可以转化为查找和为正的子数组)

因此,在二进制搜索的帮助下,上述算法的复杂度仍然是O(n^2 logn)(如果我们有n/2个唯一的数字,我们需要执行上述过程n/2次,每次都需要O(n logn))

为了改进它,我们观察到,我们实际上不需要存储所有计数器的所有值,而只需要存储
x
的计数器值,我们可以为上面的数组计数器存储:

[1、#、#、0,1、#、#、#、#、-1,0]


这将导致O(n log n)解,它只对每个元素执行一次。

算法: 本质上,Boyer Moore所做的是寻找nums的后缀sufsuf,其中suf[0]suf[0]在这个过程中,我们保持一个计数,每当我们看到当前的多数元素的一个实例,每当我们看到任何其他元素时,它就会递增。每当计数等于0时,我们就有效地忘记了当前索引中的NUM中的所有内容,并考虑当前数字为TH。大多数的元素都是E候选。我们不清楚为什么我们能忘记NoS前缀——考虑下面的例子(管道插入非零计数的独立运行)。 [7,7,5,7,5,1 | 5,7 | 5,5,7,7,7]

这里,索引0处的7被选为多数元素的第一个候选。在处理索引5后,计数最终将达到0,因此索引6处的5将是下一个候选。在这种情况下,7是真正的多数元素,因此忽略此前缀,我们将忽略相等数量的多数元素和少数元素-因此,7仍将是通过丢弃第一个前缀而形成的后缀中的多数元素

[7,7,5,7,5,1 | 5,7 | 5,5,7,7 | 5,5,5]

现在,多数元素是5(我们将数组的最后一次运行从7s更改为5s),但我们的第一个候选元素仍然是7。在这种情况下,我们的候选元素不是真正的多数元素,但我们仍然不能丢弃比少数元素更多的多数元素(这将影响
public int majorityElement(int[] nums) {
    int count = 0;
    Integer candidate = null;

    for (int num : nums) {
        if (count == 0) {
            candidate = num;
        }
        count += (num == candidate) ? 1 : -1;
    }

    return candidate;
} 
    * c * * c * * c c c
 i: 0 1 2 3 4 5 6 7 8 9
  sum_sequence

  0    c               c
 -1  *   *   c       c
 -2        *   *   c
 -3              *
  min_sum

  0    c * *
 -1  *       c * *
 -2                c c c
[start_min
    \
     \
      \
       \
      end_min, start_min
                  \
                   \
                   end_min]