Skip to main content

sorted squared array

· 2 min read

this time we will try to (satisfactory) solve a coding challenge.

description

write a function that takes in a non-empty array of integers that are sorted in ascending order and returns a new array of the same length with the squares of the original integers also sorted in ascending order.

first attempt

first attempt (which fails when array includes negative numbers) given array = [-2, -1] as input, output is [4, 1] which is wrong because correct output should be sorted in ascending order:

first-attempt.kts
#!/usr/bin/env kscript

fun sortedSquaredArray(array: List<Int>): List<Int> {
return array.map { n -> n * n }
}

what i like from first-attempt (failed) solution is that we have no state (we are not mutating anything), we are only traversing our input array once and generating a new array as our output.

second attempt

an optimal solution would be to use a data structure that preserves the order of its elements i.e binary tree; but, given that we have no b-tree at our disposal we can leverage Kotlin native BinarySearch methods in List. we need to be careful with the return value of such a function in order to prevent index bound exceptions:

second-attempt.kts
#!/usr/bin/env kscript

fun sortedSquaredArray(array: List<Int>): List<Int> {
val acc = mutableListOf<Int>()

for (n in array) {
val sqr = n * n

if (acc.isEmpty()) acc.add(sqr)
else {
val i = (acc.binarySearch(sqr, 0, acc.size) + 1).absoluteValue
acc.add(i, sqr)
}
}

return acc
}

what i dislike from second-attempt solution is that: we have state mutations. on the other hand, i like that we are still traversing our input array once meaning O(n) complexity which I think is nice!

bonus

as a bonus here is a 3rd optional solution that is not as efficient as the previous one but this third solution is based on immutable data structures which is always good:

bonus-attempt.kts
#!/urs/bin/env kscript

fun sortedSquaredArray(array: List<Int>): List<Int> {

fun add(n: Int, list: List<Int>): List<Int> {
val (l, g) = list.partition { x -> x <= n }
return l.plus(n).plus(g)
}

return array.fold(listOf()) { acc, n ->
add(n * n, acc)
}
}

PD. in case you are wondering bout the kscript in the codeblocks take a look at: holgerbrandl/kscript