diff --git a/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist-solution-notes.md b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist-solution-notes.md new file mode 100644 index 00000000..a79054fa --- /dev/null +++ b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist-solution-notes.md @@ -0,0 +1,48 @@ +# [Greedy Algorithms: Greedy Florist](https://www.hackerrank.com/challenges/greedy-florist) + +- Difficulty: `#medium` +- Category: `#ProblemSolvingBasic` + +## About the problem statement + +At first it seems a bit confusing. Due the problem statement tends to +make us believe that the most convenient thing is to start with the highest +numbers, but the examples doesn't not present a logical descending order. + +## Way of thinking + +After rereading the problem several times it can be determined that: + +- It does not matter who the buyers are, nor in what order they buy, +nor how much each one buys. +The important thing is how many people are organized +into a group to minimize the purchase price. + +- If the number of people in the group is greater than or equal to +the number of different flowers, then the price is the lowest possible, +because they can all be purchased "in a single pass", +making each person in the group (or less) buy 1 unit. + +- The price of flowers does matter, therefore it is more convenient to buy +the most expensive ones first. +Each "round" of purchasing makes the flowers more expensive, +therefore it is better to buy the cheapest ones in the last "round." + +## Deductions + +- It seems convenient to sort the flower price list entry in descending order +(or in ascending order, traversing the new sorted list in reverse). + +- The number of passes depends on how many "groups" of "k - people" +fit in the list of flowers, that is: +$ \textbf{\#(c) / k}$ (integer division) + +- At first I assumed that the order in which the traversal is done in +the examples was a suggestion of the criteria in which the list of flowers +should be traversed to reach the solution. + + Finally, realizing that the price calculation in descending order + (and "the round" in which the purchase is made) + and the example were equivalent, made me consider the idea that the order of + the examples might just be a distractor, + introduced on purpose to make deducing the solution a little more difficult. diff --git a/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist.md b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist.md new file mode 100644 index 00000000..4cbf0977 --- /dev/null +++ b/docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist.md @@ -0,0 +1,135 @@ +# [Greedy Algorithms: Greedy Florist](https://www.hackerrank.com/challenges/greedy-florist) + +- Difficulty: `#medium` +- Category: `#ProblemSolvingBasic` + +A group of friends want to buy a bouquet of flowers. +The florist wants to maximize his number of new customers and the money he makes. +To do this, he decides he'll multiply the price of each flower by the number +of that customer's previously purchased flowers plus `1`. +The first flower will be original price, $(0 + 1) \times \text{original price}$, +the next will be $(1 + 1) \times \text{original price}$ and so on. + +Given the size of the group of friends, the number of flowers they want +to purchase and the original prices of the flowers, determine the minimum cost +to purchase all of the flowers. +The number of flowers they want equals the length of the array. + +## Example + +`c = [1, 2, 3, 4]` +`k = 3` + +The length of `c = 4`, so they want to buy `4` flowers total. +Each will buy one of the flowers priced `[2, 3, 4]` at the original price. +Having each purchased `x = 1` flower, +the first flower in the list, `c[0]`, will now cost +$ ( + \textsf{\textbf{current purchase}} + + + \textsf{\textbf{previous purchase}} +) \times +\textsf{\textbf{c[0]}} $. +The total cost is `2 + 3 + 4 + 2 = 11`. + +## Function Description + +Complete the getMinimumCost function in the editor below. + +getMinimumCost has the following parameter(s): + +- `int c[n]`: the original price of each flower +- `int k`: the number of friends + +## Returns + +- `int`: the minimum cost to purchase all flowers + +## Input Format + +The first line contains two space-separated integers `n` and `k`, +the number of flowers and the number of friends. +The second line contains `n` space-separated positive integers `c[i]`, +the original price of each flower. + +## Constraints + +- $ 1 \leq n, k \leq 100 $ +- $ 1 \leq c[i] \leq 10^5 $ +- $ answer < 2^31 $ +- $ 0 \leq i \leq n $ + +## Sample Input 0 + +```text +3 3 +2 5 6 +``` + +## Sample Output 0 + +```text +13 +``` + +## Explanation 0 + +There are `n = 3` flowers with costs `c = [2, 5, ,6]` and `k = 3` people in the group. +If each person buys one flower, +the total cost of prices paid is `2 + 5 + 6 = 13` dollars. +Thus, we print `13` as our answer. + +## Sample Input 1 + +```text +3 2 +2 5 6 +``` + +## Sample Output 1 + +```text +15 +``` + +## Explanation 1 + +There are `n = 3` flowers with costs `c = [2, 5, 6]` and `k = 2` +people in the group. +We can minimize the total purchase cost like so: + +1. The first person purchases 2 flowers in order of decreasing price; +this means they buy the more expensive flower ($ c_1 = 5 $) first at price +$ + p_1 = (0 + 1) \times 5 = 5 +$ +dollars and the less expensive flower ($ c_0 = 5 $) second at price +$ + p_0 = (1 + 1) \times 2 = 4 +$ + dollars. +2. The second person buys the most expensive flower at price +$ + p_2 = (0 + 1) \times 6 = 6 +$ +dollars. + +We then print the sum of these purchases, which is `5 + 4 + 6 = 15`, as our answer. + +## Sample Input 2 + +```text +5 3 +1 3 5 7 9 +``` + +## Sample Output 2 + +```text +29 +``` + +## Explanation 2 + +The friends buy flowers for `9, 7`, and `3, 5`, and `1` for a cost of +`9 + 7 + 3 * (1 + 1) + 5 + 1 * (1 + 1) = 29`. diff --git a/src/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.test.ts b/src/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.test.ts new file mode 100644 index 00000000..407b3b61 --- /dev/null +++ b/src/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.test.ts @@ -0,0 +1,22 @@ +import { describe, expect, it } from '@jest/globals'; +import { logger as console } from '../../../logger'; + +import { getMinimumCost } from './greedy_florist'; + +import TEST_CASES from './greedy_florist.testcases.json'; + +describe('greedy_florist', () => { + it('greedy_florist test cases', () => { + expect.assertions(3); + + TEST_CASES.forEach((test) => { + const answer = getMinimumCost(test.k, test.contests); + + console.debug( + `getMinimumCost(${test.k}, ${test.contests}) solution found: ${answer}` + ); + + expect(answer).toStrictEqual(test.expected); + }); + }); +}); diff --git a/src/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.testcases.json b/src/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.testcases.json new file mode 100644 index 00000000..2ab2a7a5 --- /dev/null +++ b/src/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.testcases.json @@ -0,0 +1,20 @@ +[ + { + "title": "Sample Test case 0", + "k": 3, + "contests": [2, 5, 6], + "expected": 13 + }, + { + "title": "Sample Test case 1", + "k": 2, + "contests": [2, 5, 6], + "expected": 15 + }, + { + "title": "Sample Test case 2", + "k": 3, + "contests": [1, 3, 5, 7, 9], + "expected": 29 + } +] diff --git a/src/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.ts b/src/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.ts new file mode 100644 index 00000000..10b0f188 --- /dev/null +++ b/src/hackerrank/interview_preparation_kit/greedy_algorithms/greedy_florist.ts @@ -0,0 +1,24 @@ +/** + * @link Problem definition [[docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist.md]] + * @see Solution Notes: [[docs/hackerrank/interview_preparation_kit/greedy_algorithms/greedy-florist-solution-notes.md]] + */ + +export function getMinimumCost(k: number, c: number[]): number { + const flowers = c + .map((x: number): number => x) + .sort((a: number, b: number): number => b - a); + + let total: number = 0; + + let i: number = 0; + flowers.forEach((flower_cost) => { + const position = Math.floor(i / k); + + total += (position + 1) * flower_cost; + i += 1; + }); + + return total; +} + +export default { getMinimumCost };