Sum by Factors

kata programming

مساله:

آرایه ای از اعداد صحیح مثبت و منفی به شما داده می شود:

I= [i1,..,in]

شما باید آرایه P را به فرم زیر ایجاد کنید:

[ [p, sum of all ij of I for which p is a prime factor (p positive) of ij] ...]

آرایه P باید بر اساس اعداد اول مرتب سازی شود. در آخر باید نتیجه به صورت یک رشته نمایش داده شود.

مثال:

I = {12, 15}; // result = "(2 12)(3 27)(5 15)"

اعداد [2,3,5] لیست اعداد اولی است که در این آرایه استفاده شده است.

نکته:

این امکان وجود دارد که اگر اعداد منفی هم داشته باشیم، جمع اعداد 0 شود.


Description:

Given an array of positive or negative integers

I= [i1,..,in]

you have to produce a sorted array P of the form

[ [p, sum of all ij of I for which p is a prime factor (p positive) of ij] ...]

P will be sorted by increasing order of the prime numbers. The final result has to be given as a string in Java, C#, C, C++ and as an array of arrays in other languages.

Example:

I = {12, 15}; // result = "(2 12)(3 27)(5 15)"

[2, 3, 5] is the list of all prime factors of the elements of I, hence the result.

Notes:

It can happen that a sum is 0 if some numbers are negative!

Example: I = [15, 30, -45] 5 divides 15, 30 and (-45) so 5 appears in the result, the sum of the numbers for which 5 is a factor is 0 so we have [5, 0] in the result amongst others.

In Fortran – as in any other language – the returned string is not permitted to contain any redundant trailing whitespace: you can use dynamically allocated character strings.


راه حل:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class SumOfDivided {

    public static String sumOfDivided(int[] l) {
        final int maxValue = Arrays.stream(l).map(num -> Math.abs(num)).max().getAsInt();
        return eratosteneSieve(maxValue).stream()
                .reduce("",
                        (resultString, primeNum) -> {
                            List<Integer> divisibleNum = Arrays.stream(l).filter(num -> num % primeNum == 0).boxed().collect(Collectors.toList());
                            return divisibleNum.size() > 0
                                    ? resultString + String.format("(%d %d)", primeNum, divisibleNum.stream().mapToInt(Integer::intValue).sum())
                                    : resultString;
                        },
                        (not, used) -> null);
    }

    public static List<Integer> eratosteneSieve(final int x) {
        final List<Integer> candidates = IntStream.rangeClosed(2, x).boxed().collect(Collectors.toList());
        return candidates.stream()
                .filter(num -> num <= Math.sqrt(x))
                .reduce(candidates,
                        (resList, currNum) -> resList.stream()
                        .filter(num -> num % currNum != 0 || num.equals(currNum))
                        .collect(Collectors.toList()),
                        (not, used) -> null);
    }
}
import java.lang.Math;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
import java.util.HashMap;
import java.util.stream.Collectors;

public class SumOfDivided {

  /*
  *  We use a cache of already known primes to minimize double computation.
  */
  private static SortedSet<Integer> primeCache = new TreeSet<>();
  private static Map<Integer, Integer> map = new HashMap<>();

  public static String sumOfDivided(int[] l) {
    initalize();
    
    for(int i=0; i<l.length; i++) {
      int absNum = Math.abs(l[i]);
      updatePrimeCache(absNum);
      updateMap(l[i]);
    }
    
    return convertMapToString();
  }
  
  private static void initalize(){
    map = new HashMap<>();
    if(primeCache.isEmpty()){
      primeCache.add(2);
    }
  }
  
  /*
  *  We update the prime cache so it contains all primes up to number. 
  */
  private static void updatePrimeCache(int number) {
    Integer largestKnownPrime  = primeCache.last();
    if(largestKnownPrime > number) {
      return;
    }
    
    for(int p=largestKnownPrime+1; p <= number; p++) {
      if(isPrime(p)) {
        primeCache.add(p);
        largestKnownPrime = p;
      }
    }
  }
  
  private static boolean isPrime(int p) {
    for(int i=2; i<=Math.sqrt(p); i++) {
      if(p%i == 0) return false;
    } 
    
    return true;
  }
  
  private static void updateMap(int num) {
    for(Integer prime: primeCache) {
      if(num%prime == 0) {
        Integer sum = map.getOrDefault(prime, 0);
        sum += num;
        map.put(prime, sum);
      }
    }
  }
  
  private static String convertMapToString() {
    TreeMap<Integer, Integer> sortedMap = new TreeMap(map); 
    return sortedMap.entrySet()
      .stream()
      .map(entry -> "(" + entry.getKey() + " " + entry.getValue() + ")")
      .collect(Collectors.joining(""));
  }
}
import java.util.*;
import java.util.stream.*;
import static java.util.stream.Collectors.*;
import static java.util.Arrays.*;

public class SumOfDivided {
  public static String sumOfDivided(int[] l) {
    return generatePrimeNumbersClosed(stream(l).max().orElse(0))
          .mapToObj(it -> new Object(){ int primeNumber = it, sum = stream(l).filter(n -> n % it == 0).sum(); })
          .filter(it -> it.sum > 0)
          .map(it -> String.format("(%d %d)", it.primeNumber, it.sum))
          .collect(joining(""));
  }

  private static IntStream generatePrimeNumbersClosed(int n) {
    BitSet composited = new BitSet();
    for(int i = (int) Math.sqrt(n); i >= 2; i--) for(int m = i * i; m <= n; m += i) {
      composited.set(m);
    }
    return IntStream.rangeClosed(2, n).filter(it -> !composited.get(it));
  }
}

import java.util.*;
import java.util.stream.*;
import static java.util.stream.Collectors.*;
import static java.util.Arrays.*;

public class SumOfDivided {
  public static String sumOfDivided(int[] l) {
    return generatePrimeNumbersClosed(stream(l).max().orElse(0))
          .mapToObj(it -> new Object(){ int primeNumber = it, sum = stream(l).filter(n -> n % it == 0).sum(); })
          .filter(it -> it.sum > 0)
          .map(it -> String.format("(%d %d)", it.primeNumber, it.sum))
          .collect(joining(""));
  }

  private static IntStream generatePrimeNumbersClosed(int n) {
    BitSet composited = new BitSet();
    for(int i = (int) Math.sqrt(n); i >= 2; i--) for(int m = i * i; m <= n; m += i) {
      composited.set(m);
    }
    return IntStream.rangeClosed(2, n).filter(it -> !composited.get(it));
  }
}
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;

public class SumOfDivided {
  
  public static String sumOfDivided(int[] l) {
    StringBuilder stringBuilder = new StringBuilder();
    Set<Integer> allPrimeFactorsForElementsOfl = findAllPrimeFactorsForElementsFromArr(l);
    for (Integer primeFactor : allPrimeFactorsForElementsOfl) {
      int sum = 0;
      for (Integer element : l) {
        if (isPrimeFactor(primeFactor, element)) {
          sum += element;
        }
      }
      stringBuilder.append("(" + primeFactor + " " + sum + ")");
    }
    return stringBuilder.toString();
  }

  private static Set<Integer> findAllPrimeFactorsForElementsFromArr(int[] numbers) {
    Set<Integer> primeFactors = new TreeSet<Integer>();
    for (int number : numbers) {
      primeFactors.addAll(findPrimeFactors(Math.abs(number)));
    }
    return primeFactors;
  }

  private static Set<Integer> findPrimeFactors(int numberFromI) {
    Set<Integer> primeFactors = new HashSet<Integer>();
    for (int i = 2; i <= numberFromI; i++) {
      while (numberFromI % i == 0) {
        primeFactors.add(i);
        numberFromI /= i;
      }
    }
    return primeFactors;
  }

  private static boolean isPrimeFactor(int primeFactor, int numberTobeChecked) {
    return numberTobeChecked % primeFactor == 0;
  }

}
import java.util.Arrays;
import java.util.OptionalInt;
import java.util.stream.IntStream;

public class SumOfDivided {
  public static String sumOfDivided(int[] numbers) {
    int maxValue = Arrays.stream(numbers).map(Math::abs).max().getAsInt();
    boolean[] eratosteneSieve = new boolean[maxValue];
    StringBuilder result = new StringBuilder(4*maxValue*numbers.length);
    IntStream.rangeClosed(2, maxValue)
      .filter(num-> !eratosteneSieve[num-2])
      .forEach(prime->{
        for(int i=2; prime*i <= maxValue; i++){
            eratosteneSieve[prime*i-2] = true;
        }
        OptionalInt sum = Arrays.stream(numbers).filter(num-> num % prime == 0).reduce(Integer::sum);
        if(sum.isPresent()){
          result.append("(").append(prime).append(" ").append(sum.getAsInt()).append(")");
        }
      });
    return result.toString();
  }
}

دیدگاهتان را بنویسید