Algorithm: Find smallest contiguous array containing K 0's in array of 1's and 0's - arrays

I have array of 1's and 0's only. Now I want to find smallest contiguous subset/subarray which contains at least K 0's.
Example
Array is 1 1 0 1 1 0 1 1 0 0 0 0 1 0 1 1 0 0 0 1 1 0 0 1 0 0 0
and K(6) should be 0 0 1 0 1 1 0 0 0 or 0 0 0 0 1 0 1 1 0....
My Solution
Array: 1 1 0 1 1 0 1 1 0 0 0 0 1 0 1 1 0 0 0 1 1 0 0
Index: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Sum: 1 2 2 3 4 4 5 6 6 6 6 6 7 7 8 9 9 9 9 10 11 11 11
Diff(I-S): 0 0 1 1 1 2 2 2 3 4 5 6 6 7 7 7 8 9 10 10 10 11 12
For K(6)
Start with 9-15 = Store difference in diff.
Next increase difference
8-15(Difference in index)
8-14(Compare Difference in index)
So on keep moving to find element with least elements...
I am looking for better algorithm for this solution.

I believe you could do it with a rolling window like:
In the given array, find the first occurance of 0 (say at index i).
Keep on scanning until you've k 0's included in your window (say, the window ends at index j) Record the window Length(say j-i+1=L).
Now, discard the left-most 0 at index i, and keep scanning till you get next 0 (say at index i'
Extend the right-end of the window situated at j to j' to make the count of 0's = k again.
If the new window-length L'=j'-i'+1 is smaller update it.
Keep on repeating the above procedure till j hits the end of array.
No extra space needed and It's O(N) time-complexity, as an element would be scanned at max twice.

With extra O(k) memory , you can do it in O(n) time.Here is the java code.What you are doing is , if a[i]==0 then you check where the queue's first element points to.and if the differnce in positions is less than minimum, then you update the answer.
Queue<Integer> queue =new LinkedList<Integer>();
int i=0;
while(queue.size()<k&&i<n)
{
if(a[i]==0)
{
queue.add(i);
}
i++;
}
if(i==n&&queue.size()<k)
System.out.println("Insufficient 0''s");
int ans=i-1-queue.peek();
for(int j=i;j<n;j++)
{
if(a[i]==0)
{
queue.poll();
queue.add(i);
ans=Math.min(ans,i-queue.peek());
}
}
System.out.println(ans);
EDIT :Explanation
We maintain a queue which consist of all the positions which have a 0 and we limit the queue size to be k. So initially in the while loop we fill the queue with the first k indexes. If ofcourse the queue size is less than k after seeing all elements , then it's impossible. After that , we keep going to all the left over elements .Each time we see a 0 , we calcualte the length of the subsequence ,(i-queue.peek()) and find the minimum .Also we remove the first element , and add the latest index again maintaining the queue size

fully working python code:
>>> A = "1 1 0 1 1 0 1 1 0 0 0 0 1 0 1 1 0 0 0 1 1 0 0".split()
>>> A = map(int, A)
>>> zero_positions = [i for i, x in enumerate(A) if x == 0]
>>> k = 3
>>> containing_k_zeros_intervals = zip(zero_positions, zero_positions[k:])
>>> min(b - a for a, b in containing_k_zeros_intervals)
3

Scan the array from the starting to find the index till which we get k zeros.
Have two pointers.
Now ptr1 is at the index where first zero is seen.
start = ptr1
ptr2 is at the index where we have found k 0's.
end = ptr2;
a)increment ptr1.
b ) find the index from ptr2+1 until we find k 0's.
c) Say at ptr3 we find K 0's. If ptr3-ptr1 < (end-start) update indexes start and end.
Repeat steps a -c until the end of the list.
At the end, start and end will have indexes where there are k 0's.

Related

MATLAB find first elements in columns of array

