-
Notifications
You must be signed in to change notification settings - Fork 0
/
AdjacencyCounts.cpp
244 lines (192 loc) · 6.93 KB
/
AdjacencyCounts.cpp
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/*
Adjacency count
Given a sequence of 0 and 1's
The adjacency count of the sequence is the maximum length of an interval
of equal values
Additional condition :
Exactly one of the values must be inverted
Fast algorithm :
Scan over values and keep track of adjacency sequence.
Notice that a seqence can be extended by allowing for exactly one value to be inverted
if the value is of the opposite value of the members of the adjacency sequence
If during the scan an adjacency sequence can only be extended by inverting the current value for a second
time : the adjancency sequence ends.
*/
#include <vector>
#include <list>
#include <algorithm>
#include <iostream>
typedef std::vector<int> tIntVec;
// Test cases
tIntVec test_1 = { 1,1,1,0,1,0,0,0,1,1,1,0,0,1,1,0 };
tIntVec test_2 = { 1,1,1,0,1,0,0,0,1,1,1,1,1,0,0,1,1,0 };
// Find maximum adjacency count of a sequence
int
FindMaximumAdjacencyCount(const tIntVec& inSeq)
{
if (inSeq.empty())
{
return 0;
}
int max_length(1);
int length(1);
int curr_val(inSeq[0]);
for (auto s_it (inSeq.begin() + 1); s_it != inSeq.end(); ++s_it)
{
if (*s_it == curr_val)
{
++length;
}
else
{
max_length = std::max(max_length, length);
curr_val = *s_it;
length = 1;
}
}
// Compare with current adjacency sequence
return std::max(max_length, length);
}
// Find maximum adjacency count of a sequence where one value must be inverted
// Algorithm : iterate over complete sequence, invert value at iterator and run FindMaximumAdjacencyCount() over created sequence
int
FindMaximumAdjacencyCountWithOneElementInvertedSimple(const tIntVec& inSeq)
{
tIntVec test_seq(inSeq);
int max_seq(0);
for (auto s_it(test_seq.begin()); s_it != test_seq.end(); ++s_it)
{
// Invert one item
int val(*s_it);
*s_it = (val == 0) ? 1 : 0;
max_seq = std::max(max_seq, FindMaximumAdjacencyCount(test_seq));
*s_it = val;
}
return max_seq;
}
// Adjacency sequence counter utility class
//
class AdjSeqCounters
{
public:
// Constructor
AdjSeqCounters(int inTrackValue);
// Update counters
// Return adjacency count if sequence ends
void Update(int inValue);
// Return adjacency count for valid sequences
// Takes into account that one value must be inverted
int GetAdjacencySequenceLengthAtEnd();
private:
// Value of individual elements for which the counters are tracking
int mTrackValue;
// Current length of adjacency sequence for which not yet one value is inverted
int mSeqCount;
// Current length of adjacency sequence for which exactly one value is inverted
int mSeqCountOneInv;
// Maximum length of adjacency sequence with exactly one value inverted
int mMaxSeqCount;
};
// Constructor
AdjSeqCounters::AdjSeqCounters(int inTrackValue) :
mTrackValue (inTrackValue),
mSeqCount (0),
mSeqCountOneInv (0),
mMaxSeqCount (0)
{
}
// Update counters
// Track maximum adjacency count if adjacency sequence ends
void
AdjSeqCounters::Update(int inValue)
{
if (inValue == mTrackValue)
{
// Current value is equal to value of tracked sequences
++mSeqCount;
if (mSeqCountOneInv > 0)
{
// Sequence with one inverted value exists
++mSeqCountOneInv;
}
}
else
{
// Current value is opposite of value of tracked sequences
// Sequence with one inverted value ends
mMaxSeqCount = std::max(mMaxSeqCount, mSeqCountOneInv);
mSeqCountOneInv = 0;
if (mSeqCount > 0)
{
// Sequence with no inverted values is extended with one inverted value
mSeqCountOneInv = mSeqCount + 1;
// Sequence with no inverted value is reset
mSeqCount = 0;
}
}
}
// Return adjacency count for valid sequences
// Takes into account that one value must be inverted
int
AdjSeqCounters::GetAdjacencySequenceLengthAtEnd()
{
return std::max(
std::max(
mSeqCount - 1,
mSeqCountOneInv),
mMaxSeqCount);
}
// Find maximum adjacency count of a sequence with one value inverted
// In one scan over the sequence
int
FindMaximumAdjacencyCountWithOneElementInvertedFast(const tIntVec& inSeq)
{
AdjSeqCounters seq_counters_zeros(0);
AdjSeqCounters seq_counters_ones(1);
int max_seq(0);
for (auto s_it(inSeq.begin()); s_it != inSeq.end(); ++s_it)
{
seq_counters_zeros.Update(*s_it);
seq_counters_ones.Update(*s_it);
}
return std::max(
std::max(
seq_counters_zeros.GetAdjacencySequenceLengthAtEnd(),
seq_counters_ones.GetAdjacencySequenceLengthAtEnd()
),
max_seq);
}
// Test parameters
// Number of tests
const int TEST_COUNT = 100;
// Maximum length of a sequence
const int MAX_SEQ_LENGTH = 1000;
int
main()
{
// Human verifiable test cases
std::cout << "Max adjacency count test_1 : " << FindMaximumAdjacencyCount(test_1) << std::endl;
std::cout << "Max adjacency count test_2 : " << FindMaximumAdjacencyCount(test_2) << std::endl;
std::cout << "Max one flipped seq test_1 simple : " << FindMaximumAdjacencyCountWithOneElementInvertedSimple(test_1) << std::endl;
std::cout << "Max one flipped seq test_2 simple : " << FindMaximumAdjacencyCountWithOneElementInvertedSimple(test_2) << std::endl;
std::cout << "Max one flipped seq test_1 fast : " << FindMaximumAdjacencyCountWithOneElementInvertedFast(test_1) << std::endl;
std::cout << "Max one flipped seq test_2 fast : " << FindMaximumAdjacencyCountWithOneElementInvertedFast(test_2) << std::endl;
// Computer generated test cases
// Verified by comparison with simple algorithm
int test_case_fail_count(0);
for (int t_ix(0); t_ix < TEST_COUNT; ++t_ix)
{
// Generate testcase
tIntVec seq(rand() % MAX_SEQ_LENGTH);
for_each(seq.begin(), seq.end(), [](int &outVal) { outVal = rand() % 2; });
// Test
int max_adj_count_simpe(FindMaximumAdjacencyCountWithOneElementInvertedSimple(seq));
int max_adj_count_fast(FindMaximumAdjacencyCountWithOneElementInvertedFast(seq));
if (max_adj_count_simpe != max_adj_count_fast)
{
++test_case_fail_count;
}
}
std::cout << "Count of test cases for which a difference was found between simple and fast algorithm : " << test_case_fail_count << std::endl;
return 0;
}