If an array contains N number of elements (elements can be repeated) and the goal is to make all the elements equal by a +1 on an element and a -1 on another element in each iteration, how can we determine whether it's possible or not to normalize the array? What will be the optimal algorithm to solve the problem?
Ex.
For the array 1 2 3, if I apply +1 on 1 and -1 on 3, the array becomes 2 2 2. That means it's possible in 1 iteration.
For the array 1 2 1, it's not possible to make all the elements equal.
First, since you're not disturbing the sum by each iteration, since you're increasing one number and decreasing another, the optimal target value is going to be the average.
If this average is a whole number, you should be able to achieve it with the iterations, however if the average is a fractional number then you will not be able to achieve it.
The number of steps is going to be the sum of the distances between each number and the target, divided by 2.
Every iteration pick one number above target and one below and apply the operations to them.
PS! As per commented, if all you want is answers to the following two questions:
Can it be done
What will the value be
Then the answers are:
Yes, provided the average number is a whole number
The value repeated in the whole array is the average number
Anyway, if you want the actual operations getting from the input to the target values, here's a longer example:
1 2 3 4 5 6 7 = 28, 28/7 = 4 (optimal target)
+ -
2 2 3 4 5 6 6
+ -
3 2 3 4 5 6 5
+ -
4 2 3 4 5 6 4
+ -
4 3 3 4 5 5 4
+ -
4 4 3 4 5 4 4
+ -
4 4 4 4 4 4 4
6 steps, let's total the distances from the first number:
1 2 3 4 5 6 7
3 2 1 0 1 2 3 = 12, divided by 2 = 6
Here's the example from the comments on the question:
1 9 10 12 3 7 = 42 / 6 = 7 (optimal target)
Distances:
1 9 10 12 3 7
6 2 3 5 4 0 = 20, divided by 2 = 10 (steps)
1 9 10 12 3 7
+ - step 1
2 8 10 12 3 7
+ - step 2
3 7 10 12 3 7
+ - step 3
4 7 9 12 3 7
+ - step 4
5 7 8 12 3 7
+ - step 5
6 7 7 12 3 7
+ - step 6
7 7 7 11 3 7
- + step 7
7 7 7 10 4 7
- + step 8
7 7 7 9 5 7
- + step 9
7 7 7 8 6 7
- + step 10
7 7 7 7 7 7
Here is a more pseudo-code like algorithm description:
Calculate SUM of all the elements
COUNT all the elements
If AVERAGE (SUM/COUNT) is not whole number, solution is not possible to achieve
STEPS = SUM(ABS(numberN - AVERAGE))/2
Each iteration, pick one number below AVERAGE and one above
Apply + operation to number below and - operation to number above
Repeat steps 5 and 6 until target achieved
Related
I have a matrix like following,
A =
1 2 3
4 5 6
7 8 9
10 11 12
4 5 6
7 8 9
4 5 6
1 2 3
I could extract unique rows in this matrix using command A_unique = unique(A,'rows') and result as follows
A_unique =
1 2 3
4 5 6
7 8 9
10 11 12
I need to find number of times each rows exists in the main matrix A
Some thing like following
A_unique_count =
2
3
2
1
How can I find count of unique rows? Can anyone help? Thanks in Advance
Manu
The third output of unique gives you the index of the unique row in the original array. You can use this with accumarray to count the number of occurrences.
For example:
A = [1 2 3
4 5 6
7 8 9
10 11 12
4 5 6
7 8 9
4 5 6
1 2 3];
[uniquerow, ~, rowidx] = unique(A, 'rows');
noccurrences = accumarray(rowidx, 1)
Returns:
noccurrences =
2
3
2
1
As expected
I would recommend #excaza's approach. But just for variety:
A_unique_count = diff([0; find([any(diff(sortrows(A), [], 1), 2); 1])]);
This question already has an answer here:
3d matrix: how to use (row, column) pairs with 3rd dimension wildcard in MATLAB?
(1 answer)
Closed 5 years ago.
I am trying to get a few values from a 2D matrix
Consider the starting matrix:
>> test = randi(10,10)
test =
10 4 8 7 10 4 2 8 4 1
6 5 6 5 5 2 10 4 7 6
7 2 5 4 1 1 3 7 6 1
1 3 3 9 9 5 10 4 6 9
9 1 8 4 7 2 3 7 3 10
8 10 3 9 4 8 4 1 3 1
2 7 1 8 10 4 1 10 5 10
6 10 8 9 3 9 7 9 3 1
4 2 7 6 7 8 2 8 9 7
6 10 8 7 7 6 1 9 10 8
What I want to do is grab elements (1,4);(2,5);and(3,6) only
So I try
test([1,2,3],[4,5,6])
but that returns all combinations of the two indicies!
ans =
6 3 1
1 2 4
8 4 8
Without this intermediate step, how do I do what I want in one line? There must be a way.
I cannot use the intermediate step because in actuality, my matrix is very large and so are my indices lengths so I will run out of memory.
You can do this using sub2ind as was already pointed out at mathworks:
test(sub2ind(size(test),[1,2,3],[4,5,6]))
Applied to 3D
test = randi(10,10,10,10);
test(sub2ind(size(test),[1,2,3],[4,5,6], [3,3,3]))
Let c be 2D array, and x and y be 1D arrays of the same length (for instance, let's have x=1:7 and y=3:9).
I need to find a way to pass in arguments from x and y in the way I will describe below.
If I put simply c(x,y) it will give a 7 by 7 matrix. I don't want that.
Instead, I want to pass in the diagonal of the [x y] matrix: ((x(1), y(1)), (x(2), y(2))...(x(7), y(7)). Is there a way to do this without a for loop or any iterative statement?
You are looking for sub2ind function
res = c( sub2ind(size(c), x, y ) )
There's an easier way. If you're looking for a diagonal, use diag. If you have a matrix c:
c =
5 8 4 2 9 1 6 1 1
9 8 7 5 9 3 2 7 5
2 3 9 10 2 1 4 2 2
3 2 9 2 4 4 7 2 4
3 9 10 8 7 5 2 1 8
5 6 3 7 6 1 10 5 2
6 1 7 3 10 8 2 4 2
you can find the main diagonal by using diag with no extra arguments:
>> diag(c)
ans =
5
8
9
2
7
1
2
The second argument, though, indicates which diagonal you want as an offset from the main diagonal. So the default diagonal is equal to 0. If you want the diagonal starting at c(1,3), that's 2 above the main diagonal, so
>> diag(c,2)
ans =
4
5
2
4
2
5
2
Similarly, if you want the diagonal starting at c(4,1), the offset is -3:
>> diag(c,-3)
ans =
3
9
3
3
I have the following matrix:
[ 2 5 7 8 1 3 4 6 5 7 3 1;
1 1 1 1 2 2 2 2 3 3 3 3;]
The first row represents values and the second characteristic
I want to get the max value if the value in the second row is the same, i.e. their characteristic is the same. So, what I would like to have is:
[ 8 6 7], since 8 is the highest value when the second row is 1, 6 when the second row is is 2, and 7 when the second row is 3. I can do it with a loop, but I would like vectorized solution, and if possible of course, in one line.
accumarray does exactly what you want
x=[ 2 5 7 8 1 3 4 6 5 7 3 1; 1 1 1 1 2 2 2 2 3 3 3 3;]
accumarray(x(2,:)',x(1,:)',[],#max)
Suppose I have a 2D array called A. I want to create a 3D array called B, whose "pages" are select columns of a stencil moving across A, column-by-column. For example, the first page of B might be the 1st, 3rd, and 5th columns of A. Then the second page would be the 2nd, 4th, and 6th columns of A, etc.
Anyone have an efficient way of doing this is MATLAB?
Thanks!
I am guessing you are looking for this -
%%// Given 2D array
A = randi(10,4,12)
t1 = reshape(A,size(A,1)*2,[]);
t2 = reshape(t1',size(A,2)/2,[],2); %%//'
B = permute(t2,[2 1 3]) %%// Output 3D array
Output -
A =
5 10 3 5 6 8 4 3 8 10 8 7
10 8 3 7 6 10 9 2 7 8 8 5
10 4 7 8 6 4 5 4 1 1 3 7
7 7 6 6 1 10 5 8 9 4 3 3
B(:,:,1) =
5 3 6 4 8 8
10 3 6 9 7 8
10 7 6 5 1 3
7 6 1 5 9 3
B(:,:,2) =
10 5 8 3 10 7
8 7 10 2 8 5
4 8 4 4 1 7
7 6 10 8 4 3
Of course, there is an alternative straight-forward approach for this special case -
B(:,:,1)=A(:,1:2:end);
B(:,:,2)=A(:,2:2:end);