Skip to content

feat: add solutions to lc problem: No.3213 #3224

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
Jul 8, 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
4 changes: 1 addition & 3 deletions solution/2500-2599/2582.Pass the Pillow/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ tags:

<!-- description:start -->

<p><code>n</code> 个人站成一排,按从 <code>1</code> 到 <code>n</code> 编号。</p>

<p>最初,排在队首的第一个人拿着一个枕头。每秒钟,拿着枕头的人会将枕头传递给队伍中的下一个人。一旦枕头到达队首或队尾,传递方向就会改变,队伍会继续沿相反方向传递枕头。</p>
<p><code>n</code> 个人站成一排,按从 <code>1</code> 到 <code>n</code> 编号。最初,排在队首的第一个人拿着一个枕头。每秒钟,拿着枕头的人会将枕头传递给队伍中的下一个人。一旦枕头到达队首或队尾,传递方向就会改变,队伍会继续沿相反方向传递枕头。</p>

<ul>
<li>例如,当枕头到达第 <code>n</code> 个人时,TA 会将枕头传递给第 <code>n - 1</code> 个人,然后传递给第 <code>n - 2</code> 个人,依此类推。</li>
Expand Down
4 changes: 2 additions & 2 deletions solution/3100-3199/3100.Water Bottles II/Solution.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
impl Solution {
pub fn max_bottles_drunk(mut num_bottles: i32, mut num_exchange: i32) -> i32 {
let mut ans = num_bottles;

while num_bottles >= num_exchange {
num_bottles -= num_exchange;
num_exchange += 1;
ans += 1;
num_bottles += 1;
}

ans
}
}
246 changes: 241 additions & 5 deletions solution/3200-3299/3213.Construct String with Minimum Cost/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,32 +77,268 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3200-3299/3213.Co

<!-- solution:start -->

### 方法一
### 方法一:字符串哈希 + 动态规划 + 枚举长度

我们定义 $f[i]$ 表示构造 $\textit{target}$ 前 $i$ 个字符的最小代价,初始时 $f[0] = 0$,其余值均为无穷大。答案为 $f[n]$,其中 $n$ 是 $\textit{target}$ 的长度。

对于当前 $f[i]$,考虑枚举单词的长度 $j$,如果 $j \leq i$,那么我们可以考虑从 $i - j + 1$ 到 $i$ 这段区间的哈希值,如果这个哈希值对应的单词存在,那么我们可以转移从 $f[i - j]$ 转移到 $f[i]$。状态转移方程如下:

$$
f[i] = \min(f[i], f[i - j] + \textit{cost}[k])
$$

其中 $textit{cost}[k]$ 表示长度为 $j$ 的单词且哈希值与 $\textit{target}[i - j + 1, i]$ 相同的单词的最小代价。

时间复杂度 $O(n \times \sqrt{L})$,空间复杂度 $O(n)$。其中 $n$ 是 $\textit{target}$ 的长度,而 $L$ 是数组 $\textit{words}$ 中所有单词的长度之和。

<!-- tabs:start -->

#### Python3

```python

class Solution:
def minimumCost(self, target: str, words: List[str], costs: List[int]) -> int:
base, mod = 13331, 998244353
n = len(target)
h = [0] * (n + 1)
p = [1] * (n + 1)
for i, c in enumerate(target, 1):
h[i] = (h[i - 1] * base + ord(c)) % mod
p[i] = (p[i - 1] * base) % mod
f = [0] + [inf] * n
ss = sorted(set(map(len, words)))
d = defaultdict(lambda: inf)
min = lambda a, b: a if a < b else b
for w, c in zip(words, costs):
x = 0
for ch in w:
x = (x * base + ord(ch)) % mod
d[x] = min(d[x], c)
for i in range(1, n + 1):
for j in ss:
if j > i:
break
x = (h[i] - h[i - j] * p[j]) % mod
f[i] = min(f[i], f[i - j] + d[x])
return f[n] if f[n] < inf else -1
```

#### Java

