-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathProblem_0134_canCompleteCircuit.cc
200 lines (186 loc) · 4.5 KB
/
Problem_0134_canCompleteCircuit.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
#include <iostream>
#include <queue>
#include <vector>
#include "UnitTest.h"
using namespace std;
class Solution
{
public:
// TODO: figure it out
int canCompleteCircuit1(vector<int> &gas, vector<int> &cost)
{
vector<bool> good = goodArray(gas, cost);
for (int i = 0; i < gas.size(); i++)
{
if (good[i])
{
return i;
}
}
return -1;
}
vector<bool> goodArray(vector<int> &g, vector<int> &c)
{
int N = g.size();
int M = N << 1;
vector<int> arr(M);
for (int i = 0; i < N; i++)
{
arr[i] = g[i] - c[i];
arr[i + N] = g[i] - c[i];
}
for (int i = 1; i < M; i++)
{
arr[i] += arr[i - 1];
}
deque<int> w;
for (int i = 0; i < N; i++)
{
while (!w.empty() && arr[w.back()] >= arr[i])
{
w.pop_back();
}
w.push_back(i);
}
vector<bool> ans(N);
for (int offset = 0, i = 0, j = N; j < M; offset = arr[i++], j++)
{
if (arr[w.front()] - offset >= 0)
{
ans[i] = true;
}
if (w.front() == i)
{
w.pop_front();
}
while (!w.empty() && arr[w.back()] >= arr[j])
{
w.pop_back();
}
w.push_back(j);
}
return ans;
}
// 这个方法的时间复杂度O(N),额外空间复杂度O(1) 训练营讲了
int canCompleteCircuit2(vector<int> &gas, vector<int> &cost)
{
if (gas.size() == 0)
{
return -1;
}
if (gas.size() == 1)
{
return gas[0] < cost[0] ? -1 : 0;
}
vector<bool> good = stations(cost, gas);
for (int i = 0; i < gas.size(); i++)
{
if (good[i])
{
return i;
}
}
return -1;
}
vector<bool> stations(vector<int> &cost, vector<int> &gas)
{
if (cost.size() < 2 || cost.size() != gas.size())
{
return {};
}
int init = changeDisArrayGetInit(cost, gas);
return init == -1 ? vector<bool>(cost.size()) : enlargeArea(cost, init);
}
int changeDisArrayGetInit(vector<int> &dis, vector<int> &oil)
{
int init = -1;
for (int i = 0; i < dis.size(); i++)
{
dis[i] = oil[i] - dis[i];
if (dis[i] >= 0)
{
init = i;
}
}
return init;
}
vector<bool> enlargeArea(vector<int> &dis, int init)
{
vector<bool> res(dis.size());
int start = init;
int end = nextIndex(init, dis.size());
int need = 0;
int rest = 0;
do
{
// 当前来到的start已经在连通区域中,可以确定后续的开始点一定无法转完一圈
if (start != init && start == lastIndex(end, dis.size()))
{
break;
}
// 当前来到的start不在连通区域中,就扩充连通区域
if (dis[start] < need)
{ // 当前start无法接到连通区的头部
need -= dis[start];
}
else
{ // 当前start可以接到连通区的头部,开始扩充连通区域的尾巴
rest += dis[start] - need;
need = 0;
while (rest >= 0 && end != start)
{
rest += dis[end];
end = nextIndex(end, dis.size());
}
// 如果连通区域已经覆盖整个环,当前的start是良好出发点,进入2阶段
if (rest >= 0)
{
res[start] = true;
connectGood(dis, lastIndex(start, dis.size()), init, res);
break;
}
}
start = lastIndex(start, dis.size());
} while (start != init);
return res;
}
// 已知start的next方向上有一个良好出发点
// start如果可以达到这个良好出发点,那么从start出发一定可以转一圈
void connectGood(vector<int> &dis, int start, int init, vector<bool> &res)
{
int need = 0;
while (start != init)
{
if (dis[start] < need)
{
need -= dis[start];
}
else
{
res[start] = true;
need = 0;
}
start = lastIndex(start, dis.size());
}
}
int lastIndex(int index, int size) { return index == 0 ? (size - 1) : index - 1; }
int nextIndex(int index, int size) { return index == size - 1 ? 0 : (index + 1); }
};
void testCanCompleteCircuit()
{
Solution s;
vector<int> g1 = {1, 2, 3, 4, 5};
vector<int> c1 = {3, 4, 5, 1, 2};
vector<int> g2 = {2, 3, 4};
vector<int> c2 = {3, 4, 3};
EXPECT_EQ_INT(3, s.canCompleteCircuit1(g1, c1));
EXPECT_EQ_INT(-1, s.canCompleteCircuit1(g2, c2));
EXPECT_EQ_INT(3, s.canCompleteCircuit2(g1, c1));
EXPECT_EQ_INT(-1, s.canCompleteCircuit2(g2, c2));
EXPECT_SUMMARY;
}
int main()
{
testCanCompleteCircuit();
return 0;
}