A brute force approach:
function V = ShuffledVector
x = 100;
Z = 5;
V = [true(1, x/2), false(1, x/2)];
found = false;
iter = 0;
while ~found
V = V(randperm(x, x));
[~, n] = RunLength(V);
found = all(n < Z);
iter = iter + 1;
end
end
function [b,n,idx] = RunLength(x)
x = x(:);
d = [true; diff(x) ~= 0];
b = x(d);
k = find([d', true]);
n = diff(k);
idx = k(1:length(k) - 1);
end
This permutes the complete vector if more than Z neighboring elements are equal. There larger Z is, the more efficient is this method. For x = 100 and Z = 10 one or two iterations are very likely, but for Z=3 you might wait for hours.
.An improvement is shuffle only elements from the blocks of equal values:
...
found = false;
iter = 0;
V = V(randperm(x, x));
while ~found
[b, n, idx] = RunLength(V);
[maxN, maxInd] = max(n);
if maxN > Z
oldIdx = idx(maxInd) + randi(maxN) - 1;
other = find(V ~= b(maxInd));
newIdx = other(randi(numel(other)));
swap = V(oldIdx);
V(oldIdx) = V(newIdx);
V(newIdx) = swap;
else
found = true;
end
iter = iter + 1;
end
This "bombing technique" chooses one element of the largest block of equal data and swaps its values randomly with other elements of V. Per iteration of the while loop, only one of these blocks is processed. It is very likely, that maxN occurs multiple times in n, so it might be better to include another loop:
...
found = false;
maxIter = 1e9;
iter = 0;
V = V(randperm(x, x));
while ~found && iter < maxIter
[b, n, idx] = RunLength(V);
maxN = max(n);
if maxN > Z
for maxInd = find(n == maxN)
oldIdx = idx(maxInd) + randi(maxN) - 1;
other = find(V ~= b(maxInd));
newIdx = other(randi(numel(other)));
swap = V(oldIdx);
V(oldIdx) = V(newIdx);
V(newIdx) = swap;
end
else
found = true;
end
iter = iter + 1;
end
if ~found
error('Cannot find solution in %d iterations!', iter)
end
Here I've added a security limit for the number of iterations.
For x = 100, Z = 5, this needs an average of 6 iterations.
Best Answer