Skip to content

Commit f2099bb

Browse files
authored
feat: add solutions to lc problem: No.0918 (doocs#1245)
No.0918.Maximum Sum Circular Subarray
1 parent 80cc828 commit f2099bb

File tree

3 files changed

+258
-45
lines changed

3 files changed

+258
-45
lines changed

solution/0800-0899/0874.Walking Robot Simulation/README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,15 @@
8888

8989
我们定义一个长度为 $5$ 的方向数组 $dirs=[0, 1, 0, -1, 0]$,数组中的相邻两个元素表示一个方向。即 $(dirs[0], dirs[1])$ 表示向北,而 $(dirs[1], dirs[2])$ 表示向东,以此类推。
9090

91-
我们使用一个哈希表 $s$ 来存储所有障碍物的坐标,这样我们就可以在 $O(1)$ 的时间内判断下一步是否会遇到障碍物。
91+
我们使用一个哈希表 $s$ 来存储所有障碍物的坐标,这样可以在 $O(1)$ 的时间内判断下一步是否会遇到障碍物。
9292

93-
我们使用两个变量 $x$ 和 $y$ 来表示机器人当前所在的坐标,初始时 $x = y = 0$。变量 $k$ 表示机器人当前的方向,答案变量 $ans$ 表示机器人距离原点的最大欧式距离的平方。
93+
另外,使用两个变量 $x$ 和 $y$ 来表示机器人当前所在的坐标,初始时 $x = y = 0$。变量 $k$ 表示机器人当前的方向,答案变量 $ans$ 表示机器人距离原点的最大欧式距离的平方。
9494

9595
接下来,我们遍历数组 $commands$ 中的每个元素 $c$:
9696

9797
- 如果 $c = -2$,表示机器人向左转 $90$ 度,即 $k = (k + 3) \bmod 4$;
9898
- 如果 $c = -1$,表示机器人向右转 $90$ 度,即 $k = (k + 1) \bmod 4$;
99-
- 否则,表示机器人向前移动 $c$ 个单位长度。我们将机器人当前的方向 $k$ 与方向数组 $dirs$ 结合,即可得到机器人在 $x$ 轴和 $y$ 轴上的增量。我们将 $c$ 个单位长度的增量分别累加到 $x$ 和 $y$ 上,并判断每次移动后的新坐标 $(x, y)$ 是否在障碍物的坐标中,如果不在,则更新答案 $ans$,否则停止模拟,进行下一条指令的模拟。
99+
- 否则,表示机器人向前移动 $c$ 个单位长度。我们将机器人当前的方向 $k$ 与方向数组 $dirs$ 结合,即可得到机器人在 $x$ 轴和 $y$ 轴上的增量。我们将 $c$ 个单位长度的增量分别累加到 $x$ 和 $y$ 上,并判断每次移动后的新坐标 $(nx, ny)$ 是否在障碍物的坐标中,如果不在,则更新答案 $ans$,否则停止模拟,进行下一条指令的模拟。
100100

101101
最后返回答案 $ans$ 即可。
102102

solution/0900-0999/0918.Maximum Sum Circular Subarray/README.md

+139-23
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,32 @@
5252

5353
<!-- 这里可写通用的实现逻辑 -->
5454

55-
环形子数组的最大和,可分为两种情况:无环最大和、有环最大和。求其较大值即可。
55+
**方法一:维护前缀最值**
5656

57-
无环最大和 s1 的求解可参考:[53. 最大子序和](/solution/0000-0099/0053.Maximum%20Subarray/README.md)
57+
求环形子数组的最大和,可以分为两种情况:
5858

59-
对于有环最大和,我们可以转换为求最小子序和 s2,然后用 sum 减去最小子序和,得到有环的最大和。
59+
- 情况一:最大和的子数组不包含环形部分,即为普通的最大子数组和;
60+
- 情况二:最大和的子数组包含环形部分,我们可以转换为:求数组总和减去最小子数组和。
6061

61-
注意:若数组所有元素均不大于 0,直接返回无环最大和 s1 即可。
62+
因此,我们维护以下几个变量:
63+
64+
- 前缀和最小值 $pmi$,初始值为 $0$;
65+
- 前缀和最大值 $pmx$,初始值为 $-\infty$;
66+
- 前缀和 $s$,初始值为 $0$;
67+
- 最小子数组和 $smi$,初始值为 $\infty$;
68+
- 答案 $ans$,初始值为 $-\infty$。
69+
70+
接下来,我们只需要遍历数组 $nums$,对于当前遍历到的元素 $x$,我们做以下更新操作:
71+
72+
- 更新前缀和 $s = s + x$;
73+
- 更新答案 $ans = \max(ans, s - pmi)$,即为情况一的答案(前缀和 $s$ 减去最小前缀和 $pmi$,可以得到最大子数组和);
74+
- 更新 $smi = \min(smi, s - pmx)$,即为情况二的最小子数组和;
75+
- 更新 $pmi = \min(pmi, s)$,即为最小前缀和;
76+
- 更新 $pmx = \max(pmx, s)$,即为最大前缀和。
77+
78+
遍历结束,我们取 $ans$ 以及 $s - smi$ 的最大值作为答案返回即可。
79+
80+
时间复杂度 $O(n)$,其中 $n$ 为数组长度。空间复杂度 $O(1)$。
6281

6382
<!-- tabs:start -->
6483

@@ -78,6 +97,20 @@ class Solution:
7897
return s1 if s1 <= 0 else max(s1, sum(nums) - s2)
7998
```
8099

100+
```python
101+
class Solution:
102+
def maxSubarraySumCircular(self, nums: List[int]) -> int:
103+
pmi, pmx = 0, -inf
104+
ans, s, smi = -inf, 0, inf
105+
for x in nums:
106+
s += x
107+
ans = max(ans, s - pmi)
108+
smi = min(smi, s - pmx)
109+
pmi = min(pmi, s)
110+
pmx = max(pmx, s)
111+
return max(ans, s - smi)
112+
```
113+
81114
### **Java**
82115

83116
<!-- 这里可写当前语言的特殊实现逻辑 -->
@@ -98,26 +131,21 @@ class Solution {
98131
}
99132
```
100133

101-
### **TypeScript**
102-
103-
```ts
104-
function maxSubarraySumCircular(nums: number[]): number {
105-
let pre1 = nums[0],
106-
pre2 = nums[0];
107-
let ans1 = nums[0],
108-
ans2 = nums[0];
109-
let sum = nums[0];
110-
111-
for (let i = 1; i < nums.length; ++i) {
112-
let cur = nums[i];
113-
sum += cur;
114-
pre1 = Math.max(pre1 + cur, cur);
115-
ans1 = Math.max(pre1, ans1);
116-
117-
pre2 = Math.min(pre2 + cur, cur);
118-
ans2 = Math.min(pre2, ans2);
134+
```java
135+
class Solution {
136+
public int maxSubarraySumCircular(int[] nums) {
137+
final int inf = 1 << 30;
138+
int pmi = 0, pmx = -inf;
139+
int ans = -inf, s = 0, smi = inf;
140+
for (int x : nums) {
141+
s += x;
142+
ans = Math.max(ans, s - pmi);
143+
smi = Math.min(smi, s - pmx);
144+
pmi = Math.min(pmi, s);
145+
pmx = Math.max(pmx, s);
146+
}
147+
return Math.max(ans, s - smi);
119148
}
120-
return ans1 > 0 ? Math.max(ans1, sum - ans2) : ans1;
121149
}
122150
```
123151

@@ -140,6 +168,25 @@ public:
140168
};
141169
```
142170
171+
```cpp
172+
class Solution {
173+
public:
174+
int maxSubarraySumCircular(vector<int>& nums) {
175+
const int inf = 1 << 30;
176+
int pmi = 0, pmx = -inf;
177+
int ans = -inf, s = 0, smi = inf;
178+
for (int x : nums) {
179+
s += x;
180+
ans = max(ans, s - pmi);
181+
smi = min(smi, s - pmx);
182+
pmi = min(pmi, s);
183+
pmx = max(pmx, s);
184+
}
185+
return max(ans, s - smi);
186+
}
187+
};
188+
```
189+
143190
### **Go**
144191

145192
```go
@@ -173,6 +220,75 @@ func min(a, b int) int {
173220
}
174221
```
175222

223+
```go
224+
func maxSubarraySumCircular(nums []int) int {
225+
const inf = 1 << 30
226+
pmi, pmx := 0, -inf
227+
ans, s, smi := -inf, 0, inf
228+
for _, x := range nums {
229+
s += x
230+
ans = max(ans, s-pmi)
231+
smi = min(smi, s-pmx)
232+
pmi = min(pmi, s)
233+
pmx = max(pmx, s)
234+
}
235+
return max(ans, s-smi)
236+
}
237+
238+
func max(a, b int) int {
239+
if a > b {
240+
return a
241+
}
242+
return b
243+
}
244+
245+
func min(a, b int) int {
246+
if a < b {
247+
return a
248+
}
249+
return b
250+
}
251+
```
252+
253+
### **TypeScript**
254+
255+
```ts
256+
function maxSubarraySumCircular(nums: number[]): number {
257+
let pre1 = nums[0],
258+
pre2 = nums[0];
259+
let ans1 = nums[0],
260+
ans2 = nums[0];
261+
let sum = nums[0];
262+
263+
for (let i = 1; i < nums.length; ++i) {
264+
let cur = nums[i];
265+
sum += cur;
266+
pre1 = Math.max(pre1 + cur, cur);
267+
ans1 = Math.max(pre1, ans1);
268+
269+
pre2 = Math.min(pre2 + cur, cur);
270+
ans2 = Math.min(pre2, ans2);
271+
}
272+
return ans1 > 0 ? Math.max(ans1, sum - ans2) : ans1;
273+
}
274+
```
275+
276+
```ts
277+
function maxSubarraySumCircular(nums: number[]): number {
278+
const inf = 1 << 30;
279+
let [pmi, pmx] = [0, -inf];
280+
let [ans, s, smi] = [-inf, 0, inf];
281+
for (const x of nums) {
282+
s += x;
283+
ans = Math.max(ans, s - pmi);
284+
smi = Math.min(smi, s - pmx);
285+
pmi = Math.min(pmi, s);
286+
pmx = Math.max(pmx, s);
287+
}
288+
return Math.max(ans, s - smi);
289+
}
290+
```
291+
176292
### **...**
177293

178294
```

solution/0900-0999/0918.Maximum Sum Circular Subarray/README_EN.md

+116-19
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ class Solution:
6262
return s1 if s1 <= 0 else max(s1, sum(nums) - s2)
6363
```
6464

65+
```python
66+
class Solution:
67+
def maxSubarraySumCircular(self, nums: List[int]) -> int:
68+
pmi, pmx = 0, -inf
69+
ans, s, smi = -inf, 0, inf
70+
for x in nums:
71+
s += x
72+
ans = max(ans, s - pmi)
73+
smi = min(smi, s - pmx)
74+
pmi = min(pmi, s)
75+
pmx = max(pmx, s)
76+
return max(ans, s - smi)
77+
```
78+
6579
### **Java**
6680

6781
```java
@@ -80,26 +94,21 @@ class Solution {
8094
}
8195
```
8296

83-
### **TypeScript**
84-
85-
```ts
86-
function maxSubarraySumCircular(nums: number[]): number {
87-
let pre1 = nums[0],
88-
pre2 = nums[0];
89-
let ans1 = nums[0],
90-
ans2 = nums[0];
91-
let sum = nums[0];
92-
93-
for (let i = 1; i < nums.length; ++i) {
94-
let cur = nums[i];
95-
sum += cur;
96-
pre1 = Math.max(pre1 + cur, cur);
97-
ans1 = Math.max(pre1, ans1);
98-
99-
pre2 = Math.min(pre2 + cur, cur);
100-
ans2 = Math.min(pre2, ans2);
97+
```java
98+
class Solution {
99+
public int maxSubarraySumCircular(int[] nums) {
100+
final int inf = 1 << 30;
101+
int pmi = 0, pmx = -inf;
102+
int ans = -inf, s = 0, smi = inf;
103+
for (int x : nums) {
104+
s += x;
105+
ans = Math.max(ans, s - pmi);
106+
smi = Math.min(smi, s - pmx);
107+
pmi = Math.min(pmi, s);
108+
pmx = Math.max(pmx, s);
109+
}
110+
return Math.max(ans, s - smi);
101111
}
102-
return ans1 > 0 ? Math.max(ans1, sum - ans2) : ans1;
103112
}
104113
```
105114

@@ -122,6 +131,25 @@ public:
122131
};
123132
```
124133
134+
```cpp
135+
class Solution {
136+
public:
137+
int maxSubarraySumCircular(vector<int>& nums) {
138+
const int inf = 1 << 30;
139+
int pmi = 0, pmx = -inf;
140+
int ans = -inf, s = 0, smi = inf;
141+
for (int x : nums) {
142+
s += x;
143+
ans = max(ans, s - pmi);
144+
smi = min(smi, s - pmx);
145+
pmi = min(pmi, s);
146+
pmx = max(pmx, s);
147+
}
148+
return max(ans, s - smi);
149+
}
150+
};
151+
```
152+
125153
### **Go**
126154

127155
```go
@@ -155,6 +183,75 @@ func min(a, b int) int {
155183
}
156184
```
157185

186+
```go
187+
func maxSubarraySumCircular(nums []int) int {
188+
const inf = 1 << 30
189+
pmi, pmx := 0, -inf
190+
ans, s, smi := -inf, 0, inf
191+
for _, x := range nums {
192+
s += x
193+
ans = max(ans, s-pmi)
194+
smi = min(smi, s-pmx)
195+
pmi = min(pmi, s)
196+
pmx = max(pmx, s)
197+
}
198+
return max(ans, s-smi)
199+
}
200+
201+
func max(a, b int) int {
202+
if a > b {
203+
return a
204+
}
205+
return b
206+
}
207+
208+
func min(a, b int) int {
209+
if a < b {
210+
return a
211+
}
212+
return b
213+
}
214+
```
215+
216+
### **TypeScript**
217+
218+
```ts
219+
function maxSubarraySumCircular(nums: number[]): number {
220+
let pre1 = nums[0],
221+
pre2 = nums[0];
222+
let ans1 = nums[0],
223+
ans2 = nums[0];
224+
let sum = nums[0];
225+
226+
for (let i = 1; i < nums.length; ++i) {
227+
let cur = nums[i];
228+
sum += cur;
229+
pre1 = Math.max(pre1 + cur, cur);
230+
ans1 = Math.max(pre1, ans1);
231+
232+
pre2 = Math.min(pre2 + cur, cur);
233+
ans2 = Math.min(pre2, ans2);
234+
}
235+
return ans1 > 0 ? Math.max(ans1, sum - ans2) : ans1;
236+
}
237+
```
238+
239+
```ts
240+
function maxSubarraySumCircular(nums: number[]): number {
241+
const inf = 1 << 30;
242+
let [pmi, pmx] = [0, -inf];
243+
let [ans, s, smi] = [-inf, 0, inf];
244+
for (const x of nums) {
245+
s += x;
246+
ans = Math.max(ans, s - pmi);
247+
smi = Math.min(smi, s - pmx);
248+
pmi = Math.min(pmi, s);
249+
pmx = Math.max(pmx, s);
250+
}
251+
return Math.max(ans, s - smi);
252+
}
253+
```
254+
158255
### **...**
159256

160257
```

0 commit comments

Comments
 (0)