Edits:
1: Code corrected for edge case highlighted in comment, benchmark updated.
2: Added 'expansion' solution to benchmark (had to reduce max N element to 20000).
3: Added accumarray method to benchmark (Winner for high N), and sparse method.
Here's another way to get the result, without using the function unique or hist.
It does relly on the function sort.
In an expanded form (if you want to see the result of the intermediate steps):
A = [4, 12, 9, 8, 9, 12, 7, 1] ;
[B,I] = sort(A) ; % this will put duplicate elements side by side
df = diff(B) ; % the duplicates will return '0' when substracted
dx = find(df==0) ; % find their indices
% Since each duplicate concerns 2 elemts of the array, we add the next
% index for each "flagged" index, taking care not to duplicate the indices
% of sucessive duplicates.
if ~isempty(dx)
dd = [diff(dx)~=1 , true] ;
dx = [dx dx(dd)+1] ;
d = I(dx) % get the original position of the duplicates in original array
else
d=[] ;
end
Which you could compact to:
[B,I] = sort(A) ;
dx = find(diff(B)==0) ;
if ~isempty(dx)
d = I([dx dx([diff(dx)~=1,true])+1]) ;
else
d = [] ;
end
gives:
d =
3 2 5 6
Personnaly I would also sort the returned indices but if it's not necessary and you're concerned about performance you can just accept the unsorted result.
Here's another benchmark (testing the number of element from 10 to 20000):
run on MATLAB R2016a

And the code for it:
function ExecTimes = benchmark_findDuplicates
nOrder = (1:9).' * 10.^(1:3) ; nOrder = [nOrder(:) ; 10000 ; 20000 ] ;
npt = numel(nOrder) ;
ExecTimes = zeros(npt,6) ;
for k = 1:npt
% Sample data
N = nOrder(k) ;
A = randi(5000,[1,N]) ;
% Benchmark
f1 = @() findDuplicates_histMethod(A) ;
f2 = @() findDuplicates_histcountMethod(A) ;
f3 = @() findDuplicates_sortMethod(A) ;
f4 = @() findDuplicates_expansionMethod(A) ;
f5 = @() findDuplicates_accumarrayMethod(A) ;
f6 = @() findDuplicates_sparseMethod(A) ;
ExecTimes(k,1) = timeit( f1 ) ;
ExecTimes(k,2) = timeit( f2 ) ;
ExecTimes(k,3) = timeit( f3 ) ;
ExecTimes(k,4) = timeit( f4 ) ;
ExecTimes(k,5) = timeit( f5 ) ;
ExecTimes(k,6) = timeit( f6 ) ;
clear A
disp(N)
end
function d = findDuplicates_histMethod(A)
U = unique(A);
[co,ce] = hist(A,U);
an = ce(co>1);
d=[];
for i=1:numel(an)
d=[d,find(A==an(i))];
end
end
function d = findDuplicates_histcountMethod(A)
[~,idxu,idxc] = unique(A);
[count, ~, idxcount] = histcounts(idxc,numel(idxu));
idxkeep = count(idxcount)>1;
idx_A = 1:length(A);
d = idx_A(idxkeep);
end
function d = findDuplicates_sortMethod(A)
[B,I] = sort(A) ;
dx = find(diff(B)==0) ;
if ~isempty(dx)
d = I([dx dx([diff(dx)~=1,true])+1]) ;
else
d=[];
end
end
function d = findDuplicates_expansionMethod(A)
Ae = ones(numel(A),1) * A ;
d = find(sum(Ae==Ae.')>1) ;
end
function d = findDuplicates_accumarrayMethod(A)
d = find(ismember(A, find(accumarray(A(:), 1)>1))) ;
end
function d = findDuplicates_sparseMethod(A)
d = find(ismember(A, find(sparse(A, 1, 1)>1)));
end
end