Skip to content

Commit 0739537

Browse files
committed
feat: leetcode 1774
1 parent 286e6a5 commit 0739537

File tree

8 files changed

+182
-1
lines changed

8 files changed

+182
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
<p align="center">
44
<!-- TOPICS COUNT START -->
5-
<img src="https://img.shields.io/badge/-进度:561-green" alt="进度:561">
5+
<img src="https://img.shields.io/badge/-进度:562-green" alt="进度:562">
66
<!-- TOPICS COUNT END -->
77
<a href="./assets/docs/TOPICS.md"><img src="https://img.shields.io/badge/-题库目录-blue" alt="题库目录"></a>
88
<a href="./assets/docs/CATEGORIES.md"><img src="https://img.shields.io/badge/-题库分类-red" alt="题库分类"></a>

assets/data/categories.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,6 +1777,12 @@
17771777
"path": "./problemset/maximum-repeating-substring/README.md",
17781778
"difficulty": "简单"
17791779
},
1780+
{
1781+
"id": "1774",
1782+
"title": "最接近目标价格的甜点成本",
1783+
"path": "./problemset/closest-dessert-cost/README.md",
1784+
"difficulty": "中等"
1785+
},
17801786
{
17811787
"id": "1800",
17821788
"title": "最大升序子数组和",

assets/data/topics.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5199,6 +5199,16 @@
51995199
"url": "https://leetcode.cn/problems/count-items-matching-a-rule/",
52005200
"path": "./problemset/count-items-matching-a-rule/README.md"
52015201
},
5202+
{
5203+
"id": "1774",
5204+
"title": {
5205+
"cn": "最接近目标价格的甜点成本",
5206+
"en": "closest-dessert-cost"
5207+
},
5208+
"difficulty": "中等",
5209+
"url": "https://leetcode.cn/problems/closest-dessert-cost/",
5210+
"path": "./problemset/closest-dessert-cost/README.md"
5211+
},
52025212
{
52035213
"id": "1779",
52045214
"title": {

assets/docs/CATEGORIES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@
329329
| 940. [不同的子序列 II](../../problemset/distinct-subsequences-2/README.md) | 困难 |
330330
| 1235. [规划兼职工作](../../problemset/maximum-profit-in-job-scheduling/README.md) | 困难 |
331331
| 1668. [最大重复子字符串](../../problemset/maximum-repeating-substring/README.md) | 简单 |
332+
| 1774. [最接近目标价格的甜点成本](../../problemset/closest-dessert-cost/README.md) | 中等 |
332333
| 1800. [最大升序子数组和](../../problemset/maximum-ascending-subarray-sum/README.md) | 简单 |
333334
| 1994. [好子集的数目](../../problemset/the-number-of-good-subsets/README.md) | 困难 |
334335
| 2100. [适合打劫银行的日子](../../problemset/find-good-days-to-rob-the-bank/README.md) | 中等 |

assets/docs/TOPICS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,8 @@
10401040

10411041
[1773. 统计匹配检索规则的物品数量](../../problemset/count-items-matching-a-rule/README.md)
10421042

1043+
[1774. 最接近目标价格的甜点成本](../../problemset/closest-dessert-cost/README.md)
1044+
10431045
[1779. 找到最近的有相同 X 或 Y 坐标的点](../../problemset/find-nearest-point-that-has-the-same-x-or-y-coordinate/README.md)
10441046

10451047
[1784. 检查二进制字符串字段](../../problemset/check-if-binary-string-has-at-most-one-segment-of-ones/README.md)
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# 最接近目标价格的甜点成本
2+
3+
> 难度:中等
4+
>
5+
> https://leetcode.cn/problems/closest-dessert-cost/
6+
7+
## 题目
8+
9+
你打算做甜点,现在需要购买配料。目前共有 `n` 种冰激凌基料和 `m` 种配料可供选购。而制作甜点需要遵循以下几条规则:
10+
11+
- 必须选择 **一种** 冰激凌基料。
12+
- 可以添加 **一种或多种** 配料,也可以不添加任何配料。
13+
- 每种类型的配料 **最多两份**
14+
15+
给你以下三个输入:
16+
17+
- `baseCosts` ,一个长度为 `n` 的整数数组,其中每个 `baseCosts[i]` 表示第 `i` 种冰激凌基料的价格。
18+
- `toppingCosts`,一个长度为 `m` 的整数数组,其中每个 `toppingCosts[i]` 表示 一份 第 `i` 种冰激凌配料的价格。
19+
- `target` ,一个整数,表示你制作甜点的目标价格。
20+
21+
你希望自己做的甜点总成本尽可能接近目标价格 `target`
22+
23+
返回最接近 `target` 的甜点成本。如果有多种方案,返回 **成本相对较低** 的一种。
24+
25+
### 示例
26+
27+
#### 示例 1:
28+
29+
```
30+
输入:baseCosts = [1,7], toppingCosts = [3,4], target = 10
31+
输出:10
32+
解释:考虑下面的方案组合(所有下标均从 0 开始):
33+
- 选择 1 号基料:成本 7
34+
- 选择 1 份 0 号配料:成本 1 x 3 = 3
35+
- 选择 0 份 1 号配料:成本 0 x 4 = 0
36+
总成本:7 + 3 + 0 = 10 。
37+
```
38+
39+
#### 示例 2:
40+
41+
```
42+
输入:baseCosts = [2,3], toppingCosts = [4,5,100], target = 18
43+
输出:17
44+
解释:考虑下面的方案组合(所有下标均从 0 开始):
45+
- 选择 1 号基料:成本 3
46+
- 选择 1 份 0 号配料:成本 1 x 4 = 4
47+
- 选择 2 份 1 号配料:成本 2 x 5 = 10
48+
- 选择 0 份 2 号配料:成本 0 x 100 = 0
49+
总成本:3 + 4 + 10 + 0 = 17 。不存在总成本为 18 的甜点制作方案。
50+
```
51+
52+
#### 示例 3:
53+
54+
```
55+
输入:baseCosts = [3,10], toppingCosts = [2,5], target = 9
56+
输出:8
57+
解释:可以制作总成本为 8 和 10 的甜点。返回 8 ,因为这是成本更低的方案。
58+
```
59+
60+
#### 示例 4:
61+
62+
```
63+
输入:baseCosts = [10], toppingCosts = [1], target = 1
64+
输出:10
65+
解释:注意,你可以选择不添加任何配料,但你必须选择一种基料。
66+
```
67+
68+
## 解题
69+
70+
```ts
71+
/**
72+
* 动态规划
73+
* @desc 时间复杂度 O(Target*M*N) 空间复杂度 O(Target)
74+
* @param baseCosts
75+
* @param toppingCosts
76+
* @param target
77+
* @returns
78+
*/
79+
export function closestCost(baseCosts: number[], toppingCosts: number[], target: number): number {
80+
const x = Math.min(...baseCosts)
81+
if (x >= target)
82+
return x
83+
84+
const can = new Array(target + 1).fill(0)
85+
let res = 2 * target - x
86+
87+
for (const b of baseCosts) {
88+
if (b <= target) can[b] = true
89+
else res = Math.min(res, b)
90+
}
91+
92+
for (const t of toppingCosts) {
93+
for (let count = 0; count < 2; ++count) {
94+
for (let i = target; i > 0; --i) {
95+
if (can[i] && i + t > target) res = Math.min(res, i + t)
96+
if (i - t > 0) can[i] = can[i] | can[i - t]
97+
}
98+
}
99+
}
100+
101+
for (let i = 0; i <= res - target; ++i) {
102+
if (can[target - i])
103+
return target - i
104+
}
105+
106+
return res
107+
}
108+
```
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { closestCost } from '.'
3+
4+
describe('最接近目标价格的甜点成本', () => {
5+
testCase(closestCost)
6+
})
7+
8+
function testCase(fn: (baseCosts: number[], toppingCosts: number[], target: number) => number) {
9+
it.each([
10+
[[1, 7], [3, 4], 10, 10],
11+
[[2, 3], [4, 5, 100], 18, 17],
12+
[[3, 10], [2, 5], 9, 8],
13+
[[10], [1], 1, 10],
14+
])('示例%#', (baseCosts, toppingCosts, target, expected) => {
15+
expect(fn(baseCosts, toppingCosts, target)).toBe(expected)
16+
})
17+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* 动态规划
3+
* @desc 时间复杂度 O(Target*M*N) 空间复杂度 O(Target)
4+
* @param baseCosts
5+
* @param toppingCosts
6+
* @param target
7+
* @returns
8+
*/
9+
export function closestCost(baseCosts: number[], toppingCosts: number[], target: number): number {
10+
const x = Math.min(...baseCosts)
11+
if (x >= target)
12+
return x
13+
14+
const can = new Array(target + 1).fill(0)
15+
let res = 2 * target - x
16+
17+
for (const b of baseCosts) {
18+
if (b <= target) can[b] = true
19+
else res = Math.min(res, b)
20+
}
21+
22+
for (const t of toppingCosts) {
23+
for (let count = 0; count < 2; ++count) {
24+
for (let i = target; i > 0; --i) {
25+
if (can[i] && i + t > target) res = Math.min(res, i + t)
26+
if (i - t > 0) can[i] = can[i] | can[i - t]
27+
}
28+
}
29+
}
30+
31+
for (let i = 0; i <= res - target; ++i) {
32+
if (can[target - i])
33+
return target - i
34+
}
35+
36+
return res
37+
}

0 commit comments

Comments
 (0)