Pihanya

FlowerDelivery.kt

Apr 21st, 2021 (edited)
375
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 2.77 KB | None | 0 0
  1. package com.revolut.interview
  2.  
  3. import java.util.Collections.emptyList
  4.  
  5. data class Flower(
  6.     val id: Int,
  7.     val color: String
  8. )
  9.  
  10. data class Address(
  11.     val address: String
  12. )
  13.  
  14. data class Box(
  15.     val address: Address,
  16.     val flowers: List<Flower> = emptyList()
  17. )
  18.  
  19. class FlowerDelivery {
  20.     /*
  21.      * Distributes flowers over given addresses aligning the following rules:
  22.      * 1) Each address should get a box
  23.      * 2) Each box should contain at least one flower
  24.      * 3) If box contains more than one flower then flower colours should be unique
  25.      */
  26.     // Time complexity: O(N + M)
  27.     fun distribute(addresses: List<Address>, flowers: List<Flower>): List<Box> { // N == addresses.size, M == flowers.size
  28.         if (addresses.isEmpty()) {
  29.             throw IllegalStateException("Addresses must be defined")
  30.         }
  31.  
  32.         if (flowers.isEmpty()) {
  33.             throw IllegalStateException("Flowers must present")
  34.         }
  35.  
  36.         if (flowers.size < addresses.size) {
  37.             throw IllegalArgumentException("Cannot distribute ${flowers.size} flower for ${addresses.size} addresses")
  38.         }
  39.  
  40.         // O(N * max len of address), but in real life I would distinct by `id` so it would be O(N)
  41.         val uniqueAddresses = addresses.distinctBy { it.address }
  42.         if (uniqueAddresses.size < addresses.size) {
  43.             val notUnique: List<Address> = (addresses - uniqueAddresses) // O(N) but nevermind because it's an error branch - doing it for debug purposes
  44.             throw IllegalStateException("Given addresses presented in list twice: $notUnique")
  45.         }
  46.  
  47.         val addressFlowers: List<MutableList<Flower>> = ArrayList<MutableList<Flower>>(addresses.size).apply {
  48.             repeat(addresses.size) { // O(N)
  49.                 add(mutableListOf())
  50.             }
  51.         }
  52.  
  53.         val flowersByColor: Map<String, List<Flower>> = flowers.groupBy { it.color } // O(M)
  54.  
  55.         var currentAddressIndex = 0
  56.         for ((_, colorFlowers) in flowersByColor) { // O(const) == O(1) because there's no much colors
  57.             val startIndex = currentAddressIndex
  58.             for (colorFlower in colorFlowers) { // O(M/const) == O(M)
  59.                 addressFlowers[currentAddressIndex].add(colorFlower)
  60.  
  61.                 currentAddressIndex = (currentAddressIndex + 1) % addresses.size
  62.                 if (currentAddressIndex == startIndex) { // We distributed as much flowers for this color as we could
  63.                     break
  64.                 }
  65.             }
  66.         }
  67.  
  68.         val boxes: List<Box> = addressFlowers.mapIndexed { index, boxFlowers -> // O(N)
  69.             Box(addresses[index], boxFlowers)
  70.         }
  71.  
  72.         // Final complexity:
  73.         // O(N + N + M + M + N) = O(3N + 2M) = O(N + M)
  74.  
  75.         return boxes
  76.     }
  77. }
  78.  
Add Comment
Please, Sign In to add comment