Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 00ce7cb

Browse files
authored
feat: update solutions to lc problems: No.2901, 2902, 2911 (#1893)
1 parent 8be44f3 commit 00ce7cb

File tree

7 files changed

+412
-0
lines changed

7 files changed

+412
-0
lines changed

‎solution/2900-2999/2901.Longest Unequal Adjacent Groups Subsequence II/README.md‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@
8080

8181
时间复杂度 $O(n^2 \times L),ドル空间复杂度 $O(n)$。其中 $L$ 表示单词的最大长度。
8282

83+
**优化:空间换时间**
84+
85+
**方法一**中,我们需要枚举所有的 $i$ 和 $j$ 组合, 这一步可以通过维护一个通配符哈希表来优化. 对于每个字符串 $word[i],ドル 我们枚举它的每个字符, 将其替换为通配符, 然后将替换后的字符串作为键, 将其下标作为值存入哈希表中. 这样我们可以在 $O(L)$ 时间内找到所有距离 $word[i]$ 汉明距离为 1 的 $word[j]$. 尽管时间复杂度仍然是 $O(n^2 \times L),ドル 但平均复杂度会有所降低.
86+
8387
<!-- tabs:start -->
8488

8589
### **Python3**
@@ -163,6 +167,54 @@ class Solution {
163167
}
164168
```
165169

170+
```java
171+
class Solution {
172+
public List<String> getWordsInLongestSubsequence(int n, String[] words, int[] groups) {
173+
int[] dp = new int[n];
174+
int[] next = new int[n];
175+
Map<String, List<Integer>> strToIdxMap = new HashMap<>();
176+
int maxIdx = n;
177+
for (int i = n - 1; i >= 0; i--) {
178+
int prevIdx = n;
179+
char[] word = words[i].toCharArray();
180+
for (int j = 0; j < word.length; j++) {
181+
// convert word to pattern with '*'.
182+
char temp = word[j];
183+
word[j] = '*';
184+
String curr = new String(word);
185+
186+
// search matches and update dp.
187+
List<Integer> prevList = strToIdxMap.getOrDefault(curr, List.of());
188+
for (int prev : prevList) {
189+
if (groups[prev] == groups[i] || dp[prev] < dp[i]) {
190+
continue;
191+
}
192+
dp[i] = dp[prev] + 1;
193+
prevIdx = prev;
194+
}
195+
196+
// append current pattern to dictionary.
197+
strToIdxMap.computeIfAbsent(curr, k -> new ArrayList<>()).add(i);
198+
199+
// restore pattern to orignal word.
200+
word[j] = temp;
201+
}
202+
if (maxIdx >= n || dp[i] > dp[maxIdx]) {
203+
maxIdx = i;
204+
}
205+
next[i] = prevIdx;
206+
}
207+
int curr = maxIdx;
208+
List<String> ans = new ArrayList<>();
209+
while (curr < n) {
210+
ans.add(words[curr]);
211+
curr = next[curr];
212+
}
213+
return ans;
214+
}
215+
}
216+
```
217+
166218
### **C++**
167219

168220
```cpp

‎solution/2900-2999/2901.Longest Unequal Adjacent Groups Subsequence II/README_EN.md‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ Finally, we find the index $i$ corresponding to the maximum value in the $f$ arr
7474

7575
The time complexity is $O(n^2 \times L),ドル and the space complexity is $O(n)$. Here, $L$ represents the maximum length of a word.
7676

77+
**Optimization: Space for Time**
78+
79+
In **Solution 1**, we need to enumerate all $i$ and $j$ combinations, a step that can be optimized by maintaining a wildcard hash table. For each string $word[i],ドル we enumerate each character, replace it with a wildcard, and then use the replaced string as the key and add its subscript to the list which is the value in the hash table. This allows us to find all $word[j]$ with a Hamming distance of 1 from $word[i]$ in $O(L)$ time. Although the time complexity is still $O(n^2 \times L),ドル the average complexity is reduced.
80+
7781
<!-- tabs:start -->
7882

7983
### **Python3**
@@ -153,6 +157,54 @@ class Solution {
153157
}
154158
```
155159

160+
```java
161+
class Solution {
162+
public List<String> getWordsInLongestSubsequence(int n, String[] words, int[] groups) {
163+
int[] dp = new int[n];
164+
int[] next = new int[n];
165+
Map<String, List<Integer>> strToIdxMap = new HashMap<>();
166+
int maxIdx = n;
167+
for (int i = n - 1; i >= 0; i--) {
168+
int prevIdx = n;
169+
char[] word = words[i].toCharArray();
170+
for (int j = 0; j < word.length; j++) {
171+
// convert word to pattern with '*'.
172+
char temp = word[j];
173+
word[j] = '*';
174+
String curr = new String(word);
175+
176+
// search matches and update dp.
177+
List<Integer> prevList = strToIdxMap.getOrDefault(curr, List.of());
178+
for (int prev : prevList) {
179+
if (groups[prev] == groups[i] || dp[prev] < dp[i]) {
180+
continue;
181+
}
182+
dp[i] = dp[prev] + 1;
183+
prevIdx = prev;
184+
}
185+
186+
// append current pattern to dictionary.
187+
strToIdxMap.computeIfAbsent(curr, k -> new ArrayList<>()).add(i);
188+
189+
// restore pattern to orignal word.
190+
word[j] = temp;
191+
}
192+
if (maxIdx >= n || dp[i] > dp[maxIdx]) {
193+
maxIdx = i;
194+
}
195+
next[i] = prevIdx;
196+
}
197+
int curr = maxIdx;
198+
List<String> ans = new ArrayList<>();
199+
while (curr < n) {
200+
ans.add(words[curr]);
201+
curr = next[curr];
202+
}
203+
return ans;
204+
}
205+
}
206+
```
207+
156208
### **C++**
157209

158210
```cpp

‎solution/2900-2999/2902.Count of Sub-Multisets With Bounded Sum/README.md‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,50 @@ class Solution:
9797
<!-- 这里可写当前语言的特殊实现逻辑 -->
9898

9999
```java
100+
class Solution {
101+
static final int MOD = 1_000_000_007;
102+
public int countSubMultisets(List<Integer> nums, int l, int r) {
103+
Map<Integer, Integer> count = new HashMap<>();
104+
int total = 0;
105+
for (int num : nums) {
106+
total += num;
107+
if (num <= r) {
108+
count.merge(num, 1, Integer::sum);
109+
}
110+
}
111+
if (total < l) {
112+
return 0;
113+
}
114+
r = Math.min(r, total);
115+
int[] dp = new int[r + 1];
116+
dp[0] = count.getOrDefault(0, 0) + 1;
117+
count.remove(Integer.valueOf(0));
118+
int sum = 0;
119+
for (Map.Entry<Integer, Integer> e : count.entrySet()) {
120+
int num = e.getKey();
121+
int c = e.getValue();
122+
sum = Math.min(sum + c * num, r);
123+
// prefix part
124+
// dp[i] = dp[i] + dp[i - num] + ... + dp[i - c*num] + dp[i-(c+1)*num] + ... + dp[i % num]
125+
for (int i = num; i <= sum; i++) {
126+
dp[i] = (dp[i] + dp[i - num]) % MOD;
127+
}
128+
int temp = (c + 1) * num;
129+
// correction part
130+
// subtract dp[i - (freq + 1) * num] to the end part.
131+
// leves dp[i] = dp[i] + dp[i-num] +...+ dp[i - c*num];
132+
for (int i = sum; i >= temp; i--) {
133+
dp[i] = (dp[i] - dp[i - temp] + MOD) % MOD;
134+
}
135+
}
136+
int ans = 0;
137+
for (int i = l; i <= r; i++) {
138+
ans += dp[i];
139+
ans %= MOD;
140+
}
141+
return ans;
142+
}
143+
}
100144

101145
```
102146

‎solution/2900-2999/2902.Count of Sub-Multisets With Bounded Sum/README_EN.md‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,50 @@ class Solution:
8787
### **Java**
8888

8989
```java
90+
class Solution {
91+
static final int MOD = 1_000_000_007;
92+
public int countSubMultisets(List<Integer> nums, int l, int r) {
93+
Map<Integer, Integer> count = new HashMap<>();
94+
int total = 0;
95+
for (int num : nums) {
96+
total += num;
97+
if (num <= r) {
98+
count.merge(num, 1, Integer::sum);
99+
}
100+
}
101+
if (total < l) {
102+
return 0;
103+
}
104+
r = Math.min(r, total);
105+
int[] dp = new int[r + 1];
106+
dp[0] = count.getOrDefault(0, 0) + 1;
107+
count.remove(Integer.valueOf(0));
108+
int sum = 0;
109+
for (Map.Entry<Integer, Integer> e : count.entrySet()) {
110+
int num = e.getKey();
111+
int c = e.getValue();
112+
sum = Math.min(sum + c * num, r);
113+
// prefix part
114+
// dp[i] = dp[i] + dp[i - num] + ... + dp[i - c*num] + dp[i-(c+1)*num] + ... + dp[i % num]
115+
for (int i = num; i <= sum; i++) {
116+
dp[i] = (dp[i] + dp[i - num]) % MOD;
117+
}
118+
int temp = (c + 1) * num;
119+
// correction part
120+
// subtract dp[i - (freq + 1) * num] to the end part.
121+
// leves dp[i] = dp[i] + dp[i-num] +...+ dp[i - c*num];
122+
for (int i = sum; i >= temp; i--) {
123+
dp[i] = (dp[i] - dp[i - temp] + MOD) % MOD;
124+
}
125+
}
126+
int ans = 0;
127+
for (int i = l; i <= r; i++) {
128+
ans += dp[i];
129+
ans %= MOD;
130+
}
131+
return ans;
132+
}
133+
}
90134

91135
```
92136

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
class Solution {
3+
static final int MOD = 1_000_000_007;
4+
public int countSubMultisets(List<Integer> nums, int l, int r) {
5+
Map<Integer, Integer> count = new HashMap<>();
6+
int total = 0;
7+
for (int num : nums) {
8+
total += num;
9+
if (num <= r) {
10+
count.merge(num, 1, Integer::sum);
11+
}
12+
}
13+
if (total < l) {
14+
return 0;
15+
}
16+
r = Math.min(r, total);
17+
int[] dp = new int[r + 1];
18+
dp[0] = count.getOrDefault(0, 0) + 1;
19+
count.remove(Integer.valueOf(0));
20+
int sum = 0;
21+
for (Map.Entry<Integer, Integer> e : count.entrySet()) {
22+
int num = e.getKey();
23+
int c = e.getValue();
24+
sum = Math.min(sum + c * num, r);
25+
// prefix part
26+
// dp[i] = dp[i] + dp[i - num] + ... + dp[i - c*num] + dp[i-(c+1)*num] + ... + dp[i %
27+
// num]
28+
for (int i = num; i <= sum; i++) {
29+
dp[i] = (dp[i] + dp[i - num]) % MOD;
30+
}
31+
int temp = (c + 1) * num;
32+
// correction part
33+
// subtract dp[i - (freq + 1) * num] to the end part.
34+
// leves dp[i] = dp[i] + dp[i-num] +...+ dp[i - c*num];
35+
for (int i = sum; i >= temp; i--) {
36+
dp[i] = (dp[i] - dp[i - temp] + MOD) % MOD;
37+
}
38+
}
39+
int ans = 0;
40+
for (int i = l; i <= r; i++) {
41+
ans += dp[i];
42+
ans %= MOD;
43+
}
44+
return ans;
45+
}
46+
}

‎solution/2900-2999/2911.Minimum Changes to Make K Semi-palindromes/README.md‎

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@
5959

6060
<!-- 这里可写通用的实现逻辑 -->
6161

62+
**优化: 预处理因数列表**
63+
64+
可以预先处理每个长度的因数列表,这样就不用每次都去计算了。
65+
6266
<!-- tabs:start -->
6367

6468
### **Python3**
@@ -141,6 +145,89 @@ class Solution {
141145
}
142146
```
143147

148+
```java
149+
class Solution {
150+
static int inf = 200;
151+
List<Integer>[] factorLists;
152+
int n;
153+
int k;
154+
char[] ch;
155+
Integer[][] cost;
156+
public int minimumChanges(String s, int k) {
157+
this.k = k;
158+
n = s.length();
159+
ch = s.toCharArray();
160+
161+
factorLists = getFactorLists(n);
162+
cost = new Integer[n + 1][n + 1];
163+
return calcDP();
164+
}
165+
static List<Integer>[] getFactorLists(int n) {
166+
List<Integer>[] l = new ArrayList[n + 1];
167+
for (int i = 1; i <= n; i++) {
168+
l[i] = new ArrayList<>();
169+
l[i].add(1);
170+
}
171+
for (int factor = 2; factor < n; factor++) {
172+
for (int num = factor + factor; num <= n; num += factor) {
173+
l[num].add(factor);
174+
}
175+
}
176+
return l;
177+
}
178+
int calcDP() {
179+
int[] dp = new int[n];
180+
for (int i = n - k * 2 + 1; i >= 1; i--) {
181+
dp[i] = getCost(0, i);
182+
}
183+
int bound = 0;
184+
for (int subs = 2; subs <= k; subs++) {
185+
bound = subs * 2;
186+
for (int i = n - 1 - k * 2 + subs * 2; i >= bound - 1; i--) {
187+
dp[i] = inf;
188+
for (int prev = bound - 3; prev < i - 1; prev++) {
189+
dp[i] = Math.min(dp[i], dp[prev] + getCost(prev + 1, i));
190+
}
191+
}
192+
}
193+
return dp[n - 1];
194+
}
195+
int getCost(int l, int r) {
196+
if (l >= r) {
197+
return inf;
198+
}
199+
if (cost[l][r] != null) {
200+
return cost[l][r];
201+
}
202+
cost[l][r] = inf;
203+
for (int factor : factorLists[r - l + 1]) {
204+
cost[l][r] = Math.min(cost[l][r], getStepwiseCost(l, r, factor));
205+
}
206+
return cost[l][r];
207+
}
208+
int getStepwiseCost(int l, int r, int stepsize) {
209+
if (l >= r) {
210+
return 0;
211+
}
212+
int left = 0;
213+
int right = 0;
214+
int count = 0;
215+
for (int i = 0; i < stepsize; i++) {
216+
left = l + i;
217+
right = r - stepsize + 1 + i;
218+
while (left + stepsize <= right) {
219+
if (ch[left] != ch[right]) {
220+
count++;
221+
}
222+
left += stepsize;
223+
right -= stepsize;
224+
}
225+
}
226+
return count;
227+
}
228+
}
229+
```
230+
144231
### **C++**
145232

146233
```cpp

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /