Skip to content

feat: add solutions to lc problems: No.3346,3347 #3739

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 39 additions & 14 deletions solution/1500-1599/1547.Minimum Cost to Cut a Stick/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,17 @@ tags:

### 方法一:动态规划(区间 DP)

我们可以往切割点数组 $cuts$ 中添加两个元素,分别是 $0$ 和 $n$,表示棍子的两端。然后我们对 $cuts$ 数组进行排序,这样我们就可以将整个棍子切割为若干个区间,每个区间都有两个切割点。不妨设此时 $cuts$ 数组的长度为 $m$。
我们可以往切割点数组 $\textit{cuts}$ 中添加两个元素,分别是 $0$ 和 $n$,表示棍子的两端。然后我们对 $\textit{cuts}$ 数组进行排序,这样我们就可以将整个棍子切割为若干个区间,每个区间都有两个切割点。不妨设此时 $\textit{cuts}$ 数组的长度为 $m$。

接下来,我们定义 $f[i][j]$ 表示切割区间 $[cuts[i],..cuts[j]]$ 的最小成本。
接下来,我们定义 $\textit{f}[i][j]$ 表示切割区间 $[\textit{cuts}[i],..\textit{cuts}[j]]$ 的最小成本。

如果一个区间只有两个切割点,也就是说,我们无需切割这个区间,那么 $f[i][j] = 0$。
如果一个区间只有两个切割点,也就是说,我们无需切割这个区间,那么 $\textit{f}[i][j] = 0$。

否则,我们枚举区间的长度 $l$,其中 $l$ 等于切割点的数量减去 $1$。然后我们枚举区间的左端点 $i$,右端点 $j$ 可以由 $i + l$ 得到。对于每个区间,我们枚举它的切割点 $k$,其中 $i \lt k \lt j$,那么我们可以将区间 $[i, j]$ 切割为 $[i, k]$ 和 $[k, j]$,此时的成本为 $f[i][k] + f[k][j] + cuts[j] - cuts[i]$,我们取所有可能的 $k$ 中的最小值,即为 $f[i][j]$ 的值。
否则,我们枚举区间的长度 $l$,其中 $l$ 等于切割点的数量减去 $1$。然后我们枚举区间的左端点 $i$,右端点 $j$ 可以由 $i + l$ 得到。对于每个区间,我们枚举它的切割点 $k$,其中 $i \lt k \lt j$,那么我们可以将区间 $[i, j]$ 切割为 $[i, k]$ 和 $[k, j]$,此时的成本为 $\textit{f}[i][k] + \textit{f}[k][j] + \textit{cuts}[j] - \textit{cuts}[i]$,我们取所有可能的 $k$ 中的最小值,即为 $\textit{f}[i][j]$ 的值。

最后,我们返回 $f[0][m - 1]$。
最后,我们返回 $\textit{f}[0][m - 1]$。

时间复杂度 $O(m^3)$,空间复杂度 $O(m^2)$。其中 $m$ 为修改后的 $cuts$ 数组的长度。
时间复杂度 $O(m^3)$,空间复杂度 $O(m^2)$。其中 $m$ 为修改后的 $\textit{cuts}$ 数组的长度。

<!-- tabs:start -->

