11

我现在正在学习codility。有些任务我可以自己解决,但有些任务有问题。这个任务的难度是<**>。它是中等的,但我停滞不前。

问题:


给定一个由 N 个整数组成的非空零索引数组 A。对于每个满足 0 ≤ i < N 的数字 A[i],我们要计算数组中不是 A[i] 的除数的元素的数量。我们说这些元素是非除数。例如,考虑整数 N = 5 和数组 A 使得:

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 课,课程中的第一个任务。

谢谢!

4

26 回答 26

15

我想我会用 C++ 分享我的解决方案,得到 100 分。我认为这很简单。

https://codility.com/demo/results/demoQFK5R5-YGD/

  1. 首先,它计算数组中每个数字的出现次数。

  2. 然后对于每个数组元素i,它会在 1 到 的范围内找到其除数的数量sqrt(i),包括作为除法结果的除数。

  3. 最后,它从数组中的元素总数中减去给定元素的除数总数。

    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;
    }
    
于 2014-02-20T18:51:38.607 回答
7

该解决方案给出 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;
}

谢谢大家的帮助。

于 2014-01-27T20:08:28.053 回答
5

A solution attempt: (EDITED, see below)

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;
    }
}

The maximum value for the numbers that occur in the array was defined to be 2*arrayLength. For each number that MAY occur in the array, it computes

  • The set of divisors of this number (using the Erathostenes Sieve)
  • How often the number actually occurs in the array

Given this information, one can walk through the array. For each value that is found in the array, one can look up the set of divisors, and compute the total number occurences of all the divisors. The result is then simply the array length, minus this total number of occurances of divisors.

Since it uses only the Sieve of Erathostenes for the computation (and only walks through the set of divisors for each number, which should be logN as well), it should have a worst-case time complexity of O(N*logN). But I'm not entirely sure whether the storage complexity really can be considered to be strictly O(N), because for each of the N numbers, it has to store the set of divisors. Maybe this can somehow be avoided, by combining some of the methods, but in any case, the storage is at least in O(N*logN) as well.

EDIT: The exceptions came from the array for the occurrences storing only values up to A.length*2-1, this was fixed now. Additionally, the set of divisors was not computed properly, this should also be fixed now. Apart from that, analysis results like

got      [8, 8, 9, 10, 6, 8, .. 
expected [8, 8, 9, 10, 6, 8, ..

are not really helpful. Maybe this is part of the "game", but I'm not playing this game right now. The basic idea should be clear, and I assume that it's now working properly until someone shows be a counterexample ;-P It still does not reach the O(N) storage complexity, but I haven't thought about a possible way to achieve this thoroughly...

于 2014-01-24T14:39:15.537 回答
3

这是我的 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
于 2014-01-28T05:15:10.570 回答
2

在这里,我们采用我得到 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/

于 2015-10-11T14:14:42.823 回答
2

我使用了一个哈希图,它满足 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;
    }
}
于 2017-01-29T17:23:37.697 回答
1

红宝石解决方案,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
于 2019-06-05T23:33:49.433 回答
1

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 解决方案的启发。

于 2018-04-17T20:58:32.707 回答
1

这个 C# 中的 100/100 代码解决方案。因为 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;
    }
}
于 2020-03-31T19:02:05.943 回答
0

要了解为什么数字“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
于 2014-01-23T20:42:52.480 回答
0

因为那个返回数字代表了非除数的数量!对于索引 [0],有 2 个非除数,对于索引 [3],也有 2 个非除数。

于 2014-01-24T11:03:53.673 回答
0

这对我有用,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;
}
于 2015-05-04T17:04:13.577 回答
0

下面的 C++ 中的 O(n * logn) 解决方案。

检查 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;                                                          
}
于 2021-11-06T20:05:01.933 回答
0

Golang解决方案获得了 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
}
于 2020-05-21T08:07:42.203 回答
0

这是我的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;

}
于 2020-02-23T19:02:38.190 回答
0

这是我在 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;
}
于 2015-11-06T14:42:53.807 回答
0

根据 jaho 的回答,我添加了缓存以避免相同的计算。

这是代码结果

下面是我的 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;
}
于 2018-05-25T09:02:14.350 回答
0

得分为 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)
于 2020-06-01T13:54:54.053 回答
0

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;
}
于 2015-08-29T12:37:39.013 回答
0

// 在 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 = 解决方案(&数组)

于 2020-07-28T11:51:53.403 回答
0

One of the most difficult to read solution written in GO lang, designed by Java developer (100% total score):

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
}
于 2020-06-20T09:28:43.647 回答
0

这里 100% python 使用 Eratosthenes 的 Sieve 原则来避免计算除数(或多个)超过一次,直到数组的最大值:

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
于 2019-05-18T13:03:43.377 回答
0

性能不是此代码中最好的,但可读性非常简单。

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();
于 2020-07-11T15:45:18.180 回答
0

一个易于遵循的 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 的频率,以便更容易计算非除数。将非除数放在一个字典中,然后在最后的列表理解中简单地检索答案。

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

于 2020-09-30T14:26:37.793 回答
0
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;
  }
于 2018-10-05T15:34:05.527 回答
-2
/**
 * 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]);
        }
    }
}
于 2014-01-25T15:17:01.347 回答