【问题标题】:Reducing time complexity from n^2从 n^2 降低时间复杂度
【发布时间】:2019-03-01 18:36:14
【问题描述】:

一个班级有n 个学生。很快,将有一个校际科学测验,其中将有 4 个科目的问题,为简单起见,将它们称为 1、2、3 和 4。一个团队应该有 2 个学生。任何学生在特定科目上的好坏都是一样的。

我们有 n 行作为输入,每行有 4 个条目。如果i-th 列等于1,则学生擅长i-th 科目。我应该找出学校可以派出团队的总数,以便两个学生在一起知道所有4个科目。

例如,

S1: 1 1 1 1
S2: 1 1 0 1
S3: 1 0 1 1
S4: 0 0 1 1
S5: 0 0 0 0

学生 1 可以和任何学生一起去,因为所有科目都是他的强项。 => 4

学生 2 可以选择 S3 和 S4,因为 S2 在科目 1,2 和 4 中表现良好,而 S3 和 S4 在科目 3 中表现良好。=> 2(注意 (S1,S2) 已计入)

S3 会选择擅长科目 2 的人=> 无

S4:同样,没有。

因此,ans=4+2=6

我的解决方案:-

ans=0;
//arr is the array containing subject-wise "strength" of students
for(int i=0;i<n;i++){
    ArrayList<Integer> a=new ArrayList<>();
    for(int j=0;j<4;j++)
        if(arr[i][j]==0)
            a.add(j);
    if(a.size()==0)
        ans+=n-i-1;
    else
        for(int j=i+1;j<n;j++){
            bool=false;
            for(int k=0;k<a.size();k++){
                if(arr[j][a.get(k)]==0)
                    break;
                bool=true;
            }
            if(bool)
                ans++;
        }
}
System.out.println(ans);

现在我知道我的解决方案是正确的,但它的时间复杂度是 O(n^2),我正在寻找更好的解决方案。谢谢!

【问题讨论】:

  • @vivek -- 这不起作用; S2 需要有人在 2 的位置有 1。例如,值为 4 的人不会组成一个可行的团队。
  • @NicoSchertler:这个结论不成立。有些问题您可以计算解决方案的数量而无需描述这些解决方案。
  • @user11067275 不要循环访问学生。循环一个大小为 16 (0-15) 的数组,该数组将计算每个小数出现的次数。现在,对于每个学生,您只需遍历该数组并检查需要哪些位以及该数字是否设置了位。如果是,请将其添加到最终答案中
  • @vivek_23 是的!这是完美的。直接减少到O(n)。非常感谢!
  • 对不起;我只是在写答案时阅读了进来的 cmets。看来@vivek_23 和我有同样的方法。

标签: algorithm data-structures


【解决方案1】:

您可以通过为科目组合花费内存来减少学生数量的复杂性。

构建一个包含 2^s 元素的列表,其中 s 是主题的数量。按主题组合索引列表,解释为二进制数。例如,S2 的值为 13,缺少值 2。

首先统计每个学生可以满足的“需求”。对于学生已知科目中1 位的每个组合,增加计数列表的索引。

for student in student_list:

    score =   # student's covered subjects as an int

    tally = [0]*16
    for idx in range(16):
        if idx & score == idx:
            tally[idx] += 1

您现在有了一个列表,其中列出了有多少学生可以涵盖所需科目的每种组合。这是 O(n * 2^s)

对于每个学生,找到 需要 分数,即学生分数的 1 补码。现在,为所需分数添加所有计数是一件简单的事情。

team_ct = 0

for student in student_list:

    needed =   # student's needed subjects as an int; this is 15-score (above)
    team_ct += tally[needed]

现在,每个配对都被计算了两次,所以将 team_ct 除以 2。 是的,这最后一段代码可以放在一行代码中:

team_ct = sum([tally[15-score] for score in foo]) / 2

其中foo 是所有学生分数的构造。这部分是O(n)

【讨论】:

  • 我想提一下,虽然它会增加额外的复杂性并为 4 主题的情况节省一点时间,但使用相同的技巧可以将时间复杂度降低到 O(n*2^(s/2))作为子集和问题。
  • 不是在第 1 阶段迭代整个受试者的功率集,而是迭代一半受试者的功率集 (2^(s/2)),增加预分配的计数器 bin tally[half1_idx][half2_score] += 1。然后在第 2 阶段,将进程索引的另一半重复到 tally,然后迭代后半功率集,保持运行总和。
  • 好点。如果 2^s 变得比我们想要迭代的大,这将使运行时间恢复到易于处理的水平。在给定的问题描述中,实际数字将使运行时间保持在一定范围内,但您的更新对于具有相同组合学的不同范式将是有益的。
猜你喜欢
  • 2022-10-08
  • 2011-06-15
  • 2016-07-29
  • 2012-07-28
  • 2016-10-07
  • 2021-03-29
  • 2015-05-05
  • 2020-09-15
相关资源
最近更新 更多