Expand Down Expand Up @@ -186,15 +186,15 @@ func minCost(n int, cuts []int) int {

```ts
function minCost(n: number, cuts: number[]): number {
cuts.push(0);
cuts.push(n);
cuts.push(0, n);
cuts.sort((a, b) => a - b);
const m = cuts.length;
const f: number[][] = new Array(m).fill(0).map(() => new Array(m).fill(0));
for (let i = m - 2; i >= 0; --i) {
for (let j = i + 2; j < m; ++j) {
f[i][j] = 1 << 30;
for (let k = i + 1; k < j; ++k) {
const f: number[][] = Array.from({ length: m }, () => Array(m).fill(0));
for (let l = 2; l < m; l++) {
for (let i = 0; i < m - l; i++) {
const j = i + l;
f[i][j] = Infinity;
for (let k = i + 1; k < j; k++) {
f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + cuts[j] - cuts[i]);
}
}
Expand All @@ -209,7 +209,11 @@ function minCost(n: number, cuts: number[]): number {

<!-- solution:start -->

### 方法二
### 方法二:动态规划(另一种枚举方式)

我们也可以从大到小枚举 $i$,从小到大枚举 $j$,这样可以保证在计算 $f[i][j]$ 时,状态 $f[i][k]$ 和 $f[k][j]$ 都已经被计算过了,其中 $i \lt k \lt j$。

时间复杂度 $O(m^3)$,空间复杂度 $O(m^2)$。其中 $m$ 为修改后的 $\textit{cuts}$ 数组的长度。

<!-- tabs:start -->

Expand Down Expand Up @@ -304,6 +308,27 @@ func minCost(n int, cuts []int) int {
}
```

#### TypeScript

```ts
function minCost(n: number, cuts: number[]): number {
cuts.push(0);
cuts.push(n);
cuts.sort((a, b) => a - b);
const m = cuts.length;
const f: number[][] = Array.from({ length: m }, () => Array(m).fill(0));
for (let i = m - 2; i >= 0; --i) {
for (let j = i + 2; j < m; ++j) {
f[i][j] = 1 << 30;
for (let k = i + 1; k < j; ++k) {
f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + cuts[j] - cuts[i]);
}
}
}
return f[0][m - 1];
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
53 changes: 39 additions & 14 deletions solution/1500-1599/1547.Minimum Cost to Cut a Stick/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,17 @@ There are much ordering with total cost &lt;= 25, for example, the order [4, 6,

### Solution 1: Dynamic Programming (Interval DP)

We can add two elements to the cut array $cuts$, which are $0$ and $n$, representing the two ends of the stick. Then we sort the $cuts$ array, so that we can cut the entire stick into several intervals, each interval has two cut points. Suppose the length of the $cuts$ array at this time is $m$.
We can add two elements to the array $\textit{cuts}$, namely $0$ and $n$, representing the two ends of the stick. Then we sort the $\textit{cuts}$ array, so we can divide the entire stick into several intervals, each with two cut points. Let the length of the $\textit{cuts}$ array be $m$.

Next, we define $f[i][j]$ to represent the minimum cost of cutting the interval $[cuts[i],..cuts[j]]$.
Next, we define $\textit{f}[i][j]$ to represent the minimum cost to cut the interval $[\textit{cuts}[i], \textit{cuts}[j]]$.

If an interval only has two cut points, that is, we do not need to cut this interval, then $f[i][j] = 0$.
If an interval has only two cut points, meaning we do not need to cut this interval, then $\textit{f}[i][j] = 0$.

Otherwise, we enumerate the length of the interval $l$, where $l$ is the number of cut points minus $1$. Then we enumerate the left endpoint $i$ of the interval, and the right endpoint $j$ can be obtained by $i + l$. For each interval, we enumerate its cut point $k$, where $i \lt k \lt j$, then we can cut the interval $[i, j]$ into $[i, k]$ and $[k, j]$, the cost at this time is $f[i][k] + f[k][j] + cuts[j] - cuts[i]$, we take the minimum value of all possible $k$, which is the value of $f[i][j]$.
Otherwise, we enumerate the length $l$ of the interval, where $l$ is equal to the number of cut points minus $1$. Then we enumerate the left endpoint $i$ of the interval, and the right endpoint $j$ can be obtained by $i + l$. For each interval, we enumerate its cut point $k$, where $i \lt k \lt j$. We can then divide the interval $[i, j]$ into $[i, k]$ and $[k, j]$. The cost at this point is $\textit{f}[i][k] + \textit{f}[k][j] + \textit{cuts}[j] - \textit{cuts}[i]$. We take the minimum value among all possible $k$, which is the value of $\textit{f}[i][j]$.

Finally, we return $f[0][m - 1]$.
Finally, we return $\textit{f}[0][m - 1]$.

The time complexity is $O(m^3)$, and the space complexity is $O(m^2)$. Here, $m$ is the length of the modified $cuts$ array.
The time complexity is $O(m^3)$, and the space complexity is $O(m^2)$. Here, $m$ is the length of the modified $\textit{cuts}$ array.

<!-- tabs:start -->

Expand Down Expand Up @@ -181,15 +181,15 @@ func minCost(n int, cuts []int) int {

```ts
function minCost(n: number, cuts: number[]): number {
cuts.push(0);
cuts.push(n);
cuts.push(0, n);
cuts.sort((a, b) => a - b);
const m = cuts.length;
const f: number[][] = new Array(m).fill(0).map(() => new Array(m).fill(0));
for (let i = m - 2; i >= 0; --i) {
for (let j = i + 2; j < m; ++j) {
f[i][j] = 1 << 30;
for (let k = i + 1; k < j; ++k) {
const f: number[][] = Array.from({ length: m }, () => Array(m).fill(0));
for (let l = 2; l < m; l++) {
for (let i = 0; i < m - l; i++) {
const j = i + l;
f[i][j] = Infinity;
for (let k = i + 1; k < j; k++) {
f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + cuts[j] - cuts[i]);
}
}
Expand All @@ -204,7 +204,11 @@ function minCost(n: number, cuts: number[]): number {

<!-- solution:start -->

### Solution 2
### Solution 2: Dynamic Programming (Another Enumeration Method)

We can also enumerate $i$ from large to small and $j$ from small to large. This ensures that when calculating $f[i][j]$, the states $f[i][k]$ and $f[k][j]$ have already been computed, where $i \lt k \lt j$.

The time complexity is $O(m^3)$, and the space complexity is $O(m^2)$. Here, $m$ is the length of the modified $\textit{cuts}$ array.

<!-- tabs:start -->

Expand Down Expand Up @@ -299,6 +303,27 @@ func minCost(n int, cuts []int) int {
}
```

#### TypeScript

```ts
function minCost(n: number, cuts: number[]): number {
cuts.push(0);
cuts.push(n);
cuts.sort((a, b) => a - b);
const m = cuts.length;
const f: number[][] = Array.from({ length: m }, () => Array(m).fill(0));
for (let i = m - 2; i >= 0; --i) {
for (let j = i + 2; j < m; ++j) {
f[i][j] = 1 << 30;
for (let k = i + 1; k < j; ++k) {
f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + cuts[j] - cuts[i]);
}
}
}
return f[0][m - 1];
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
14 changes: 7 additions & 7 deletions solution/1500-1599/1547.Minimum Cost to Cut a Stick/Solution.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
function minCost(n: number, cuts: number[]): number {
cuts.push(0);
cuts.push(n);
cuts.push(0, n);
cuts.sort((a, b) => a - b);
const m = cuts.length;
const f: number[][] = new Array(m).fill(0).map(() => new Array(m).fill(0));
for (let i = m - 2; i >= 0; --i) {
for (let j = i + 2; j < m; ++j) {
f[i][j] = 1 << 30;
for (let k = i + 1; k < j; ++k) {
const f: number[][] = Array.from({ length: m }, () => Array(m).fill(0));
for (let l = 2; l < m; l++) {
for (let i = 0; i < m - l; i++) {
const j = i + l;
f[i][j] = Infinity;
for (let k = i + 1; k < j; k++) {
f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + cuts[j] - cuts[i]);
}
}
Expand Down
16 changes: 16 additions & 0 deletions solution/1500-1599/1547.Minimum Cost to Cut a Stick/Solution2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
function minCost(n: number, cuts: number[]): number {
cuts.push(0);
cuts.push(n);
cuts.sort((a, b) => a - b);
const m = cuts.length;
const f: number[][] = Array.from({ length: m }, () => Array(m).fill(0));
for (let i = m - 2; i >= 0; --i) {
for (let j = i + 2; j < m; ++j) {
f[i][j] = 1 << 30;
for (let k = i + 1; k < j; ++k) {
f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + cuts[j] - cuts[i]);
}
}
}
return f[0][m - 1];
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,25 +86,124 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3346.Ma
#### Python3

```python

class Solution:
def maxFrequency(self, nums: List[int], k: int, numOperations: int) -> int:
cnt = defaultdict(int)
d = defaultdict(int)
for x in nums:
cnt[x] += 1
d[x] += 0
d[x - k] += 1
d[x + k + 1] -= 1
ans = s = 0
for x, t in sorted(d.items()):
s += t
ans = max(ans, min(s, cnt[x] + numOperations))
return ans
```

#### Java

```java

class Solution {
public int maxFrequency(int[] nums, int k, int numOperations) {
Map<Integer, Integer> cnt = new HashMap<>();
TreeMap<Integer, Integer> d = new TreeMap<>();
for (int x : nums) {
cnt.merge(x, 1, Integer::sum);
d.putIfAbsent(x, 0);
d.merge(x - k, 1, Integer::sum);
d.merge(x + k + 1, -1, Integer::sum);
}
int ans = 0, s = 0;
for (var e : d.entrySet()) {
int x = e.getKey(), t = e.getValue();
s += t;
ans = Math.max(ans, Math.min(s, cnt.getOrDefault(x, 0) + numOperations));
}
return ans;
}
}
```

#### C++

```cpp

class Solution {
public:
int maxFrequency(vector<int>& nums, int k, int numOperations) {
unordered_map<int, int> cnt;
map<int, int> d;

for (int x : nums) {
cnt[x]++;
d[x];
d[x - k]++;
d[x + k + 1]--;
}

int ans = 0, s = 0;
for (const auto& [x, t] : d) {
s += t;
ans = max(ans, min(s, cnt[x] + numOperations));
}

return ans;
}
};
```

#### Go

```go
func maxFrequency(nums []int, k int, numOperations int) (ans int) {
cnt := make(map[int]int)
d := make(map[int]int)
for _, x := range nums {
cnt[x]++
d[x] = d[x]
d[x-k]++
d[x+k+1]--
}

s := 0
keys := make([]int, 0, len(d))
for key := range d {
keys = append(keys, key)
}
sort.Ints(keys)
for _, x := range keys {
s += d[x]
ans = max(ans, min(s, cnt[x]+numOperations))
}

return
}
```

#### TypeScript

```ts
function maxFrequency(nums: number[], k: number, numOperations: number): number {
const cnt: Record<number, number> = {};
const d: Record<number, number> = {};
for (const x of nums) {
cnt[x] = (cnt[x] || 0) + 1;
d[x] = d[x] || 0;
d[x - k] = (d[x - k] || 0) + 1;
d[x + k + 1] = (d[x + k + 1] || 0) - 1;
}
let [ans, s] = [0, 0];
const keys = Object.keys(d)
.map(Number)
.sort((a, b) => a - b);
for (const x of keys) {
s += d[x];
ans = Math.max(ans, Math.min(s, (cnt[x] || 0) + numOperations));
}

return ans;
}
```

<!-- tabs:end -->
Expand Down
Loading
Loading