CountNonDivisible - Codility 训练任务
Posted
技术标签:
【中文标题】CountNonDivisible - Codility 训练任务【英文标题】:CountNonDivisible - Codility training task 【发布时间】:2014-02-10 04:43:46 【问题描述】:我现在正在学习 codility。有些任务我可以自己解决,但有些任务有问题。 这个任务的难度是。它是中等的,但我停滞不前了。
问题:
给定一个由 N 个整数组成的非空零索引数组 A。 对于每个满足 0 ≤ i
A[0] = 3
A[1] = 1
A[2] = 2
A[3] = 3
A[4] = 6
对于以下元素:
A[0] = 3, the non-divisors are: 2, 6,
A[1] = 1, the non-divisors are: 3, 2, 3, 6,
A[2] = 2, the non-divisors are: 3, 3, 6,
A[3] = 3, the non-divisors are: 2, 6,
A[6] = 6, there aren't any non-divisors.
写一个函数:
class Solution public int[] solution(int[] A);
给定一个由 N 个整数组成的非空零索引数组 A,返回一个整数序列,表示非除数的数量。 该序列应返回为:
结构结果(在 C 中), 或整数向量(在 C++ 中), 或记录结果(帕斯卡), 或整数数组(在任何其他编程语言中)。例如,给定:
A[0] = 3
A[1] = 1
A[2] = 2
A[3] = 3
A[4] = 6
该函数应返回 [2, 4, 3, 2, 0],如上所述。 假设:
N 是 [1..50,000] 范围内的整数; 数组 A 的每个元素都是 [1..2 * N] 范围内的整数。复杂性:
预计最坏情况时间复杂度为 O(N*log(N)); 预期的最坏情况空间复杂度为 O(N),超出输入存储 (不包括输入参数所需的存储空间)。输入数组的元素可以修改。
我已经写了一些解决方案。但是我的解决方案体积庞大,并且仍然具有 O(n^2) 复杂性。 你能帮我一些想法或算法如何以最佳方式做到这一点吗?这不是面试任务或其他什么。我只是在训练并尝试解决所有任务。 您可以在此处找到此任务:http://codility.com/demo/train/ 第 9 课,课程中的第一个任务。
谢谢!
【问题讨论】:
这听起来你应该把你的解决方案发布到Code Review 看看他们怎么说。 我的第一个想法是玩一下 Eratosthenes 的筛子,看看你是否可以通过按摩它来解决这个问题。我不是说这就是答案。我不知道答案是什么。这正是我的第一个想法。 @Keppil,我的解决方案很简单。用一些拐杖来解决问题以降低复杂性是显而易见的方法,但它不起作用。我没有一个好主意,所以我想专注于想法和算法,而不是代码。 【参考方案1】:我想我会用 C++ 分享我的解决方案,获得 100 分。我认为这很简单。
https://codility.com/demo/results/demoQFK5R5-YGD/
首先计算数组中每个数字的出现次数。
然后对于每个数组元素i
,它会在1到sqrt(i)
的范围内找到其除数的数量,包括除数的结果。
最后,它从数组中的元素总数中减去给定元素的除数总数。
vector<int> solution(vector<int> &A)
int N = A.size();
vector<int> counts (*std::max_element(A.begin(), A.end()) + 1,0);
// Calculate occurences of each number in the array
for (int i = 0; i < N; ++i)
counts[A[i]] += 1;
std::vector<int> answer(N,0);
// For each element of the array
for (int i = 0; i < N; ++i)
// Calulate how many of its divisors are in the array
int divisors = 0;
for (int j = 1; j * j <= A[i]; ++j)
if (A[i] % j == 0)
divisors += counts[j];
if (A[i] / j != j)
divisors += counts[A[i] / j];
// Subtract the number of divisors from the number of elements in the array
answer[i] = N - divisors;
return answer;
【讨论】:
看起来这个解决方案的复杂度是O(N*sqrt(N))
。外循环 - N
迭代,内循环 - 最多 sqrt(2*N)
迭代。
干得好!很好的解决方案【参考方案2】:
此解决方案给出 100 分。 https://codility.com/demo/results/demo63KVRG-Q63/
public int[] solution(int[] A)
int[][] D = new int[A.length*2 + 1][2];
for (int i = 0; i < A.length; i++)
D[A[i]][0]++;
D[A[i]][1] = -1;
for (int i = 0; i < A.length; i++)
if (D[A[i]][1] == -1)
D[A[i]][1] = 0;
for (int j = 1; j <= Math.sqrt(A[i]) ; j++)
if (A[i] % j == 0 && A[i] / j != j)
D[A[i]][1] += D[j][0];
D[A[i]][1] += D[A[i]/j][0];
else if (A[i] % j == 0 && A[i] / j == j)
D[A[i]][1] += D[j][0];
for (int i = 0; i < A.length; i++)
A[i] = A.length - D[A[i]][1];
return A;
感谢大家的帮助。
【讨论】:
这在算法上与我的解决方案有什么不同吗? (如果不是,我至少可以说我的解决方案是为了理解这种方法,而你的解决方案是为了获得高分;-))。如果它不同(除了像 sqrt 优化这样的小事),对差异的解释会很好。 @Marco 不同之处在于除数搜索,我不存储所有除数集,只存储除数数。总的来说,我采用了您解决方案的基本思想。我说这对我有帮助。谢谢。 @Stepler : 你能帮我理解一下吗【参考方案3】:解决方案尝试:(已编辑,见下文)
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
// Solution for Lesson 9, "CountNonDivisible"
// of http://codility.com/demo/train/
public class Solution
public static void main(String[] args)
int A[] = new int[5];
A[0] = 3;
A[1] = 1;
A[2] = 2;
A[3] = 3;
A[4] = 6;
Solution s = new Solution();
int B[] = s.solution(A);
System.out.println("Input : "+Arrays.toString(A));
System.out.println("Result : "+Arrays.toString(B));
public int[] solution(int[] A)
Set<Integer> setA = asSet(A);
List<Set<Integer>> divisors = computeDivisors(A.length * 2);
int occurrences[] = computeOccurrences(A);
int nonDivisors[] = new int[A.length];
for (int i=0; i<A.length; i++)
int value = A[i];
Set<Integer> d = divisors.get(value);
int totalOccurances = 0;
for (Integer divisor : d)
if (setA.contains(divisor))
totalOccurances += occurrences[divisor];
nonDivisors[i] = A.length-totalOccurances;
return nonDivisors;
/**
* Returns a set containing all elements of the given array
*
* Space: O(N)
* Time: O(N)
*
* @param A The input array
* @return The set
*/
private static Set<Integer> asSet(int A[])
Set<Integer> result = new HashSet<Integer>();
for (int value : A)
result.add(value);
return result;
/**
* Computes a list that contains for each i in [0...maxValue+1] a set
* with all divisors of i. This is basically an "Eratosthenes Sieve".
* But in addition to setting the entries of a list to 'false'
* (indicating that the respective numbers are non-prime), this
* methods inserts the divisors into the corresponding set.
*
* Space: O(N) (?)
* Time: O(N*logN) (?)
*
* @param maxValue The maximum value
* @return The list
*/
private static List<Set<Integer>> computeDivisors(int maxValue)
List<Boolean> prime = new ArrayList<Boolean>();
prime.addAll(Collections.nCopies(maxValue+1, Boolean.TRUE));
List<Set<Integer>> divisors = new ArrayList<Set<Integer>>();
for (int i = 0; i < maxValue + 1; i++)
Set<Integer> d = new HashSet<Integer>();
d.add(1);
d.add(i);
divisors.add(d);
for (int i = 2; i <= maxValue; i++)
int next = i + i;
while (next <= maxValue)
divisors.get(next).addAll(divisors.get(i));
prime.set(next, Boolean.FALSE);
next += i;
return divisors;
/**
* Computes an array of length 2*A.length+1, where each entry i contains
* the number of occurrences of value i in array A
*
* Space: O(N)
* Time: O(N)
*
* @param A The input array
* @return The occurrences array
*/
private static int[] computeOccurrences(int A[])
int occurances[] = new int[A.length * 2 + 1];
for (int i=0; i<A.length; i++)
int value = A[i];
occurances[value]++;
return occurances;
数组中出现的数字的最大值被定义为 2*arrayLength。对于数组中可能出现的每个数字,它计算
这个数的除数集(使用 Erathostenes Sieve) 数字在数组中实际出现的频率有了这些信息,人们就可以穿过阵列了。对于在数组中找到的每个值,可以查找一组除数,并计算所有除数的出现总数。结果就是简单的数组长度,减去这个除数出现的总数。
由于它仅使用 Erathostenes 筛进行计算(并且仅遍历每个数字的除数集,这也应该是 logN),因此它的最坏情况时间复杂度应该是 O(N*logN )。但我不完全确定存储复杂度是否真的可以被认为是严格的 O(N),因为对于 N 个数字中的每一个,它都必须存储一组除数。也许这可以通过结合一些方法以某种方式避免,但无论如何,存储也至少在 O(N*logN) 中。
编辑:异常来自仅存储不超过 A.length*2-1 的值的数组,现在已修复。此外,除数集没有正确计算,现在也应该修复。 除此之外,分析结果像
got [8, 8, 9, 10, 6, 8, ..
expected [8, 8, 9, 10, 6, 8, ..
并没有真正的帮助。也许这是“游戏”的一部分,但我现在不玩这个游戏。基本思想应该很清楚,我假设它现在可以正常工作,直到有人提出反例;-P 它仍然没有达到 O(N) 的存储复杂度,但我还没有想到一种可能的方法来彻底实现这一点......
【讨论】:
你检查过你的解决方案吗?我试过了,codility 给了我这些结果codility.com/demo/results/demoHQAV4M-BQP。 添加了 EDIT,但没有 codility 帐户,不会在那里进行测试 谢谢,没注意到。现在功能是正确的,但是 3 个“大”测试用例中的 2 个发生了超时。 (代码可以很容易地优化以缓解这个问题,但我不确定超时是否完全是由于......实用......实现,或者真的是由于渐近复杂性。事实上,' large' case pass 表示不是后者,但未详细验证)。 100 分中的 77 分,不过...... 我喜欢你的回答,感谢你的详细解释。它对我有帮助,今天我找到了一个得分 100 的解决方案。 由于与每个元素相关联的除数的上限是 (n^(1/3)),所以遍历集合的最坏时间复杂度不应该是 O(n^(1 /3))?导致总时间复杂度为 O(n^(4/3))?【参考方案4】:这是我的 100 分 Python 解决方案。希望对其他人有所帮助。
def solution(A):
''' Solution for the CountNonDivisible by codility
Author: Sheng Yu - codesays.com
'''
from math import sqrt
A_max = max(A)
A_len = len(A)
# Compute the frequency of occurrence of each
# element in array A
count =
for element in A:
count[element] = count.get(element,0)+1
# Compute the divisors for each element in A
divisors =
for element in A:
# Every nature number has a divisor 1.
divisors[element] = [1]
# In this for loop, we only find out all the
# divisors less than sqrt(A_max), with brute
# force method.
for divisor in xrange(2, int(sqrt(A_max))+1):
multiple = divisor
while multiple <= A_max:
if multiple in divisors and not divisor in divisors[multiple]:
divisors[multiple].append(divisor)
multiple += divisor
# In this loop, we compute all the divisors
# greater than sqrt(A_max), filter out some
# useless ones, and combine them.
for element in divisors:
temp = [element/div for div in divisors[element]]
# Filter out the duplicate divisors
temp = [item for item in temp if item not in divisors[element]]
divisors[element].extend(temp)
# The result of each number should be, the array length minus
# the total number of occurances of its divisors.
result = []
for element in A:
result.append(A_len-sum([count.get(div,0) for div in divisors[element]]))
return result
【讨论】:
看来and not divisor in divisors[multiple]
是没有必要的。【参考方案5】:
这里我们采用我 100% 接受的解决方案:
boolean[] result_;
public int[] solution(int[] A)
int a[][] = new int[2*A.length + 1][2];
result_ = new boolean[2*A.length + 1];
for(int i : A)
++a[i][0];
a[1][1] = A.length - a[1][0];
result_[1] = true;
for(int i : A)
multCount(a,A,i);
int[] result = new int[A.length];
for(int i=0;i<result.length; i++)
result[i] = a[A[i]][1];
return result;
private void multCount( int[][] a, int[] A, int item)
if( result_[item] )
return;
int sub=(int)Math.sqrt(item);
a[item][1] = A.length;
if(item % sub == 0&& sub >1)
a[item][1] -= a[sub][0];
int rest = item/sub;
if(rest != sub)
a[item][1] -= a[rest][0];
a[item][1] -= a[item][0];
a[item][1] -= a[1][0];
for(int i=2; i<sub; i++)
if(item % i == 0)
a[item][1] -= a[i][0];
int rest = item/i;
a[item][1] -= a[rest][0];
result_[item] = true;
https://codility.com/demo/results/trainingZ2VRTK-5Y9/
【讨论】:
您能解释一下您的代码,以便您的答案对其他人更有用吗? 所有数字都在 1 到 2*N 之间 所有数字都在 1 到 2*N 之间 我们创建了一个有两个维度的数组 数组的索引是数字本身 第二维是一个有两个数字的数组 第一个是计数数字的第二个是答案第一个数字直接由这个数组填充 for(int i : A) ++a[i][0]; 示例:假设数组 A 有以下项: [1,3,1,5,3] 二维数组将按如下方式填充 0,0,2,0,0,0 ,2,0,0,0,1,0,0,,.. 表示:数字 0 有 0 个 count 数字 1 有 2 个 count 数字 2 有 0 个 count 数字 3 有两个计数 为了找到可设计的数字,我使用了最简单的算法:我应该找到 1 和 sqrt 之间的数字,并将它们添加到结果示例: 3,1,3,2,6 数组如下:0,01,01,02,0,0,0 ,0,0,1.0 让我们从第一项 3 开始:只有 3 和 1 这意味着不可设计的是数组的长度 (5 ) 减去 1 的数量和 3 表示 2为了消除多次重新计算的次数,我添加了布尔数组,告诉我这个数字是计算出来的【参考方案6】:我使用了一个哈希图,它满足 o(nlogn) 和 o(n) 时间和空间复杂度
import java.util.*;
class Solution
public int[] solution(int[] A)
int N = A.length;
HashMap<Integer, Integer> count = new HashMap<>();
for (int i : A)
Integer key = count.get(i);
if (key != null)
count.put(i, key + 1);
else
count.put(i, 1);
HashMap<Integer, Integer> divs = new HashMap<>();
for (Integer n : count.keySet())
int sum = 0;
int j = 1;
while (j * j <= n)
if (n % j == 0)
if (count.containsKey(j))
sum += count.get(j);
//find n = j*k cases to add both to the dividors
int k = n / j;
if (k != j)
if (count.containsKey(k))
sum += count.get(k);
j++;
divs.put(n, N - sum);
for (int i = 0; i < A.length; i++)
A[i] = divs.get(A[i]);
return A;
【讨论】:
【参考方案7】:100% 得分解决方案,ES6:
function solution(A)
let count =
// counting number frequency
A.map(a =>
//console.log(count[a])
if (count[a] > 0)
count[a] = count[a] + 1
else
count[a] = 1
)
// console.log(count)
let divs =
Object.keys(count).map(key =>
let sum = 0
let j = 1
while (j * j <= key)
if (key % j == 0)
if (count[j] > 0)
sum += count[j]
// adding another dividor
let k = key / j
// scenario: 9 = 81 / 9. Escaping same number
if (k != j)
if (count[k] > 0)
sum += count[k]
// another possible solution: sum = sum * 2
// if key is square number: sum -= 1
j++
divs[key] = A.length - sum
)
// console.log(divs)
let answer = []
A.map(a =>
answer.push(divs[a])
)
// console.log(answer)
return answer
受@Soley 解决方案的启发。
【讨论】:
【参考方案8】:Ruby 解决方案,100%
def solution(a)
elements = a.inject(Hash.new(0)) |acc, el| acc[el] +=1;acc
n = elements.keys.sort
div = n.each.inject(Hash.new(0)) do |acc, el|
k=el
while k < n[-1]
k+=el
acc[k] += elements[el]
end
acc
end
a.map |x| a.size - elements[x] - div[x]
end
【讨论】:
【参考方案9】:这个 100/100 的 C# 代码解决方案。 因为 C# 和 Java 非常相似可能会有所帮助。
public class NonDivisiblesCounter
/// <summary>
/// 1. Count the ocurrences of each element
/// 2. Count all divisors for each element and subtract by the Length of array A to get nonDivisors
/// 3. Add it to a cache since the elements can repeat and you do not need to calculate again.
/// </summary>
/// <param name="A"></param>
/// <returns></returns>
public int[] Count(int[] A)
int n = A.Length;
var ocurrencesOfEach = CountOcurrencesOfEach(A);
var nonDivisorsOfEach = new int[n];
var nonDivisorsCache = new Dictionary<int, int>();
for (int i = 0; i < n; i++)
int element = A[i];
if (nonDivisorsCache.ContainsKey(element))
nonDivisorsOfEach[i] = nonDivisorsCache[element];
else
int nonDivisorCounter = n - CountDivisorsPerOcurrence(element, ocurrencesOfEach);
nonDivisorsOfEach[i] = nonDivisorCounter;
nonDivisorsCache[element] = nonDivisorCounter;
return nonDivisorsOfEach;
private int CountDivisorsPerOcurrence(int element, Dictionary<int, int> ocurrencesOfEach)
int square = (int)Math.Sqrt(element);
int divisorCounter = 0;
if (square * square == element && ocurrencesOfEach.ContainsKey(square))
divisorCounter += ocurrencesOfEach[square];
for (int divisor = 1; element / divisor > square; divisor++)
if (element % divisor == 0)
if (ocurrencesOfEach.ContainsKey(divisor))
divisorCounter += ocurrencesOfEach[divisor];
if (ocurrencesOfEach.ContainsKey(element / divisor))
divisorCounter += ocurrencesOfEach[element / divisor];
return divisorCounter;
private Dictionary<int, int> CountOcurrencesOfEach(int[] elements)
var result = new Dictionary<int, int>();
for (int i = 0; i < elements.Length; i++)
int element = elements[i];
if (result.ContainsKey(element))
result[element]++;
else
result.Add(element, 1);
return result;
【讨论】:
【参考方案10】:因为返回数字代表非除数的数量! 对于索引 [0],有 2 个非除数,对于索引 [3],也有 2 个非除数。
【讨论】:
【参考方案11】:这对我很有用,C 分数为 100%
struct Results solution(int A[], int N)
struct Results result;
// write your code in C99
int *numbers = (int *)calloc(2*N + 1, sizeof(int));
for (int i = 0; i < N; i++)
++numbers[A[i]];
int *numbers2 = (int *)calloc(2*N + 1, sizeof(int));
for (int i = 0; 2*i < 2*N + 1; i++)
if (numbers[i] != 0)
for (int j = 2*i; j < 2*N + 1; j+=i)
numbers2[j] += numbers[i];
int * Carr = (int *)calloc(N, sizeof(int));
for (int i = 0; i < N; i++)
Carr[i] = N - numbers[A[i]] - numbers2[A[i]];
result.C = Carr;
result.L = N;
free(numbers);
free(numbers2);
return result;
【讨论】:
【参考方案12】:100% 用于 javascript。 https://codility.com/demo/results/demoKRRRPF-8JW/
function solution(A)
var N = A.length;
if (N < 1 || N > 50000) throw 'Error: Bad input';
var uniqueDict = ;
var keys = [];
for (var i = 0; i < N; ++i)
var num = A[i]
var uniqueCount = uniqueDict[num];
if (uniqueCount > 0)
uniqueDict[num] = uniqueCount + 1;
else
uniqueDict[num] = 1;
keys.push(num);
keys.sort(function(a,b)
return a-b;
);
for (i = keys.length-1; i >= 0; --i)
num = keys[i];
var divisorCount = divisors(num, uniqueDict);
var nonDivisorCount = N - divisorCount;
uniqueDict[num] = nonDivisorCount;
for (i = 0; i < N; ++i)
num = A[i];
A[i] = uniqueDict[num];
return A;
function divisors(num, uniqueDict)
var count = 0;
var x = 1;
while (x * x <= num)
if (parseInt(num/x) === num/x) // is divisor
if (uniqueDict[num/x] > 0)
count += uniqueDict[num/x];
if (num/x !== x && uniqueDict[x] > 0)
count += uniqueDict[x];
x++;
return count;
【讨论】:
你可以用parseInt(num/x) === num/x
代替num % x === 0
【参考方案13】:
这是我在 javascript 中的解决方案。我认为它比以前的要容易一些,它适用于 O(n log n)。您可以在此处查看其他解决方案:https://marioqs.wordpress.com
function solution(A)
var N = A.length;
var count = [];
var i;
for (i = 0; i < 2*N+1; ++i)
count.push(0);
for (i = 0; i < N; ++i)
++count[A[i]];
var divisors = [];
for (i = 0; i < 2*N+1; ++i)
divisors.push(0);
//the actual code starts here, before it's just initialisation of variables.
i = 1;
var k;
while (i <= 2*N)
k = i;
while (k <= 2*N)
divisors[k] += count[i];
k += i;
++i;
var result = [];
for (i = 0; i < N; ++i)
result.push(0);
for (i = 0; i < N; ++i)
result[i] = N - divisors[A[i]];
return result;
【讨论】:
【参考方案14】:根据 jaho 的回答,我添加了缓存以避免相同的计算。
这里是the codility result,
下面是我的 C 代码。
#include <math.h>
struct Results solution(int A[], int N)
int maxA = 0, i, j, sqrtA;
int *counts, *cache;
struct Results result;
result.C = (int *) malloc(N*sizeof(int));
result.L = N;
// Grep the maximum.
for (i = 0; i < N; ++i)
if (A[i] > maxA)
maxA = A[i];
++maxA;
// Initialize some arrays.
counts = (int *) malloc(maxA*sizeof(int));
cache = (int *) malloc(maxA*sizeof(int));
for (i = 0; i < maxA; ++i)
counts[i] = 0;
cache[i] = -1;
// Count A.
for (i = 0; i < N; ++i)
counts[A[i]] += 1;
// Main computation begins.
for (i = 0; i < N; ++i)
// If the answer is already computed, use it.
if (cache[A[i]] >= 0)
result.C[i] = cache[A[i]];
continue;
// There's no existing answer, compute it.
cache[A[i]] = N;
sqrtA = (int) sqrt(A[i]);
for (j = 1; j <= sqrtA; ++j)
if (A[i]%j == 0)
cache[A[i]] -= counts[j];
if (j*j != A[i])
cache[A[i]] -= counts[A[i]/j];
result.C[i] = cache[A[i]];
// Since Codility prohibits the system calls,
// below free commands are commented.
// free(counts);
// free(cache);
return result;
【讨论】:
【参考方案15】:import static java.lang.Integer.max;
import java.util.Arrays;
public int[] solution(int[] A)
final int N = A.length;
final int MAX_VALUE_TBL = 2*50000;
int[] r = new int[N]; // result table
int[] AS_AV = new int[MAX_VALUE_TBL + 1]; // number of cell with values
int[] AS_AR = new int[MAX_VALUE_TBL + 1]; // results yet counted for values
boolean[] b = new boolean[MAX_VALUE_TBL + 1]; // if value has been counted
if (N == 1) return r;
for (int i = 0; i < N; i++)
int v = A[i];
AS_AV[v]++;
for (int i = 0; i < N; i++)
int cu_val = A[i];
if (!b[cu_val])
int am_div = getAmDivisors(cu_val, AS_AV);
r[i] = N - am_div;
b[cu_val] = true;
AS_AR[cu_val] = r[i];
else
r[i] = AS_AR[cu_val];
return r;
private int getAmDivisors(int cu_val, int[] AS_AV)
int r = 0;
int sqr = (int) Math.sqrt(cu_val);
for (int divisor = sqr; divisor > 0; divisor--)
if (cu_val % divisor == 0)
r += AS_AV[divisor];
if (divisor * divisor != cu_val)
r += AS_AV[cu_val / divisor];
return r;
【讨论】:
【参考方案16】:这里 100% python 使用 Sieve of Eratosthenes principal 来避免计算除数(或多个)超过一次,直到数组的最大值:
def solution(A):
N=len(A)
num_non_divisors=[0]*N
if N<2:
return num_non_divisors
MaxVal=max(A)
#Trivial cases
if MaxVal < 2:
return num_non_divisors
MinVal=min(A)
if MinVal==MaxVal:
return num_non_divisors
Occur = [0] * (MaxVal + 1)
#Occurences of e in A
for e in A:
Occur[e]+=1
#Divisors of any element lower than MaxVal
Divisors = [Occur[1]] * (MaxVal + 1)
#DejaVu to avoid counting them more than once
DejaVu = [0] * (MaxVal + 1)
for e in A:
if e!=1 and DejaVu[e]==0:
Divisors[e]+=Occur[e]
DejaVu[e]+=1
i = 2
while (i * i <= MaxVal):
#We start at i x i to avoid counting 2 times multiples of the form k x i, where k<i.
k = i * i
while (k <= MaxVal):
Divisors[k] += Occur[i]
if i * i < k: #equivalent k/i != i
#Symmetric divisor
Divisors[k] += Occur[int(k/i)];
k += i
i += 1
#Re-initialize DejaVu
DejaVu = [0] * (MaxVal + 1)
for i in range(0,len(A)):
if not DejaVu[A[i]]:
DejaVu[A[i]]=N-Divisors[A[i]]
num_non_divisors[i]=DejaVu[A[i]]
return num_non_divisors
【讨论】:
【参考方案17】:这是我的 java 解决方案,100%。
没有模,没有除法。只需“计数排序”并筛分即可。
public int[] solution(int[] A)
//find max number. To be used for 'count sort' array size.
int max = A[0];
for (int i = 1 ; i < A.length ; i++)
max = Math.max(max, A[i]);
//count sort
int [] count = new int [max+1];
for (int i = 0 ; i < A.length ; i++)
count[A[i]]++;
int [] nonDiv = new int [max+1];
//initially count all elements as non divisible (minus 'number of occurrences' of the the given number)
for (int i = 1 ; i < nonDiv.length; i++)
if (count[i] != 0) //skip numbers which don't exists in table A
nonDiv[i] = A.length - count[i];
//sieve
for (int i = 1 ; i < nonDiv.length; i++)
if (count[i] != 0) //skip numbers which don't exists in table A
int s = i*2;
while (s<nonDiv.length)
if (nonDiv[s] != 0)
//Sieve. Most important part. Decrease number of non-divisible by the number of occurrences of number 'i'.
nonDiv[s] -= count[i];
s+=i;
//produce the output
int []res = new int [A.length];
for (int i = 0 ; i < A.length ; i++)
res[i] = nonDiv[A[i]];
return res;
【讨论】:
【参考方案18】:Golang solution 100%,唯一不同的是我们必须使用 hashmap 来缓存除数,否则性能测试会部分失败。
package solution
// you can also use imports, for example:
// import "fmt"
// import "os"
// you can write to stdout for debugging purposes, e.g.
// fmt.Println("this is a debug message")
func Solution(A []int) []int
tdMapping := make(map[int]int)
MaxValue := 2 * len(A)
occurs := make([]int, MaxValue+1)
for _, v := range A
occurs[v]++
r := make([]int, len(A))
for i := 0; i < len(A); i++
totalDivisors := 0
if _, ok := tdMapping[A[i]]; ok
totalDivisors = tdMapping[A[i]]
else
for j := 1; j*j <= A[i]; j++
if j*j == A[i]
totalDivisors += occurs[j]
else
if A[i]%j == 0
totalDivisors += occurs[j] + occurs[A[i]/j]
tdMapping[A[i]] = totalDivisors
r[i] = len(A) - totalDivisors
return r
【讨论】:
【参考方案19】:得分为 100% 的 JavaScript 解决方案。 Codility 检测到复杂度为 O(nlogn),但实际上是 O(n * sqrt(n))
function solution(A)
const createCounts = A =>
const counts = Array(A.length * 2 + 1).fill(0)
for (let i = 0; i < A.length; i++)
counts[A[i]] += 1
return counts
const counts = createCounts(A)
const results = []
for (let i = 0; i < A.length; i++)
let nonDivisiblesCount = A.length
let j = 1
while (j * j < A[i])
if (A[i] % j === 0)
nonDivisiblesCount -= counts[j]
nonDivisiblesCount -= counts[A[i] / j]
j++
if (j * j === A[i])
nonDivisiblesCount -= counts[j]
results.push(nonDivisiblesCount)
return results
const A = [3, 1, 2, 3, 6]
console.log(A)
const s = solution(A)
console.log(s)
【讨论】:
【参考方案20】:用 GO 语言编写的最难阅读的解决方案之一,由 Java 开发人员设计(总分 100%):
func Solution(A []int) []int
aSize := len(A)
maxValue := A[0]
for idx := 0; idx < aSize; idx++
element := A[idx]
if maxValue < element
maxValue = element
remainDividersCountList := make([]int, maxValue+1)
for idx := 0; idx < aSize; idx++
element := A[idx]
if remainDividersCountList[element] == 0
remainDividersCountList[element] = aSize - 1
else
remainDividersCountList[element] = remainDividersCountList[element] - 1
cachedResultMap := make([]int, maxValue+1)
alreadyCalculated := make([]int, maxValue+1)
alreadyCalculatedDuplicated := make([]int, maxValue+1)
caluclatedMap := make(map[int][]int)
for idx := 0; idx < aSize; idx++
element := A[idx]
if alreadyCalculated[element] == 0
for multiplier := 2; multiplier <= maxValue/element; multiplier++
multResult := element * multiplier
if multResult > maxValue
break
else
cachedResult := cachedResultMap[multResult]
if cachedResult > 0
cachedResultMap[multResult] = cachedResult + 1
else
cachedResultMap[multResult] = 1
caluclatedMap[element] = append(caluclatedMap[element], multResult)
alreadyCalculated[element] = 1
else if alreadyCalculatedDuplicated[element] == 0
multiplier := aSize - (remainDividersCountList[element] + 1)
list := caluclatedMap[element]
for repIdx := 0; repIdx < len(list); repIdx++
repElem := list[repIdx]
cachedResultMap[repElem] = cachedResultMap[repElem] + (1 * multiplier)
alreadyCalculatedDuplicated[element] = 1
result := make([]int, aSize)
for idx := 0; idx < aSize; idx++
element := A[idx]
result[idx] = remainDividersCountList[element] - cachedResultMap[element]
return result
【讨论】:
【参考方案21】:性能不是此代码中最好的,但可读性非常简单。
Map<Integer, Long> map = IntStream.range(0, A.length)
.collect(HashMap::new,
(acc, i) -> acc.compute(A[i], (k, v) -> v == null ? 1 : ++v),
HashMap::putAll);
int[] removed = new int[A.length];
for (int i = 0; i < A.length; i++)
int N = A[i];
int max = N;
List<Integer> divisors = new ArrayList<>();
if (N == 1)
divisors.add(1);
else
for (int div = 1; div < max; div++)
if (N % div == 0)
divisors.add(div);
if (div != N / div)
divisors.add(N / div);
if (N / div < max)
max = N / div;
removed[i] += map.entrySet().stream()
.filter(entry -> divisors.stream().noneMatch(div -> Objects.equals(entry.getKey(), div)))
.mapToLong(e -> e.getValue()).sum();
【讨论】:
【参考方案22】:// 在 Swift 4.2.1 (Linux) 中编写代码
public func solution(_ A : inout [Int]) -> [Int]
let n = A.count
var counters = Array(repeating: 0, count: 2 * n + 1)
var divisors = Array(repeating: 0, count: 2 * n + 2)
var nonDivisors = Array(repeating: 0, count: n)
for i in A
counters[i] += 1
for i in 1...2 * n
if counters[i] > 0
var k = i
while k <= 2 * n
if counters[k] > 0
divisors[k] += counters[i]
k += i
for i in 0..<n
nonDivisors[i] = n - divisors[A[i]]
return nonDivisors
var 数组 = [3, 1, 2, 3, 6]
var a = 解决方案(&array)
【讨论】:
【参考方案23】:一个易于理解的 100% python 解决方案 - 我认为 :-)
首先你需要除数。
def get_divisors(n):
froot = int(n**.5)
divs = set()
# reverse through possible divisors which are lower than root(n)
while froot > 0:
if not n%froot:
divs.add(froot)
divs.add(n//froot) # Catch the higher divisor on the other side of froot
froot-=1
return divs
然后您可以先计算每个 int 的频率,以便更容易计算非除数。将非除数放入 dict 中,然后简单地在最后的列表理解中检索答案。
def solution(A):
N = len(A)
int_count =
# O(N) scan to count number frequency
for i in range(N):
int_count[A[i]] = int_count.get(A[i], 0) + 1
# Create an array for every i non-divisor count
div_count =
for i, freq in int_count.items():
divs = get_divisors(i)
num_divs = 0
for d in divs:
num_divs += int_count.get(d, 0)
div_count[i] = N-num_divs # N - divisors = non-divisors :-)
return [div_count[A[i]] for i in range(N)]
偶尔做一个利用python的解决方案很好:-)
https://github.com/niall-oc/things/tree/master/codility
【讨论】:
【参考方案24】:要了解为什么数字“2”在以下结果 [2,4,3,2,0] 上出现两次,请参见以下代码:
A[0] = 3, the non-divisors are: 2, 6 >> Quantity: 2
A[1] = 1, the non-divisors are: 3, 2, 3, 6 >> Quantity: 4
A[2] = 2, the non-divisors are: 3, 3, 6, >> Quantity: 3
A[3] = 3, the non-divisors are: 2, 6 >> Quantity: 2
A[6] = 6, there aren't any non-divisors. >> Quantity: 0
【讨论】:
【参考方案25】:O(n * logn) 下面的 C++ 解决方案。
检查 A 中的最大元素以节省空间,而不是使用 sizeA * 2
构建 A 中出现次数的哈希。
将 1, num 添加为所有数字的除数。除数存储在 unordered_set 中以进行有效插入和查找。这些元素也将是独一无二的。
将所有其他除数添加到所有数字。
遍历 A 中的每个数字。检查除数在 A 中出现的次数。
非除数将是 A 的长度减去找到的除数。
vector<int> solution(vector<int> &A)
const int sizeA = A.size();
const int max_elem = *max_element(A.cbegin(), A.cend());
vector<int> hash(max_elem, 0);
vector<unordered_set<int>> divisors_hash(max_elem, unordered_set<int>);
for (const int e : A)
++hash[e - 1];
divisors_hash[e - 1].insert(1, e);
for (int i = 2; i * i <= max_elem; ++i)
for (int k = i; k <= max_elem; k += i)
if (hash[k - 1]) divisors_hash[k - 1].insert(i, k / i);
vector<int> non_divisors(sizeA, 0);
for (int i = 0; i < sizeA; ++i)
const int e = A[i];
int divisor_count = 0;
for (const int divisor : divisors_hash[e - 1])
divisor_count += hash[divisor - 1];
non_divisors[i] = sizeA - divisor_count;
return non_divisors;
【讨论】:
【参考方案26】:/**
* Count Non-divisible
*/
public class Solution
public int[] solution(int[] A)
int[] div = new int[A.length];
for (int e = 0; e < div.length; e++)
div[e] = 0;
for (int i = 0; i < A.length; i++)
int dividend = A[e];
if (dividend % A[i] != 0)
div[e] += 1;
return div;
public static void main(String args[])
int[] A = new int[]3, 1, 2, 3, 6;
Solution s = new Solution();
int[] B = s.solution(A);
for (int i = 0; i < B.length; i++)
System.out.println(B[i]);
【讨论】:
解的复杂度为 n^2。 Codility 需要 n*log(n)。以上是关于CountNonDivisible - Codility 训练任务的主要内容,如果未能解决你的问题,请参考以下文章