Within the context of writing a certain function, I have the following example matrix:
temp =
1 2 0 0 1 0
1 0 0 0 0 0
0 1 0 0 0 1
I want to obtain an array whose each element indicates the number of the element out of all non-zero elements which starts that column. If a column is empty, the element should correspond to the next non-empty column. For the matrix temp, the result would be:
result = [1 3 5 5 5 6]
Because the first non-zero element starts the first column, the third starts the second column, the fifth starts the fifth column and the sixth starts the sixth column.
How can I do this operation for any general matrix (one which may or may not contain empty columns) in a vectorized way?
Code:
temp = [1 2 0 0 1 0; 1 0 0 0 0 0; 0 1 0 0 0 1]
t10 = temp~=0
l2 = cumsum(t10(end:-1:1))
temp2 = reshape(l2(end)-l2(end:-1:1)+1, size(temp))
result = temp2(1,:)
Output:
temp =
1 2 0 0 1 0
1 0 0 0 0 0
0 1 0 0 0 1
t10 =
1 1 0 0 1 0
1 0 0 0 0 0
0 1 0 0 0 1
l2 =
1 1 1 1 1 2 2 2 2 2 2 2 3 3 4 4 5 6
temp2 =
1 3 5 5 5 6
2 4 5 5 6 6
3 4 5 5 6 6
result =
1 3 5 5 5 6
Printing values of each step may be clearer than my explanation. Basically we use cumsum to get the IDs of the non-zero elements. As you need to know the ID before reaching the element, a reversed cumsum will do. Then the only thing left is to reverse the ID numbers back.
Here's another way:
temp = [1 2 0 0 1 0; 1 0 0 0 0 0; 0 1 0 0 0 1]; % data
[~, c] = find(temp); % col indices of nonzero elements
result = accumarray(c, 1:numel(c), [], #min, NaN).'; % index, among all nonzero
% values, of the first nonzero value of each col; or NaN if none exists
result = cummin(result, 'reverse'); % fill NaN's using backwards cumulative maximum

Index array columns using vectors in GNU Octave/MATLAB [duplicate]

This question already has an answer here:
Vector as column index in matrix
(1 answer)
Closed 7 years ago.
While coding in GNU Octave/MATLAB I came through this simple problem I couldn't figure out by myself: I'm trying to select some elements of a matrix by using some indexes stored in an array. Let me put it clear with an example:
Given:
A = zeros(5, 3)
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
I would like to select some elements in A matrix row-wise, by using the values in the auxiliary array B as subindices.
Ie. the following B array
B = [ 1 3 2 1 3 ]'
1
3
2
1
3
should be read as:
1 -> index '1' on first row (element [1, 1])
3 -> index '3' on second row (element [2, 3])
2 -> index '2' on third row (element [3, 2])
1 -> index '1' on fourth row (element [4, 1])
3 -> index '3' on fifth row (element [5, 3])
Therefore, if we assign value '1' to the elements selected using the aforementioned criteria, the resulting matrix would be:
1 0 0
0 0 1
0 1 0
1 0 0
0 0 1
I believe this is a simple operation and I'm convinced that there must be a way to achieve the described behaviour without having to loop across the rows in matrix A.
Thank you.
Edit: Rewrite question so that it is (hopefully) less confusing.
Your question is a bit confusing. You're saying you want to select the elements in A by using the values in the vector B as column indexes, but your example sets (not gets) new values in matrix A. I'm explaining both cases.
Consider this matrix
A = magic(5)
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Say you want to get/set the diagonal elements of A.
Index pairs in that case are [1,1], [2,2], [3,3], [4,4] and [5,5].
To access elements as a vector, run this
A(sub2ind([5,5], (1:5)',(1:5)'))
17
5
13
21
9
To set elements run this
A(sub2ind([5,5], (1:5)',(1:5)')) = 0
0 24 1 8 15
23 0 7 14 16
4 6 0 20 22
10 12 19 0 3
11 18 25 2 0
These commands can be written as
r = 1:5
c = 1:5
A(sub2ind([max(r),max(c)], r',c'))
# to assign values
A(sub2ind([max(r),max(c)], r',c')) = 0
# and to assign different value to each index pair
A(sub2ind([max(r),max(c)], r',c')) = [20 10 50 12 99]
In your example,
r = 1:5
c = B'
A(sub2ind([max(r),max(c)], r',c')) = 1
# or simply A(sub2ind([max(r),max(B)], r',B)) = 1
1 0 0
0 0 1
0 1 0
1 0 0
0 0 1
You can read how sub2ind works here.

Finding or arranging all combinations of given numbers [duplicate]

This question already has answers here:
Find all combinations of a given set of numbers
(9 answers)
Closed 8 years ago.
I hope all you are doing great.
I have an interesting question, which has stuck me. Its about generating combinations in a precise order.
For example i have 4 variables(can be vary) and these 4 variables has some limit to increase for example in this case 2. so i want to generate 2d matrix in a order as:
0 0 0 0
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1 1 0 0
1 0 1 0
1 0 0 1
0 1 1 0
0 1 0 1
0 0 1 1
1 1 1 0
0 1 1 1
1 1 1 1
2 0 0 0
0 2 0 0
0 0 2 0
0 0 0 2
2 1 0 0
2 0 1 0
......
......
and so on.
the number of variables ( in this case 4 ) can be varied and also the maximum limit ( in this case 4) can be varied.
Even i have also find all possible combinations but i am not able to arrange them in this sequence.
it would be great if somebody gives an answer.
cheers!
I'm going to assume you've got n variables, each of which is allowed to range from 0 to b-1. What you want is just counting n-digit numbers in base b. For example, if n = 2 and b = 3, then the sequence you want to produce is
00
01
02
10
11
12
20
21
22
To implement this, write a loop something like the following: (warning: untested code)
def inc(v, b):
for i in range(len(v)):
v[i] = v[i] + 1
if v[i] < b:
break
v[i] = 0
def is_zero(v):
for i in range(len(v)):
if v[i] != 0:
return False
return True
v = [0, 0, 0]
b = 3
while True:
print(v)
inc(v, b)
if is_zero(v):
break
If you look carefully at how this works, you should see how to generalize it if your variables have different upper bounds.

Navigation of matrix from left top to right bottom, only moving to the right or downwards?

actual problem is like this which I got from an Online competition. I solved it but my solution, which is in C, couldn't produce answer in time for large numbers. I need to solve it in C.
Given below is a word from the English dictionary arranged as a matrix:
MATHE
ATHEM
THEMA
HEMAT
EMATI
MATIC
ATICS
Tracing the matrix is starting from the top left position and at each step move either RIGHT or DOWN, to reach the bottom right of the matrix. It is assured that any such tracing generates the same word. How many such tracings can be possible for a given word of length m+n-1 written as a matrix of size m * n?
1 ≤ m,n ≤ 10^6
I have to print the number of ways S the word can be traced as explained in the problem statement. If the number is larger than 10^9+7, I have to print S mod (10^9 + 7).
In the testcases, m and n can be very large.
Imagine traversing the matrix, whatever path you choose you need to take exatcly n+m-2 steps to make the word, among of which n-1 are down and m-1 are to the right, their order may change but the numbers n-1 and m-1 remain same. So the problem got reduced to only select n-1 positions out of n+m-2, so the answer is
C(n+m-2,n-1)=C(n+m-2,m-1)
How to calculate C(n,r) for this problem:
You must be knowing how to multiply two numbers in modular arithmetics, i.e.
(a*b)%mod=(a%mod*b%mod)%mod,
now to calculate C(n,r) you also need to divide, but division in modular arithmetic can be performed by using modular multiplicative inverse of the number i.e.
((a)*(a^-1))%mod=1
Ofcourse a^-1 in modular arithmetic need not equal to 1/a, and can be computed using Extended Euclidean Algorithm, as in your case mod is a prime number therefore
(a^(-1))=a^(mod-2)%mod
a^(mod-2) can be computed efficiently using repetitive squaring method.
I would suggest a dynamic programming approach for this problem since calculation of factorials of large numbers shall involve a lot of time, especially since you have multiple queries.
Starting from a small matrix (say 2x1), keep finding solutions for bigger matrices. Note that this solution works since in finding the solution for bigger matrix, you can use the value calculated for smaller matrices and speed up your calculation.
The complexity of the above soltion IMO is polynomial in M and N for an MxN matrix.
Use Laplace's triangle, incorrectly named also "binomial"
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 0 0 0
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 1 0 0
1 2 0 0 0
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
1 1 1 1 0
1 2 3 0 0
1 3 0 0 0
1 0 0 0 0
0 0 0 0 0
1 1 1 1 1
1 2 3 4 0
1 3 6 0 0
1 4 0 0 0
1 0 0 0 0
1 1 1 1 1
1 2 3 4 5
1 3 6 10 0
1 4 10 0 0
1 5 0 0 0
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 0
1 5 15 0 0
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
1 5 15 35 0
1 1 1 1 1
1 2 3 4 5
1 3 6 10 15
1 4 10 20 35
1 5 15 35 70
Got it? Notice, that elements could be counted as binomial members. The diag members are here: C^1_2, C^2_4,C^3_6,C^4_8, and so on. Choose which you need.

A question about matrix manipulation

Given a 1*N matrix or an array, how do I find the first 4 elements which have the same value and then store the index for those elements?
PS:
I'm just curious. What if we want to find the first 4 elements whose value differences are within a certain range, say below 2? For example, M=[10,15,14.5,9,15.1,8.5,15.5,9.5], the elements I'm looking for will be 15,14.5,15.1,15.5 and the indices will be 2,3,5,7.
If you want the first value present 4 times in the array 'tab' in Matlab, you can use
num_min = 4
val=NaN;
for i = tab
if sum(tab==i) >= num_min
val = i;
break
end
end
ind = find(tab==val, num_min);
By instance with
tab = [2 4 4 5 4 6 4 5 5 4 6 9 5 5]
you get
val =
4
ind =
2 3 5 7
Here is my MATLAB solution:
array = randi(5, [1 10]); %# random array of integers
n = unique(array)'; %'# unique elements
[r,~] = find(cumsum(bsxfun(#eq,array,n),2) == 4, 1, 'first');
if isempty(r)
val = []; ind = []; %# no answer
else
val = n(r); %# the value found
ind = find(array == val, 4); %# indices of elements corresponding to val
end
Example:
array =
1 5 3 3 1 5 4 2 3 3
val =
3
ind =
3 4 9 10
Explanation:
First of all, we extract the list of unique elements. In the example used above, we have:
n =
1
2
3
4
5
Then using the BSXFUN function, we compare each unique value against the entire vector array we have. This is equivalent to the following:
result = zeros(length(n),length(array));
for i=1:length(n)
result(i,:) = (array == n(i)); %# row-by-row
end
Continuing with the same example we get:
result =
1 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0
0 0 1 1 0 0 0 0 1 1
0 0 0 0 0 0 1 0 0 0
0 1 0 0 0 1 0 0 0 0
Next we call CUMSUM on the result matrix to compute the cumulative sum along the rows. Each row will give us how many times the element in question appeared so far:
>> cumsum(result,2)
ans =
1 1 1 1 2 2 2 2 2 2
0 0 0 0 0 0 0 1 1 1
0 0 1 2 2 2 2 2 3 4
0 0 0 0 0 0 1 1 1 1
0 1 1 1 1 2 2 2 2 2
Then we compare that against four cumsum(result,2)==4 (since we want the location where an element appeared for the forth time):
>> cumsum(result,2)==4
ans =
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
Finally we call FIND to look for the first appearing 1 according to a column-wise order: if we traverse the matrix from the previous step column-by-column, then the row of the first appearing 1 indicates the index of the element we are looking for. In this case, it was the third row (r=3), thus the third element in the unique vector is the answer val = n(r). Note that if we had multiple elements repeated 4 times or more in the original array, then the one first appearing for the forth time will show up first as a 1 going column-by-column in the above expression.
Finding the indices of the corresponding answer value is a simple call to FIND...
Here is C++ code
std::map<int,std::vector<int> > dict;
std::vector<int> ans(4);//here we will store indexes
bool noanswer=true;
//my_vector is a vector, which we must analize
for(int i=0;i<my_vector.size();++i)
{
std::vector<int> &temp = dict[my_vector[i]];
temp.push_back(i);
if(temp.size()==4)//we find ans
{
std::copy(temp.begin(),temp.end(),ans.begin() );
noanswer = false;
break;
}
}
if(noanswer)
std::cout<<"No Answer!"<<std::endl;
Ignore this and use Amro's mighty solution . . .
Here is how I'd do it in Matlab. The matrix can be any size and contain any range of values and this should work. This solution will automatically find a value and then the indicies of the first 4 elements without being fed the search value a priori.
tab = [2 5 4 5 4 6 4 5 5 4 6 9 5 5]
%this is a loop to find the indicies of groups of 4 identical elements
tot = zeros(size(tab));
for nn = 1:numel(tab)
idxs=find(tab == tab(nn), 4, 'first');
if numel(idxs)<4
tot(nn) = Inf;
else
tot(nn) = sum(idxs);
end
end
%find the first 4 identical
bestTot = find(tot == min(tot), 1, 'first' );
%store the indicies you are interested in.
indiciesOfInterst = find(tab == tab(bestTot), 4, 'first')
Since I couldn't easily understand some of the solutions, I made that one:
l = 10; m = 5; array = randi(m, [1 l])
A = zeros(l,m); % m is the maximum value (may) in array
A(sub2ind([l,m],1:l,array)) = 1;
s = sum(A,1);
b = find(s(array) == 4,1);
% now in b is the index of the first element
if (~isempty(b))
find(array == array(b))
else
disp('nothing found');
end
I find this easier to visualize. It fills '1' in all places of a square matrix, where values in array exist - according to their position (row) and value (column). This is than summed up easily and mapped to the original array. Drawback: if array contains very large values, A may get relative large too.
You're PS question is more complicated. I didn't have time to check each case but the idea is here :
M=[10,15,14.5,9,15.1,8.5,15.5,9.5]
val = NaN;
num_min = 4;
delta = 2;
[Ms, iMs] = sort(M);
dMs = diff(Ms);
ind_min=Inf;
n = 0;
for i = 1:length(dMs)
if dMs(i) <= delta
n=n+1;
else
n=0;
end
if n == (num_min-1)
if (iMs(i) < ind_min)
ind_min = iMs(i);
end
end
end
ind = sort(iMs(ind_min + (0:num_min-1)))
val = M(ind)

Resources