找到一组数字的最大子集,使得任何2个数字的总和不能被给定数字整除

时间:2016-08-28 20:03:40

标签: python algorithm

我正在尝试解决下面所述的Hackerrank问题Non-Divisible Subset

enter image description here

我尝试了以下解决方案(适用于示例测试用例):

# The lines below are for Hackerrank submissions
# n, k = map(int, raw_input().strip().split(' '))
    # a = map(int, raw_input().strip().split(' '))

n = 4
k = 3
a = [1, 7, 2, 4]

while True:
    all_pairs = [(a[i],a[j]) for i in range(len(a)) for j in range(i+1,len(a))]
    tested_pairs = {pair: (pair[0] + pair[1]) % k != 0 for pair in all_pairs}
    disqualified_pairs = {key: value for key, value in tested_pairs.iteritems() if not value}.keys()
    if not disqualified_pairs:
        break
    occurrences = list(sum(disqualified_pairs, ()))
    counts = map(lambda x: occurrences.count(x), a)
    index_remove = counts.index(max(counts))
    a.remove(index_remove)

print len(a)

我要做的是确定'违规'对并删除最常出现的a元素,直到没有'冒犯'对为止。

但是,对于大多数测试用例,我得到“运行时错误”:

enter image description here

据推测,上述算法适用于这种简单的情况,其中只需要删除一个数字(数字2),但在更复杂的测试用例中失败。有人能看出它有什么问题吗?

更新

根据poke的建议来测试k = 2a = [1, 2, 3],我做了以下修改:

n = 4
k = 2
a = [1, 2, 3]

while True:
    all_pairs = [(a[i],a[j]) for i in range(len(a)) for j in range(i+1,len(a))]
    disqualified_pairs = [pair for pair in all_pairs if (pair[0] + pair[1]) % k == 0]
    if not disqualified_pairs:
        break
    offending_numbers = sum(disqualified_pairs, ())   # 'Flatten' the disqualified pairs into a single list
    counts = {el: offending_numbers.count(el) for el in set(offending_numbers)}     # Count occurrences of each offending number
    number_to_remove = max(counts, key=counts.__getitem__)
    a.remove(number_to_remove)

print len(a)

生成的a[2, 3],并按预期包含两个元素。我还检查过它仍适用于原始示例。但是,我仍然在某些测试用例中遇到“分段错误”:

enter image description here

根据https://www.hackerrank.com/challenges/pairs/forum/comments/9154,由于无效的内存访问(不存在的数组索引等),通常会发生分段错误。但是,在算法失败的情况下,我仍然没有找到任何其他测试用例。有什么想法吗?

2 个答案:

答案 0 :(得分:2)

这可以通过计算模数来完成,而不是生成所有对。

时间复杂度:O(n + k)

空间复杂度:O(k)或O(1),因为k最大为100,O(k)=> O(1)

基本理念

  

(a + b)%k =((a%k)+(b%k))%k

因为(a%k)在[0,k-1]范围内,

  

(a%k)+(b%k)在[0,2k-2]

的范围内

此外,

  

(a + b)%k = 0

     
      
  1. (a%k)= 0且(b%k)= 0 OR

  2.   
  3. (a%k)+(b%k)= k

  4.   

主要想法

  1. 根据条件2,当您选择模数i的任何值时,您可以选择任何模数的任何值,模数k-i除外。
  2. 在大多数情况下,选择一个以上的模数i没有冲突。
  3. 根据条件1,您可以从模数0
  4. 中选择最多1个值
  5. 当k是偶数时,k / 2 + k / 2 = k。当k为偶数
  6. 时,您可以从模数k / 2中选择最多1个值

    根据以上信息,解决方案可能是

    1. 如果n <2,则返回n
    2. 创建一个大小为k且所有初始值为0的数组,表示为Arr,以存储模数
    3. 在数组a上循环,索引i从0到n-1,将1加到Arr [a [i]%k]
    4. 初始化一个初始值为0的计数器
    5. 在数组Arr上循环,索引i从1到k-(k / 2)-1,将Max(Arr [i],Arr [k-i])添加到计数器
    6. 如果Arr [0]> 0,将1添加到计数器
    7. 如果k%2 = 0且Arr [k / 2]> 0,将1添加到计数器
    8. 返回柜台

答案 1 :(得分:1)

我使用的方法是:

1. find power set of given list of integers.
2. sort power set by subset size.
3. iterate down the sorted power set and print if subset meets problem's conditions.

在java中:

import java.util.*;
public class f implements Comparator<List<?>> {

    @Override
    public int compare(List<?> o1, List<?> o2) {
        return Integer.valueOf(o1.size()).compareTo(o2.size());
    }
    static ArrayList<ArrayList<Integer>> powerSet = new ArrayList<>();

    // get power set of arr
    static void g(int arr[],int[] numbers,int i){
        if(i==arr.length){
            ArrayList<Integer> tmp = new ArrayList<>();
            for(int j = 0;j<arr.length;j++){
                if(arr[j]==1) tmp.add(numbers[j]);
            }
            powerSet.add(tmp);
            return;
        }
        arr[i] = 1;
        g(arr,numbers,i+1);
        arr[i] = 0;
        g(arr,numbers,i+1);
    }
    static void h(int[] a){
        int[] arr=new int[a.length];
        for(int j =0;j<arr.length;j++){
            arr[j]=0;
        }
        g(arr,a,0);
    }
    // check whether the sum of any numbers in subset are not evenly divisible by k
    static boolean condition(ArrayList<Integer> set,int k){
        for(int i = 0;i<set.size();i++){
            for(int j = i+1;j<set.size();j++){
                if((set.get(i)+set.get(j))%k==0){
                    return false;
                }
            }
        }
        return true;
    }

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int k = in.nextInt();
        int[] a = new int[n];
        for (int i=0;i<n;i++){
            a[i]=in.nextInt();
        }


        h(a);
        Collections.sort(powerSet, new f());
        for(int i=powerSet.size()-1;i>0;i--){
            if(condition(powerSet.get(i),k)){
                System.out.println(powerSet.get(i).size());
                break;
            }
        }

    }
}

结果: submission 测试用例#9错误是StackOverflowError:

的结果

enter image description here

不熟悉hackerrank错误,但也许你的错误类似。