Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b8cd2fd

Browse files
committed
🐱(weekly): 第 159 场周赛
1 parent 36068a5 commit b8cd2fd

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed

docs/weekly/README.md

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2490,5 +2490,237 @@ class Solution:
24902490
res = i + 1
24912491
continue
24922492

2493+
return res
2494+
```
2495+
2496+
## 第 159 场周赛
2497+
2498+
[点击前往第 159 场周赛](https://leetcode-cn.com/contest/weekly-contest-159)
2499+
2500+
### 5230. 缀点成线
2501+
2502+
[原题链接](https://leetcode-cn.com/contest/weekly-contest-159/problems/check-if-it-is-a-straight-line/)
2503+
2504+
取出前两个点根据 $y = kx + b$ 求解直线方程,再将后续的点套入方程中判断是否在直线上。
2505+
2506+
```python
2507+
class Solution:
2508+
def checkStraightLine(self, coordinates: List[List[int]]) -> bool:
2509+
x1, y1 = coordinates[0][0], coordinates[0][1]
2510+
x2, y2 = coordinates[1][0], coordinates[1][1]
2511+
# 求斜率 k
2512+
if x1 == x2:
2513+
k = 0
2514+
else:
2515+
k = (y2 - y1) / (x2 - x1)
2516+
b = y1 - k * x1
2517+
2518+
for i in range(2, len(coordinates)):
2519+
x = coordinates[i][0]
2520+
y = coordinates[i][1]
2521+
if k * x + b != y:
2522+
return False
2523+
2524+
return True
2525+
```
2526+
2527+
### 5231. 删除子文件夹
2528+
2529+
[原题链接](https://leetcode-cn.com/contest/weekly-contest-159/problems/remove-sub-folders-from-the-filesystem/)
2530+
2531+
#### 思路
2532+
2533+
`folder` 按字典序排序,如果目录 `x``folder` 中存在根目录,那么这个根目录必定在 `x` 之前。
2534+
2535+
1. 将第一个目录作为根目录
2536+
2. 从第二个目录开始遍历,判断 `folder[i]` 是否以当前根目录为前缀:
2537+
- 是:`folder[i]` 是子目录,跳过该目录,不记录到结果中
2538+
- 否:将当前根目录更新为 `folder[i]`
2539+
2540+
ps: 作为根目录时结尾加个 `/`,不然 `"/a/b/c"` 就是 `"/a/b/ca"` 的前缀了。
2541+
2542+
#### 实现
2543+
2544+
```python
2545+
class Solution:
2546+
def removeSubfolders(self, folder: List[str]) -> List[str]:
2547+
# 排序
2548+
folder.sort()
2549+
res = [folder[0]]
2550+
# 将第一个目录设为当前根目录
2551+
root = folder[0] + "/"
2552+
2553+
for i in range(1, len(folder)):
2554+
# 是否以 root 为前缀
2555+
if not folder[i].startswith(root):
2556+
# 不是子目录
2557+
root = folder[i] + "/" # 更新根目录
2558+
res.append(folder[i])
2559+
2560+
return res
2561+
```
2562+
2563+
另外一种用字典树的笨方法:
2564+
2565+
```python
2566+
class Solution:
2567+
def removeSubfolders(self, folder: List[str]) -> List[str]:
2568+
folder.sort()
2569+
print(folder)
2570+
m = dict()
2571+
res = []
2572+
length = len(folder)
2573+
2574+
for i in range(length):
2575+
letters = folder[i].split('/')
2576+
is_child = True
2577+
l_length = len(letters)
2578+
find = m
2579+
# 循环每个目录
2580+
for j in range(1, l_length):
2581+
letter = letters[j]
2582+
if letter not in find:
2583+
# 不在
2584+
find[letter] = dict()
2585+
is_child = False
2586+
find = find[letter]
2587+
break
2588+
else:
2589+
#
2590+
find = find[letter]
2591+
if 'end' in find: # 到达末尾
2592+
is_child = True
2593+
break
2594+
2595+
j += 1
2596+
while j < l_length:
2597+
tmp_letter = letters[j]
2598+
if tmp_letter not in find:
2599+
find[tmp_letter] = dict()
2600+
find = find[tmp_letter]
2601+
j += 1
2602+
2603+
find['end'] = True
2604+
# print(m)
2605+
2606+
if not is_child:
2607+
res.append(folder[i])
2608+
2609+
return res
2610+
```
2611+
2612+
### 5232. 替换子串得到平衡字符串
2613+
2614+
[原题链接](https://leetcode-cn.com/contest/weekly-contest-159/problems/replace-the-substring-for-balanced-string/)
2615+
2616+
#### 思路
2617+
2618+
题目要求 `QWER` 每个字符都需要出现 `n / 4` 次,那么统计这 4 个字母出现的次数,超出 `n / 4` 部分的即为需要删除的字母,即只要在字符串中找到包含所有多出字母的一个子串即可。用**双指针**圈定最终的子串范围。
2619+
2620+
#### 实现
2621+
2622+
```python
2623+
class Solution:
2624+
def balancedString(self, s: str) -> int:
2625+
length = len(s)
2626+
n = length // 4
2627+
2628+
m = {"Q": 0, "W": 1, "E": 2, "R": 3}
2629+
dp = [[0, 0, 0, 0] for i in range(length)]
2630+
c_count = [0 for _ in range(4)]
2631+
need = [0 for _ in range(4)]
2632+
2633+
# 计算每个字母出现的个数
2634+
for i in range(length):
2635+
c = s[i]
2636+
index = m[c]
2637+
c_count[index] += 1
2638+
dp[i] = [c_count[0], c_count[1], c_count[2], c_count[3]]
2639+
2640+
# 计算多出来的字母个数(即需要删除的个数)
2641+
all_zero = True
2642+
for i in range(4):
2643+
count = c_count[i]
2644+
if count > n:
2645+
need[i] = count - n
2646+
if need[i] != 0:
2647+
all_zero = False
2648+
# 如果全为 0,说明不需要替换
2649+
if all_zero:
2650+
return 0
2651+
2652+
# 双指针,确定右指针所在的最小位置
2653+
last = length - 1
2654+
for i in range(length):
2655+
if dp[i][0] >= need[0] and dp[i][1] >= need[1] and dp[i][2] >= need[2] and dp[i][3] >= need[3]:
2656+
last = i
2657+
break
2658+
2659+
i = 0
2660+
j = last
2661+
res = last + 1
2662+
while i < length and j < length:
2663+
# 两指针中间区域不满足要求,右指针右移
2664+
if dp[j][0] - dp[i][0] < need[0] or dp[j][1] - dp[i][1] < need[1] or dp[j][2] - dp[i][2] < need[2] or dp[j][3] - dp[i][3] < need[3]:
2665+
j += 1
2666+
# 满足要求,左指针尽量向右移,看是否可以缩短字串长度
2667+
else:
2668+
res = min(j - i, res)
2669+
i += 1
2670+
2671+
return res
2672+
```
2673+
2674+
### 5233. 规划兼职工作
2675+
2676+
[原题链接](https://leetcode-cn.com/contest/weekly-contest-159/problems/maximum-profit-in-job-scheduling/)
2677+
2678+
#### 思路
2679+
2680+
动态规划。在开始计算之前,先把题目给出的数据整理一下。将 `[startTime[i], endTime[i], profit[i]]` 整理为数组,并按 `startTime[i] - endTime[i] - profit[i]]` 排序。
2681+
2682+
`dp[i]` 表示完成第 `i` 份工作所能获得的最大收益。假设有第 `x` 份工作(`x < i`):
2683+
2684+
- 如果 `x``i` 时间上不重合,表示即可完成工作 `x` 又可以完成工作 `i`,那么有:`dp[i] = max(dp[i], dp[x] + profit[i])`
2685+
- 如果 `x``i` 在时间上重合了,那么将无法完成工作 `x`
2686+
2687+
由此可见,`dp[i]` 的值**取决于在它前面所有与之时间不重合的工作收益**,即:
2688+
2689+
```
2690+
dp[i] = max(dp[0], dp[1], ..., dp[j]) + profit[i] (`j` 为 `i` 之前最后一个与之时间区域不重合的工作)
2691+
```
2692+
2693+
但是,如果每次都遍历 `0 ~ j` 必然会超时,所以需要记录下时间区域不重合的工作所在的最大位置。
2694+
2695+
#### 实现
2696+
2697+
```python
2698+
class Solution:
2699+
def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int:
2700+
length = len(startTime)
2701+
times = [[0, 0, 0] for _ in range(length)]
2702+
for i in range(length):
2703+
times[i][0] = startTime[i]
2704+
times[i][1] = endTime[i]
2705+
times[i][2] = profit[i]
2706+
times.sort() # 排序
2707+
2708+
dp = [0 for i in range(length)]
2709+
2710+
res = 0
2711+
s = 0
2712+
pos = 0 # 标记位置
2713+
for i in range(length):
2714+
for j in range(pos, i):
2715+
# 区间不重合
2716+
if times[i][0] >= times[j][1]:
2717+
# 移动 pos 的位置
2718+
if j == pos:
2719+
pos += 1
2720+
s = max(s, dp[j])
2721+
2722+
dp[i] = s + times[i][2]
2723+
res = max(res, dp[i])
2724+
24932725
return res
24942726
```

0 commit comments

Comments
 (0)