```java

class Hashing {
private final long[] p;
private final long[] h;
private final long mod;

public Hashing(String word, long base, int mod) {
int n = word.length();
p = new long[n + 1];
h = new long[n + 1];
p[0] = 1;
this.mod = mod;
for (int i = 1; i <= n; i++) {
p[i] = p[i - 1] * base % mod;
h[i] = (h[i - 1] * base + word.charAt(i - 1)) % mod;
}
}

public long query(int l, int r) {
return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
}

class Solution {
public int minimumCost(String target, String[] words, int[] costs) {
final int base = 13331;
final int mod = 998244353;
final int inf = Integer.MAX_VALUE / 2;

int n = target.length();
Hashing hashing = new Hashing(target, base, mod);

int[] f = new int[n + 1];
Arrays.fill(f, inf);
f[0] = 0;

TreeSet<Integer> ss = new TreeSet<>();
for (String w : words) {
ss.add(w.length());
}

Map<Long, Integer> d = new HashMap<>();
for (int i = 0; i < words.length; i++) {
long x = 0;
for (char c : words[i].toCharArray()) {
x = (x * base + c) % mod;
}
d.merge(x, costs[i], Integer::min);
}

for (int i = 1; i <= n; i++) {
for (int j : ss) {
if (j > i) {
break;
}
long x = hashing.query(i - j + 1, i);
f[i] = Math.min(f[i], f[i - j] + d.getOrDefault(x, inf));
}
}

return f[n] >= inf ? -1 : f[n];
}
}
```

#### C++

```cpp

class Hashing {
private:
vector<long> p, h;
long mod;

public:
Hashing(const string& word, long base, long mod)
: p(word.size() + 1, 1)
, h(word.size() + 1, 0)
, mod(mod) {
for (int i = 1; i <= word.size(); ++i) {
p[i] = p[i - 1] * base % mod;
h[i] = (h[i - 1] * base + word[i - 1]) % mod;
}
}

long query(int l, int r) {
return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
};

class Solution {
public:
int minimumCost(string target, vector<string>& words, vector<int>& costs) {
const int base = 13331;
const int mod = 998244353;
const int inf = INT_MAX / 2;

int n = target.size();
Hashing hashing(target, base, mod);

vector<int> f(n + 1, inf);
f[0] = 0;

set<int> ss;
for (const string& w : words) {
ss.insert(w.size());
}

unordered_map<long, int> d;
for (int i = 0; i < words.size(); ++i) {
long x = 0;
for (char c : words[i]) {
x = (x * base + c) % mod;
}
d[x] = d.find(x) == d.end() ? costs[i] : min(d[x], costs[i]);
}

for (int i = 1; i <= n; ++i) {
for (int j : ss) {
if (j > i) {
break;
}
long x = hashing.query(i - j + 1, i);
if (d.contains(x)) {
f[i] = min(f[i], f[i - j] + d[x]);
}
}
}

return f[n] >= inf ? -1 : f[n];
}
};
```

#### Go

```go

type Hashing struct {
p []int64
h []int64
mod int64
}

func NewHashing(word string, base, mod int64) *Hashing {
n := len(word)
p := make([]int64, n+1)
h := make([]int64, n+1)
p[0] = 1
for i := 1; i <= n; i++ {
p[i] = p[i-1] * base % mod
h[i] = (h[i-1]*base + int64(word[i-1])) % mod
}
return &Hashing{p, h, mod}
}

func (hs *Hashing) query(l, r int) int64 {
return (hs.h[r] - hs.h[l-1]*hs.p[r-l+1]%hs.mod + hs.mod) % hs.mod
}

func minimumCost(target string, words []string, costs []int) int {
const base = 13331
const mod = 998244353
const inf = math.MaxInt32 / 2

n := len(target)
hashing := NewHashing(target, base, mod)

f := make([]int, n+1)
for i := range f {
f[i] = inf
}
f[0] = 0

ss := make(map[int]struct{})
for _, w := range words {
ss[len(w)] = struct{}{}
}
lengths := make([]int, 0, len(ss))
for length := range ss {
lengths = append(lengths, length)
}
sort.Ints(lengths)

d := make(map[int64]int)
for i, w := range words {
var x int64
for _, c := range w {
x = (x*base + int64(c)) % mod
}
if existingCost, exists := d[x]; exists {
if costs[i] < existingCost {
d[x] = costs[i]
}
} else {
d[x] = costs[i]
}
}

for i := 1; i <= n; i++ {
for _, j := range lengths {
if j > i {
break
}
x := hashing.query(i-j+1, i)
if cost, ok := d[x]; ok {
f[i] = min(f[i], f[i-j]+cost)
}
}
}

if f[n] >= inf {
return -1
}
return f[n]
}
```

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