From f96f58377163444c0970487e65ff55aa7fb6ff4d Mon Sep 17 00:00:00 2001 From: Justin Tse Date: Sat, 2 Sep 2023 20:20:17 +0800 Subject: [PATCH] Add Chapter greedy for JS and TS code (#718) * Fix binary_search_tree TS code * Update binary_search_tree js code style * Add the JavaScript code for Chapter of Greedy * Add the TypeScript code for Chapter of Greedy --------- Co-authored-by: Yudong Jin --- .../chapter_greedy/coin_change_greedy.js | 48 ++++++++++++++++++ .../chapter_greedy/fractional_knapsack.js | 46 +++++++++++++++++ .../javascript/chapter_greedy/max_capacity.js | 33 ++++++++++++ .../chapter_greedy/max_product_cutting.js | 33 ++++++++++++ .../chapter_greedy/coin_change_greedy.ts | 50 +++++++++++++++++++ .../chapter_greedy/fractional_knapsack.ts | 50 +++++++++++++++++++ .../typescript/chapter_greedy/max_capacity.ts | 35 +++++++++++++ .../chapter_greedy/max_product_cutting.ts | 35 +++++++++++++ 8 files changed, 330 insertions(+) create mode 100644 codes/javascript/chapter_greedy/coin_change_greedy.js create mode 100644 codes/javascript/chapter_greedy/fractional_knapsack.js create mode 100644 codes/javascript/chapter_greedy/max_capacity.js create mode 100644 codes/javascript/chapter_greedy/max_product_cutting.js create mode 100644 codes/typescript/chapter_greedy/coin_change_greedy.ts create mode 100644 codes/typescript/chapter_greedy/fractional_knapsack.ts create mode 100644 codes/typescript/chapter_greedy/max_capacity.ts create mode 100644 codes/typescript/chapter_greedy/max_product_cutting.ts diff --git a/codes/javascript/chapter_greedy/coin_change_greedy.js b/codes/javascript/chapter_greedy/coin_change_greedy.js new file mode 100644 index 000000000..4be23dfeb --- /dev/null +++ b/codes/javascript/chapter_greedy/coin_change_greedy.js @@ -0,0 +1,48 @@ +/** + * File: coin_change_greedy.js + * Created Time: 2023-09-02 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 零钱兑换:贪心 */ +function coin_change_greedy(coins, amt) { + // 假设 coins 数组有序 + let i = coins.length - 1; + let count = 0; + // 循环进行贪心选择,直到无剩余金额 + while (amt > 0) { + // 找到小于且最接近剩余金额的硬币 + while (i > 0 && coins[i] > amt) { + i--; + } + // 选择 coins[i] + amt -= coins[i]; + count++; + } + // 若未找到可行方案,则返回 -1 + return amt === 0 ? count : -1; +} + +/* Driver Code */ +// 贪心:能够保证找到全局最优解 +let coins = [1, 5, 10, 20, 50, 100]; +let amt = 186; +let res = coin_change_greedy(coins, amt); +console.log(`\ncoins = ${coins}, amt = ${amt}`); +console.log(`凑到 ${amt} 所需的最少硬币数量为 ${res}`); + +// 贪心:无法保证找到全局最优解 +coins = [1, 20, 50]; +amt = 60; +res = coin_change_greedy(coins, amt); +console.log(`\ncoins = ${coins}, amt = ${amt}`); +console.log(`凑到 ${amt} 所需的最少硬币数量为 ${res}`); +console.log("实际上需要的最少数量为 3 ,即 20 + 20 + 20"); + +// 贪心:无法保证找到全局最优解 +coins = [1, 49, 50]; +amt = 98; +res = coin_change_greedy(coins, amt); +console.log(`\ncoins = ${coins}, amt = ${amt}`); +console.log(`凑到 ${amt} 所需的最少硬币数量为 ${res}`); +console.log("实际上需要的最少数量为 2 ,即 49 + 49"); diff --git a/codes/javascript/chapter_greedy/fractional_knapsack.js b/codes/javascript/chapter_greedy/fractional_knapsack.js new file mode 100644 index 000000000..a09b19a79 --- /dev/null +++ b/codes/javascript/chapter_greedy/fractional_knapsack.js @@ -0,0 +1,46 @@ +/** + * File: fractional_knapsack.js + * Created Time: 2023-09-02 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 物品 */ +class Item { + constructor(w, v) { + this.w = w; // 物品重量 + this.v = v; // 物品价值 + } +} + +/* 分数背包:贪心 */ +function fractional_knapsack(wgt, val, cap) { + // 创建物品列表,包含两个属性:重量、价值 + const items = wgt.map((w, i) => new Item(w, val[i])); + // 按照单位价值 item.v / item.w 从高到低进行排序 + items.sort((a, b) => (b.v / b.w) - (a.v / a.w)); + // 循环贪心选择 + let res = 0; + for (const item of items) { + if (item.w <= cap) { + // 若剩余容量充足,则将当前物品整个装进背包 + res += item.v; + cap -= item.w; + } else { + // 若剩余容量不足,则将当前物品的一部分装进背包 + res += (item.v / item.w) * cap; + // 已无剩余容量,因此跳出循环 + break; + } + } + return res; +} + +/* Driver Code */ +const wgt = [10, 20, 30, 40, 50]; +const val = [50, 120, 150, 210, 240]; +const cap = 50; +const n = wgt.length; + +// 贪心算法 +const res = fractional_knapsack(wgt, val, cap); +console.log(`不超过背包容量的最大物品价值为 ${res}`); diff --git a/codes/javascript/chapter_greedy/max_capacity.js b/codes/javascript/chapter_greedy/max_capacity.js new file mode 100644 index 000000000..07858f3d0 --- /dev/null +++ b/codes/javascript/chapter_greedy/max_capacity.js @@ -0,0 +1,33 @@ +/** + * File: max_capacity.js + * Created Time: 2023-09-02 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 最大容量:贪心 */ +function max_capacity(ht) { + // 初始化 i, j 分列数组两端 + let i = 0, j = ht.length - 1; + // 初始最大容量为 0 + let res = 0; + // 循环贪心选择,直至两板相遇 + while (i < j) { + // 更新最大容量 + const cap = Math.min(ht[i], ht[j]) * (j - i); + res = Math.max(res, cap); + // 向内移动短板 + if (ht[i] < ht[j]) { + i += 1; + } else { + j -= 1; + } + } + return res; +} + +/* Driver Code */ +const ht = [3, 8, 5, 2, 7, 7, 3, 4]; + +// 贪心算法 +const res = max_capacity(ht); +console.log(`最大容量为 ${res}`); diff --git a/codes/javascript/chapter_greedy/max_product_cutting.js b/codes/javascript/chapter_greedy/max_product_cutting.js new file mode 100644 index 000000000..e2c6bf6e2 --- /dev/null +++ b/codes/javascript/chapter_greedy/max_product_cutting.js @@ -0,0 +1,33 @@ +/** + * File: max_product_cutting.js + * Created Time: 2023-09-02 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 最大切分乘积:贪心 */ +function max_product_cutting(n) { + // 当 n <= 3 时,必须切分出一个 1 + if (n <= 3) { + return 1 * (n - 1); + } + // 贪心地切分出 3 ,a 为 3 的个数,b 为余数 + let a = Math.floor(n / 3); + let b = n % 3; + if (b === 1) { + // 当余数为 1 时,将一对 1 * 3 转化为 2 * 2 + return Math.pow(3, a - 1) * 2 * 2; + } + if (b === 2) { + // 当余数为 2 时,不做处理 + return Math.pow(3, a) * 2; + } + // 当余数为 0 时,不做处理 + return Math.pow(3, a); +} + +/* Driver Code */ +let n = 58; + +// 贪心算法 +let res = max_product_cutting(n); +console.log(`最大切分乘积为 ${res}`); diff --git a/codes/typescript/chapter_greedy/coin_change_greedy.ts b/codes/typescript/chapter_greedy/coin_change_greedy.ts new file mode 100644 index 000000000..678aaa21f --- /dev/null +++ b/codes/typescript/chapter_greedy/coin_change_greedy.ts @@ -0,0 +1,50 @@ +/** + * File: coin_change_greedy.ts + * Created Time: 2023-09-02 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 零钱兑换:贪心 */ +function coin_change_greedy(coins: number[], amt: number): number { + // 假设 coins 数组有序 + let i = coins.length - 1; + let count = 0; + // 循环进行贪心选择,直到无剩余金额 + while (amt > 0) { + // 找到小于且最接近剩余金额的硬币 + while (i > 0 && coins[i] > amt) { + i--; + } + // 选择 coins[i] + amt -= coins[i]; + count++; + } + // 若未找到可行方案,则返回 -1 + return amt === 0 ? count : -1; +} + +/* Driver Code */ +// 贪心:能够保证找到全局最优解 +let coins: number[] = [1, 5, 10, 20, 50, 100]; +let amt: number = 186; +let res: number = coin_change_greedy(coins, amt); +console.log(`\ncoins = ${coins}, amt = ${amt}`); +console.log(`凑到 ${amt} 所需的最少硬币数量为 ${res}`); + +// 贪心:无法保证找到全局最优解 +coins = [1, 20, 50]; +amt = 60; +res = coin_change_greedy(coins, amt); +console.log(`\ncoins = ${coins}, amt = ${amt}`); +console.log(`凑到 ${amt} 所需的最少硬币数量为 ${res}`); +console.log("实际上需要的最少数量为 3 ,即 20 + 20 + 20"); + +// 贪心:无法保证找到全局最优解 +coins = [1, 49, 50]; +amt = 98; +res = coin_change_greedy(coins, amt); +console.log(`\ncoins = ${coins}, amt = ${amt}`); +console.log(`凑到 ${amt} 所需的最少硬币数量为 ${res}`); +console.log("实际上需要的最少数量为 2 ,即 49 + 49"); + +export { }; diff --git a/codes/typescript/chapter_greedy/fractional_knapsack.ts b/codes/typescript/chapter_greedy/fractional_knapsack.ts new file mode 100644 index 000000000..dfcf26ae9 --- /dev/null +++ b/codes/typescript/chapter_greedy/fractional_knapsack.ts @@ -0,0 +1,50 @@ +/** + * File: fractional_knapsack.ts + * Created Time: 2023-09-02 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 物品 */ +class Item { + w: number; // 物品重量 + v: number; // 物品价值 + + constructor(w: number, v: number) { + this.w = w; + this.v = v; + } +} + +/* 分数背包:贪心 */ +function fractional_knapsack(wgt: number[], val: number[], cap: number): number { + // 创建物品列表,包含两个属性:重量、价值 + const items: Item[] = wgt.map((w, i) => new Item(w, val[i])); + // 按照单位价值 item.v / item.w 从高到低进行排序 + items.sort((a, b) => (b.v / b.w) - (a.v / a.w)); + // 循环贪心选择 + let res = 0; + for (const item of items) { + if (item.w <= cap) { + // 若剩余容量充足,则将当前物品整个装进背包 + res += item.v; + cap -= item.w; + } else { + // 若剩余容量不足,则将当前物品的一部分装进背包 + res += (item.v / item.w) * cap; + // 已无剩余容量,因此跳出循环 + break; + } + } + return res; +} + +/* Driver Code */ +const wgt: number[] = [10, 20, 30, 40, 50]; +const val: number[] = [50, 120, 150, 210, 240]; +const cap: number = 50; + +// 贪心算法 +const res: number = fractional_knapsack(wgt, val, cap); +console.log(`不超过背包容量的最大物品价值为 ${res}`); + +export { }; diff --git a/codes/typescript/chapter_greedy/max_capacity.ts b/codes/typescript/chapter_greedy/max_capacity.ts new file mode 100644 index 000000000..2f8d99bea --- /dev/null +++ b/codes/typescript/chapter_greedy/max_capacity.ts @@ -0,0 +1,35 @@ +/** + * File: max_capacity.ts + * Created Time: 2023-09-02 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 最大容量:贪心 */ +function max_capacity(ht: number[]): number { + // 初始化 i, j 分列数组两端 + let i = 0, j = ht.length - 1; + // 初始最大容量为 0 + let res = 0; + // 循环贪心选择,直至两板相遇 + while (i < j) { + // 更新最大容量 + const cap: number = Math.min(ht[i], ht[j]) * (j - i); + res = Math.max(res, cap); + // 向内移动短板 + if (ht[i] < ht[j]) { + i += 1; + } else { + j -= 1; + } + } + return res; +} + +/* Driver Code */ +const ht: number[] = [3, 8, 5, 2, 7, 7, 3, 4]; + +// 贪心算法 +const res: number = max_capacity(ht); +console.log(`最大容量为 ${res}`); + +export { }; diff --git a/codes/typescript/chapter_greedy/max_product_cutting.ts b/codes/typescript/chapter_greedy/max_product_cutting.ts new file mode 100644 index 000000000..2d21c5318 --- /dev/null +++ b/codes/typescript/chapter_greedy/max_product_cutting.ts @@ -0,0 +1,35 @@ +/** + * File: max_product_cutting.ts + * Created Time: 2023-09-02 + * Author: Justin (xiefahit@gmail.com) + */ + +/* 最大切分乘积:贪心 */ +function max_product_cutting(n: number): number { + // 当 n <= 3 时,必须切分出一个 1 + if (n <= 3) { + return 1 * (n - 1); + } + // 贪心地切分出 3 ,a 为 3 的个数,b 为余数 + let a: number = Math.floor(n / 3); + let b: number = n % 3; + if (b === 1) { + // 当余数为 1 时,将一对 1 * 3 转化为 2 * 2 + return Math.pow(3, a - 1) * 2 * 2; + } + if (b === 2) { + // 当余数为 2 时,不做处理 + return Math.pow(3, a) * 2; + } + // 当余数为 0 时,不做处理 + return Math.pow(3, a); +} + +/* Driver Code */ +let n: number = 58; + +// 贪心算法 +let res: number = max_product_cutting(n); +console.log(`最大切分乘积为 ${res}`); + +export { };