不可分子集 - Hackerrank

Posted

技术标签:

【中文标题】不可分子集 - Hackerrank【英文标题】:Non-Divisible Subset - Hackerrank 【发布时间】:2016-09-29 08:36:45 【问题描述】:

我正在尝试解决来自 Hackerrank (https://www.hackerrank.com/challenges/non-divisible-subset) 的不可分割子集问题。我试图使用这样的想法,即如果 a 和 b 的总和可被 k 整除,则 a%k+b%k = k,但是,它运行得不是很好。 以下是我目前所写的内容:

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() 
   int n;
   int k;
   cin >> n;
   cin >> k;
    int j;
   vector<int>numbers;
   vector<int>remainders;
   for(int i = 0; i < n; i++) 
       int z;
       cin >> z;
       numbers.push_back(z);
   
    for (vector<int>::iterator it = numbers.begin(); it != numbers.end(); it++) 
      j = *it % k;
      remainders.push_back(j);
    

    for(vector<int>::iterator it2 = remainders.begin(); it2 != remainders.end(); it2++) 
        int remainderCount = 0;
        int otherRemainderCount = 0;
        otherRemainderCount = std::count(remainders.begin(), remainders.end(), k-*it2);
        remainderCount = std::count(remainders.begin(), remainders.end(), *it2);
        if (remainderCount > otherRemainderCount) 
            theChosenOne = *it2;
         else if (otherRemainderCount > remainderCount) 
            theChosenOne = k-*it2;
        
       cout << theChosenOne << endl;
    

  return 0;
    

我为余数创建了一个向量,并使用 std::cout 函数来找出向量中哪个余数出现得更多。如果 K 为 5,*it2 = 4,并且 k-*it2 = 1。如果 *it2 出现的次数更多,那么我会选择 *it2。否则,我会选择 k-*it2。

【问题讨论】:

您是否已经使用调试器检查过您的程序? 我真的不喜欢 HackerRank 和类似的东西。它(他们)鼓励不可维护的“可爱”一次性代码。 @MirunaCamelia “是的,它不起作用。” 这实际上太模糊了。请在您的问题中准确描述它是如何不起作用,并告诉我们您在使用调试器单步执行代码时观察到的情况。 @MartinBonner 你会推荐什么替代方案? @0x499602D2:合适的课程或书籍。 【参考方案1】:

您的解决方案看起来是在正确的轨道上,但需要进行一些更改。

您基本上需要将数组中的数字散列到适当的位置。

将数组 rem[k] 初始化为 0。

遍历数组中的n 数字,然后执行以下操作:

rem[array[i]%k]++;

现在您只需要处理rem[] 数组即可找到最大子集。 rem 数组的最大大小为 k&lt;=100。利用rem[] 数组的小尺寸,高效求解。

编辑:为您添加代码。

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;


int main() 
   int n,i,k;
   cin>>n>>k;
   int arr[n];
   int rem[k]=0;
   for(i=0;i<n;i++)
   
       cin>>arr[i];    
   
   for(i=0;i<n;i++)
   
       rem[arr[i]%k]++;
   
   int count = 0;
   for(i=1;i<=k/2;i++)
   
       count = count + max(rem[i],rem[k-i]);
   
   count = count + (rem[0]>0?1:0);
   if(k%2==0)
   
     count = count - rem[k/2];
     if(rem[k/2]>0)
        count = count + 1;
   
   cout<<count;
   return 0;

找出rem[] 数组的内容后,就该寻找最大子集了。如果您选择rem[1],那么您不能选择rem[k-1] 作为任何两个数字,一个来自rem[1] 和另一个来自rem[k-1] 可以加在一起,这将被我们不想要的k 整除。所以我们从rem[i]rem[k-i] 中找出最大的一个并将其添加到计数中

我的代码使用上述逻辑..

希望对你有帮助!!!

【讨论】:

为什么在for(i=1;i 我已经在解释中说明了原因。说k=7,我试图在rem[1] 和rem[6]、rem[2] 和rem[5]、rem[3] 和rem[4] 之间找到max。为此,我只需要写一个循环直到k/2 这个算法没有给出正确的答案。例如对于输入 10 4 并设置 1 2 3 4 5 6 7 8 9 10 它会给出答案 3 但正确的是 5 @tzanou 我的代码给出的答案为 5。请在评论前正确测试!快乐编码【参考方案2】:
int main() 

    int n,k;
    cin>>n>>k;
    vector <int> a(n);
    vector <int> r(k,0);
    for(int i=0;i<n;i++)
       
        cin>>a[i];
        r[a[i]%k]++;
    
    int ctr=min(1,r[0]);
    for(int a=1;a<(k/2+1);a++)
    
        if(a!=k-a)
            ctr+=max(r[a],r[k-a]);
    

    if(k%2==0&&r[k/2]!=0)
        ctr++;
    cout<<ctr;
    return 0;

【讨论】:

请发布相关解释,而不仅仅是代码。 ***.com/help/how-to-answer【参考方案3】:

这似乎有效

#include <stdio.h>

int min(int a, int b)  return a < b ? a : b; 

int max(int a, int b)  return a > b ? a : b; 

int main() 
int n, k, a, total = 0;
scanf("%d %d", &n, &k);
int mods[k];
for (int i = 0; i < k; i++)
mods[i] = 0;
while (n--) 
scanf("%d", &a);
mods[a % k]++;

// can only have 1 value congruent to 0 mod k
total += min(1, mods[0]);
// if even, can only have 1 value congruent to k/2 mod k
if (k % 2 == 0)
total += min(1, mods[k / 2]);
// for all others, pick max of those k and n-k mod k
for (int d = 1; d < (k + 1) / 2; d++)  // for all others,
total += max(mods[d], mods[k - d]);

printf("%d", total);
return 0;

【讨论】:

以上是关于不可分子集 - Hackerrank的主要内容,如果未能解决你的问题,请参考以下文章

什么是 Shiny 中的“‘闭包’类型的对象不可子集化”错误?

java 368.最大的可分子集(#1).java

概率论备忘

PTA7-3 子集和问题 (30 分) 回溯法

如何从bigquery中的字符串中提取子集

JavaScript的子集和超集