Skip to content

Commit

Permalink
add: biweekly 123, weekly 383,384
Browse files Browse the repository at this point in the history
  • Loading branch information
binacs committed Apr 9, 2024
1 parent 0e966ab commit 96442e1
Show file tree
Hide file tree
Showing 4 changed files with 438 additions and 0 deletions.
77 changes: 77 additions & 0 deletions string/kmp.md
Original file line number Diff line number Diff line change
Expand Up @@ -1246,3 +1246,80 @@ int main() {
<br>

* * *

> [!NOTE] **[LeetCode 3036. 匹配模式数组的子数组数目 II](https://leetcode.cn/problems/number-of-subarrays-that-match-a-pattern-ii/)**
>
> 题意: TODO
> [!TIP] **思路**
>
> 经典 KMP 应用
<details>
<summary>详细代码</summary>
<!-- tabs:start -->

##### **C++**

```cpp
class Solution {
public:
// 与 https://codeforces.com/problemset/problem/471/D 思想一致
const static int N = 1e6 + 10;

int ns[N];

vector<int> kmp(vector<int> & p, int m) {
vector<int> f(m + 1);
for (int i = 2, j = 0; i <= m; ++ i ) {
while (j && p[i] != p[j + 1])
j = f[j];
if (p[i] == p[j + 1])
j ++ ;
f[i] = j;
}
return f;
}

int countMatchingSubarrays(vector<int>& nums, vector<int>& pattern) {
int n = nums.size(), m = pattern.size();

for (int i = 1; i < n; ++ i )
if (nums[i] > nums[i - 1])
ns[i] = 1;
else if (nums[i] < nums[i - 1])
ns[i] = -1;
else
ns[i] = 0;

pattern.insert(pattern.begin(), 0); // ATTENTION
auto f = kmp(pattern, m);

int res = 0;
for (int i = 1, j = 0; i < n; ++ i ) {
while (j && ns[i] != pattern[j + 1])
j = f[j];
if (ns[i] == pattern[j + 1])
j ++ ;
if (j == m) {
res ++ ;
j = f[j];
}
}
return res;
}
};
```
##### **Python**
```python
```

<!-- tabs:end -->
</details>

<br>

* * *
91 changes: 91 additions & 0 deletions string/z-func.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,94 @@ int main() {
<br>

* * *

> [!NOTE] **[LeetCode 3031. 将单词恢复初始状态所需的最短时间 II](https://leetcode.cn/problems/minimum-time-to-revert-word-to-initial-state-ii/)**
>
> 题意: TODO
> [!TIP] **思路**
>
> 题意分析 显然只需要对比后缀与前缀
>
> 1. 字符串哈希
>
> 2. 更简单的方式是 扩展 kmp
<details>
<summary>详细代码</summary>
<!-- tabs:start -->

##### **C++ 字符串哈希**

```cpp
class Solution {
public:
using ULL = unsigned long long;
const static int N = 1e6 + 10, P = 131;

ULL h[N], p[N];
bool st[N];

ULL get(int l, int r) {
return h[r] - h[l - 1] * p[r - l + 1];
}

int minimumTimeToInitialState(string word, int k) {
int n = word.size();
h[0] = 0, p[0] = 1;
for (int i = 1; i <= n; ++ i ) {
h[i] = h[i - 1] * P + word[i - 1];
p[i] = p[i - 1] * P;
}

memset(st, 0, sizeof st);
for (int i = 1, x = k/*定义为新的开头的原始下标*/; x <= n/*因为 如果超过了 n 则后面是任意的字母 一定可以拼成*/; x += k, ++ i ) {
int w = n - x;
if (get(1, w) == get(x + 1, n))
return i;
}
return (n + k - 1) / k;
}
};
```
##### **C++ z-func**
```cpp
class Solution {
public:
int minimumTimeToInitialState(string word, int k) {
int n = word.size();
vector<int> z(n);
for (int i = 1, l = 0, r = 0; i < n; ++ i ) {
if (i <= r && z[i - l] < r - i + 1)
z[i] = z[i - l];
else {
z[i] = max(0, r - i + 1);
while (i + z[i] < n && word[z[i]] == word[i + z[i]])
z[i] ++ ;
}
if (i + z[i] - 1 > r)
l = i, r = i + z[i] - 1;
// Special logic
if (i % k == 0 && z[i] >= n - i)
return i / k;
}
return (n + k - 1) / k;
}
};
```

##### **Python**

```python

```

<!-- tabs:end -->
</details>

<br>

* * *
205 changes: 205 additions & 0 deletions topic/bf-improve.md
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,143 @@ public:

* * *

> [!NOTE] **[LeetCode 3027. 人员站位的方案数 II](https://leetcode.cn/problems/find-the-number-of-ways-to-place-people-ii/)**
>
> 题意: TODO
> [!TIP] **思路**
>
> 充要条件推导 以简化暴力遍历过程
<details>
<summary>详细代码</summary>
<!-- tabs:start -->

##### **C++ 最初比较糙的版本**

```cpp
class Solution {
public:
// ATTENTION 题意是 内部或边缘...而非只排排除边缘 显然需要二维前缀合
const static int N = 1010; // ATTENTION 1: 只需要 1010 不需要 2010,因为 xy 彼此独立

int g[N][N];
void init() {
memset(g, 0, sizeof g);
}

vector<int> xs, ys;
int get(vector<int> s, int x) {
return lower_bound(s.begin(), s.end(), x) - s.begin();
}

bool check(int x1, int y1, int x2, int y2) {
return g[x2][y1] - g[x2][y2 - 1] - g[x1 - 1][y1] + g[x1 - 1][y2 - 1] == 2;
};

int numberOfPairs(vector<vector<int>>& points) {
// sorting...
sort(points.begin(), points.end(), [](const vector<int> & a, const vector<int> & b) {
if (a[0] == b[0])
return a[1] > b[1];
return a[0] < b[0];
});

{
for (auto & p : points) {
int x = p[0], y = p[1];
xs.push_back(x), ys.push_back(y);
}
sort(xs.begin(), xs.end());
sort(ys.begin(), ys.end());
}
{
init();
for (auto & p : points) {
int x = get(xs, p[0]) + 1, y = get(ys, p[1]) + 1;
g[x][y] ++ ;
p[0] = x, p[1] = y;
}
for (int i = 1; i < N; ++ i )
for (int j = 1; j < N; ++ j )
g[i][j] += g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1];
}

int n = points.size(), res = 0;
for (int i = 0; i < n; ++ i ) {
int x1 = points[i][0], y1 = points[i][1], cap = 0; // ATTENTION 2: trick 优化 => 理论上如果某个点符合要求,则后续必须比这个点更高
for (int j = i + 1; j < n; ++ j ) {
int x2 = points[j][0], y2 = points[j][1];
if (y2 > y1)
continue;

// ATTENTION 2.1
if (y2 <= cap)
continue;

if (check(x1, y1, x2, y2)) {
res ++ ;

// ATTENTION 2.2
cap = max(cap, y2);
}
}
}
return res;
}
};
```
##### **C++ 简化**
```cpp
class Solution {
public:
// ATTENTION 更进一步 只要保证该上限即可满足条件 【思考 充要条件】
int numberOfPairs(vector<vector<int>>& points) {
// sorting...
sort(points.begin(), points.end(), [](const vector<int> & a, const vector<int> & b) {
if (a[0] == b[0])
return a[1] > b[1];
return a[0] < b[0];
});
int n = points.size(), res = 0;
for (int i = 0; i < n; ++ i ) {
int x1 = points[i][0], y1 = points[i][1], cap = -2e9; // ATTENTION 2: trick 优化 => 理论上如果某个点符合要求,则后续必须比这个点更高
for (int j = i + 1; j < n; ++ j ) {
int x2 = points[j][0], y2 = points[j][1];
if (y2 > y1)
continue;
// ATTENTION 2.1
if (y2 <= cap)
continue;
res ++ ;
// ATTENTION 2.2
cap = max(cap, y2);
}
}
return res;
}
};
```

##### **Python**

```python

```

<!-- tabs:end -->
</details>

<br>

* * *

### 双指针

> [!NOTE] **[LeetCode 1521. 找到最接近目标值的函数值](https://leetcode-cn.com/problems/find-a-value-of-a-mysterious-function-closest-to-target/)** [TAG]
Expand Down Expand Up @@ -1220,6 +1357,74 @@ public:

* * *

> [!NOTE] **[LeetCode 3026. 最大好子数组和](https://leetcode.cn/problems/maximum-good-subarray-sum/)**
>
> 题意: TODO
> [!TIP] **思路**
>
> 经典暴力优化,实际上也不需要 deque,直接维护 min 值就好
<details>
<summary>详细代码</summary>
<!-- tabs:start -->

##### **C++**

```cpp
class Solution {
public:
using LL = long long;
const static int N = 1e5 + 10;

LL sum[N];
unordered_map<LL, deque<int>> h;

long long maximumSubarraySum(vector<int>& nums, int k) {
int n = nums.size();
LL res = -1e16;
sum[0] = 0; // ATTENTION 不能初始化h[0].push_back(0)
for (int i = 1; i <= n; ++ i ) {
int x = nums[i - 1];

sum[i] = sum[i - 1] + x;

if (h.count(x - k) && !h[x - k].empty()) {
int y = h[x - k].front();
res = max(res, sum[i] - (y ? sum[y - 1] : 0));
}
if (h.count(x + k) && !h[x + k].empty()) {
int y = h[x + k].front();
res = max(res, sum[i] - (y ? sum[y - 1] : 0));
}

// ATTENTION: TLE 优化
// 对于相同的 x 要保留sum最小的那个的下标, 这样才能让区间和最大 => 单调队列 => 需要取队底部故deque
{
auto & stk = h[x];
while (!stk.empty() && sum[stk.front() - 1] >= sum[i - 1])
stk.pop_back();
stk.push_back(i);
}
}
return res == -1e16 ? 0 : res;
}
};
```
##### **Python**
```python
```

<!-- tabs:end -->
</details>

<br>

* * *

### 公式转化

> [!NOTE] **[LeetCode 891. 子序列宽度之和](https://leetcode.cn/problems/sum-of-subsequence-widths/)**
Expand Down
Loading

0 comments on commit 96442e1

Please sign in to comment.