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.
Test Cases:
testing <- function(ls, expected) {
actual <- sumOfDivided(ls)
expect_equal(actual, expected)
}
test_that("tests", {
testing(c(12, 15), list(c(2, 12), c(3, 27), c(5, 15)))
testing(c(15,21,24,30,45), list(c(2, 54), c(3, 135), c(5, 90), c(7, 21)))
testing(c(15,21,24,30,-45), list(c(2, 54), c(3, 45), c(5, 0), c(7, 21)))
testing(c(107, 158, 204, 100, 118, 123, 126, 110, 116, 100),
list(c(2, 1032), c(3, 453), c(5, 310), c(7, 126), c(11, 110), c(17, 204), c(29, 116), c(41, 123), c(59, 118), c(79, 158), c(107, 107)))
testing(c(-29804, -4209, -28265, -72769, -31744),
list(c(2, -61548), c(3, -4209), c(5, -28265), c(23, -4209), c(31, -31744), c(53, -72769), c(61, -4209), c(1373, -72769), c(5653, -28265), c(7451, -29804)))
testing(c(), list())
testing(c(1070, 1580, 2040, 1000, 1180, 1230, 1260, 1100, 1160, 1000),
list(c(2, 12620), c(3, 4530), c(5, 12620), c(7, 1260), c(11, 1100), c(17, 2040), c(29, 1160), c(41, 1230), c(59, 1180), c(79, 1580), c(107, 1070)))
testing(c(17, 34, 51, 68, 102), list(c(2, 204), c(3, 153), c(17, 272)))
testing(c(17, -17, 51, -51), list(c(3, 0), c(17, 0)))
testing(c(173471), list(c(41, 173471), c(4231, 173471)))
})
sumOfDivided098 <- function (lst) {
if (length(lst) == 0) return(list())
r <- rep(0, times = length(lst)); mx <- lst[1]; result <- list()
for (i in 1:length(lst)) {
r[i] <- abs(lst[i])
mx <- max(mx, r[i])
}
for (fac in 2:mx) {
isFactor <- FALSE; tot <- 0;
for (i in 1:length(r)) {
if (r[i] %% fac == 0) {
isFactor <- TRUE
tot <- tot + lst[i]
while (r[i] %% fac == 0)
r[i] <- r[i] / fac
}
}
if (isFactor == TRUE)
result <- c(result, list(c(fac, tot)))
}
result
}
yTests <- function() {
i <- 0
while (i < 100) {
a <- floor(runif(1, 4, 8))
ls <- floor(runif(n = a, min = 10, max = 10000))
#print(ls)
testing(ls, sumOfDivided098(ls))
i <- i + 1
}
}
test_that("Random tests", {
yTests()
})
我的思路与代码
思路
我的想法很简单,首先,直接遍历(用repeat
函数,这个我觉得看起来简洁)从2到max(abs(lst))
,讲到这里,坑啊,必须得取绝对值,因为lst
可以全是负数,或者最小的负数的绝对值大于最大的正数,这两种情况都会导致结果出问题。
接着,肯定不是每一个数都符合要求,因此需要添加if
条件,我这里加了两个:第一,k
必须要是lst
中某一个数的因子;第二,新的k
不能是已经找到的因子的倍数。
好了,要说的就这些了,没有其他特别重要的东西了。
代码
sumOfDivided <- function (lst) {
if(is.null(lst)) {return(list())}
k <- 2
k.list <- c()
result <- list()
repeat{
if(any(lst%%k == 0) & all(k%%k.list != 0)){
result[[ length(k.list)+1 ]] <- c(k,sum(lst[lst%%k==0]))
k.list <- c(k.list, k)
}
if(k >= max(abs(lst))){break}
k <- k + 1
}
result
}
别人的代码
sumOfDivided <- function (lst) {
n <- max(abs(as.integer(lst)), 0)
p <- rep(TRUE, n)
p[1] <- FALSE
for (i in seq_len(sqrt(n))) {
q <- min(which(cumsum(p) == i))
p[seq_along(p) > q][c(logical(q - 1), TRUE)] <- FALSE
}
primes <- which(p)
sums <- lapply(primes,
function(p, x) {
q <- x %% p
if(any(q == 0)) {
c(p, sum(x[q == 0]))
}
},
lst)
sums[sapply(sums, length) > 0]
}
放这段代码的目的是学习一下seq_len
与seq_along
函数的,seq_len(n)
与1:n
的作用是一样的,生成从1到n的向量。seq_along(seq)
与1:length(seq)
的作用一样,在此不再多说了。