This is related to the question "Manipulate Arrays" on hackerrank: https://www.hackerrank.com/challenges/crush/problem
Could you explain why this code subtracts from the 2nd element in the queries array and how is it totalling the numbers at the end. I added print statements to see why this works but I am stuck.
def arrayManipulation(n, queries):
arr = [0]*n
for i in queries:
arr[i[0] - 1] += i[2]
if i[1] != len(arr):
arr[i[1]] -= i[2]
maxval = 0
itt = 0
for q in arr:
itt += q
if itt > maxval:
maxval = itt
return maxval
Instead of adding the value to each element in the range, the value is added to the first element of the range and subtracted from the element after the last element of the range. This way, when iterating over the array from the beginning and summing all the values, you get the current value of each element. So, an example with n == 5:
0 0 0 0 0
query 1 3 100
100 0 0 -100 0
query 2 4 200
100 200 0 -100 -200
If you now iterate over the array and sum the values while doing so, you will get the values:
100 300 300 200 0
which is the correct state of the array after such queries.
Edit: For queries where the ending index is equal to the length of the array the value is not subtracted from anything because there are no elements after the last one, so there is no point in doing so.
Related
Here is a 10x10 array arr.
This arr has 100 elements. And it has distribution from -10 to 10 and there are 5 0-value.
I did this code because I wanted to know the number of 0.
count = 0;
for i = 1: 10
for j = 1: 10
if (arr (i, j) == 0)
count = count +1;
end
end
end
Logically, count should be 5 in MATLAB's workspace. and i and j are 10.
However, when I run the code, count is 0.
This code can not count the numbers.
How can I count the numbers?
You can just use nnz to get the number of non-zero elements in a logical array, so the number of elements in arr with the value 0 is
count = nnz( arr == 0 );
Please read Why is 24.0000 not equal to 24.0000 in MATLAB? for information about comparisons of floating point numbers, you may need to do
tol = 1e-6; % some tolerance on your comparison
count = nnz( abs(arr) < tol ); % abs(arr - x) for values equal to x within +/-tol
correct me if I'm wrong but it sounds like you want the number of occurrences of the numbers in your vector, here's an alternative if that is the case:
arr=[1 2 2;3 3 3;5 0 0;0 0 0]; % example array where 1,2,3 occur 1x,2x,3x and 5=>1x, 0=>5x
[x(:,2),x(:,1)]=hist(arr(:),unique(arr(:)));
outputs sorted category as first column, occurrences as 2nd column:
x =
0 5
1 1
2 2
3 3
5 1
I'm having some trouble writing a MATLAB code that needs to locate the max value of each cell of my one cell array, vel_data, a 1x430 cell containing several excel sheets worth of data consisting of M rows x 1 column. I want to extract the max value, as well as every value before and after that max value until the first 0 is reached into a new cell array.
e.g. if the first cell in the array were [3 2 1 0 2 6 4 3 0 1 0] it would extract the values [0 2 6 4 3 0] and do so for every cell in the array.
I know the following extracts the max values of the cell array but I would like for it to do as I mentioned above.
d=dir(f);
for n=1:numel(d)
max_vel{n} = deal(max(vel_data{n}));
end
Any advice/sample code would be very much appreciated.
First index of max value extracted as idx. Then indexes of all elements that are 0 extracted as f1. Index of the element that is 0 and is immediately before max value extracted as f2. and f3 is index of the element that is 0 and is immediately after max value.
vel_data = {[3 1 0 2 6 4 0 1 0] , [1 1 0 9 3 0 4 6 9]}
for n=1:numel(vel_data)
data = vel_data{n};
[~,idx] = max(data);
f1 = find(data==0);
if isempty(f1)
max_vel{n} = data;
continue;
end
f2 = find(f1 < idx,1,'last');
f3 = find(f1 > idx,1);
if isempty(f2)
idx_first = 1;
else
idx_first =f1(f2);
end
if isempty(f3)
idx_last = numel(data);
else
idx_last =f1(f3);
end
max_vel{n} = data(idx_first:idx_last);
end
I have an array (say of 1s and 0s) and I want to find the index, i, for the first location where 1 appears n times in a row.
For example,
x = [0 0 1 0 1 1 1 0 0 0] ;
i = 5, for n = 3, as this is the first time '1' appears three times in a row.
Note: I want to find where 1 appears n times in a row so
i = find(x,n,'first');
is incorrect as this would give me the index of the first n 1s.
It is essentially a string search? eg findstr but with a vector.
You can do it with convolution as follows:
x = [0 0 1 0 1 1 1 0 0 0];
N = 3;
result = find(conv(x, ones(1,N), 'valid')==N, 1)
How it works
Convolve x with a vector of N ones and find the first time the result equals N. Convolution is computed with the 'valid' flag to avoid edge effects and thus obtain the correct value for the index.
Another answer that I have is to generate a buffer matrix where each row of this matrix is a neighbourhood of overlapping n elements of the array. Once you create this, index into your array and find the first row that has all 1s:
x = [0 0 1 0 1 1 1 0 0 0]; %// Example data
n = 3; %// How many times we look for duplication
%// Solution
ind = bsxfun(#plus, (1:numel(x)-n+1).', 0:n-1); %'
out = find(all(x(ind),2), 1);
The first line is a bit tricky. We use bsxfun to generate a matrix of size m x n where m is the total number of overlapping neighbourhoods while n is the size of the window you are searching for. This generates a matrix where the first row is enumerated from 1 to n, the second row is enumerated from 2 to n+1, up until the very end which is from numel(x)-n+1 to numel(x). Given n = 3, we have:
>> ind
ind =
1 2 3
2 3 4
3 4 5
4 5 6
5 6 7
6 7 8
7 8 9
8 9 10
These are indices which we will use to index into our array x, and for your example it generates the following buffer matrix when we directly index into x:
>> x = [0 0 1 0 1 1 1 0 0 0];
>> x(ind)
ans =
0 0 1
0 1 0
1 0 1
0 1 1
1 1 1
1 1 0
1 0 0
0 0 0
Each row is an overlapping neighbourhood of n elements. We finally end by searching for the first row that gives us all 1s. This is done by using all and searching over every row independently with the 2 as the second parameter. all produces true if every element in a row is non-zero, or 1 in our case. We then combine with find to determine the first non-zero location that satisfies this constraint... and so:
>> out = find(all(x(ind), 2), 1)
out =
5
This tells us that the fifth location of x is where the beginning of this duplication occurs n times.
Based on Rayryeng's approach you can loop this as well. This will definitely be slower for short array sizes, but for very large array sizes this doesn't calculate every possibility, but stops as soon as the first match is found and thus will be faster. You could even use an if statement based on the initial array length to choose whether to use the bsxfun or the for loop. Note also that for loops are rather fast since the latest MATLAB engine update.
x = [0 0 1 0 1 1 1 0 0 0]; %// Example data
n = 3; %// How many times we look for duplication
for idx = 1:numel(x)-n
if all(x(idx:idx+n-1))
break
end
end
Additionally, this can be used to find the a first occurrences:
x = [0 0 1 0 1 1 1 0 0 0 0 0 1 0 1 1 1 0 0 0 0 0 1 0 1 1 1 0 0 0]; %// Example data
n = 3; %// How many times we look for duplication
a = 2; %// number of desired matches
collect(1,a)=0; %// initialise output
kk = 1; %// initialise counter
for idx = 1:numel(x)-n
if all(x(idx:idx+n-1))
collect(kk) = idx;
if kk == a
break
end
kk = kk+1;
end
end
Which does the same but shuts down after a matches have been found. Again, this approach is only useful if your array is large.
Seeing you commented whether you can find the last occurrence: yes. Same trick as before, just run the loop backwards:
for idx = numel(x)-n:-1:1
if all(x(idx:idx+n-1))
break
end
end
One possibility with looping:
i = 0;
n = 3;
for idx = n : length(x)
idx_true = 1;
for sub_idx = (idx - n + 1) : idx
idx_true = idx_true & (x(sub_idx));
end
if(idx_true)
i = idx - n + 1;
break
end
end
if (i == 0)
disp('No index found.')
else
disp(i)
end
I'm working with a 2D Logical array and i need to make all its elements zero, except some elements whose indices are randomly given in another 2D double array. By randomly i mean that the rows no. and cols no. are not in sequence.
consider:
A=[1 0 0; 0 1 1; 1 1 0]; %The logical array
I=[3 1; 2 3]; % indices of the elements i want them unchanged(stay 1)
final_A=[0 0 0; 0 0 1; 1 0 0]; % expected output
Any help?
You really just need a matrix the size of A where the elements in I are set to true and all others are set to false. You can use sub2ind to convert from the row/column specified in I to absolute indices.
final_A = false(size(A));
final_A(sub2ind(size(A), I(:,1), I(:,2))) = true;
0 0 0
0 0 1
1 0 0
This assumes that all elements of A specified in I were true to begin with. If this was not the case, then you will want to ensure that only the ones that were initially true in A are kept. You can do this using an element-wise and (&) operation.
final_A = final_A & A;
I am comparing a 100 x 1 called "x" with the value from a 4 x 1 matrix called "xCP". I need a finalMatrix with only the values in x that are higher than the third value from xCP. However, the code i have below provides me with a 100 x 1 matrix with zeros in rows that the value are not higher. I only want the 25(e.g.) rows in finalMatrix that have the higher value. So my finalMatrix needs to be a 25 x 1 with values instead of 100 x 1 with 25 values and 75 zeros.
This is what i have so far:
K = size (x)
length = K(1)
finalMatrix = zeros(length,1);
count = 1;
for i=1:length;
if x(count,1) >= xCP(3)
finalMatrix(count,1) = x(count,1);
end
count =count+1;
end
Thank you!
You can add finalMatrix(count+1:length,1) = [] in the end of the code. It will remove the excess elements.