Kth smallest element in sorted matrix - arrays

This is an interview question.
Find the Kth smallest element in a matrix with sorted rows and columns.
Is it correct that the Kth smallest element is one of a[i, j] such as i + j = K ?

False.
Consider a simple matrix like this one:
1 3 5
2 4 6
7 8 9
9 is the largest (9th smallest) element. But 9 is at A[3, 3], and 3+3 != 9. (No matter what indexing convention you use, it cannot be true).
You can solve this problem in O(k log n) time by merging the rows incrementally, augmented with a heap to efficiently find the minimum element.
Basically, you put the elements of the first column into a heap and track the row they came from. At each step, you remove the minimum element from the heap and push the next element from the row it came from (if you reach the end of the row, then you don't push anything). Both removing the minimum and adding a new element cost O(log n). At the jth step, you remove the jth smallest element, so after k steps you are done for a total cost of O(k log n) operations (where n is the number of rows in the matrix).
For the matrix above, you initially start with 1,2,7 in the heap. You remove 1 and add 3 (since the first row is 1 3 5) to get 2,3,7. You remove 2 and add 4 to get 3,4,7. Remove 3 and add 5 to get 4,5,7. Remove 4 and add 6 to get 5,6,7. Note that we are removing the elements in the globally sorted order. You can see that continuing this process will yield the kth smallest element after k iterations.
(If the matrix has more rows than columns, then operate on the columns instead to reduce the running time.)

O(k log(k)) solution.
Build a minheap.
Add (0,0) to the heap. While, we haven't found the kth smallest element, remove the top element (x,y) from heap and add next two elements [(x+1,y) and (x,y+1)] if they haven't been visited before.
We are doing O(k) operations on a heap of size O(k) and hence the complexity.

This problem can be solved using binary search and optimised counting in a sorted Matrix. A binary search takes O(log(n)) time and for each search value it takes n iterations on average to find the numbers that are smaller than the searched number. The search space for binary search is limited to the minimum value in the Matrix at mat[0][0] and the maximum value mat[n-1][n-1].
For every number that is chosen from the binary search we need to count the numbers that are smaller than or equal to that particular number. And thus the smallest number can be found.
For better understanding you can refer to this video:
https://www.youtube.com/watch?v=G5wLN4UweAM&t=145s

Start traversing the matrix from the top-left corner (0,0) and use a binary heap for storing the "frontier" - a border between a visited part of the matrix and the rest of it.
Implementation in Java:
private static class Cell implements Comparable<Cell> {
private final int x;
private final int y;
private final int value;
public Cell(int x, int y, int value) {
this.x = x;
this.y = y;
this.value = value;
}
#Override
public int compareTo(Cell that) {
return this.value - that.value;
}
}
private static int findMin(int[][] matrix, int k) {
int min = matrix[0][0];
PriorityQueue<Cell> frontier = new PriorityQueue<>();
frontier.add(new Cell(0, 0, min));
while (k > 1) {
Cell poll = frontier.remove();
if (poll.y + 1 < matrix[poll.x].length) frontier.add(new Cell(poll.x, poll.y + 1, matrix[poll.x][poll.y + 1]));
if (poll.x + 1 < matrix.length) frontier.add(new Cell(poll.x + 1, poll.y, matrix[poll.x + 1][poll.y]));
if (poll.value > min) {
min = poll.value;
k--;
}
}
return min;
}

As people mentioned previously the easiest way is to build a min heap. Here's a Java implementation using PriorityQueue:
private int kthSmallestUsingHeap(int[][] matrix, int k) {
int n = matrix.length;
// This is not necessary since this is the default Int comparator behavior
Comparator<Integer> comparator = new Comparator<Integer>() {
#Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
};
// building a minHeap
PriorityQueue<Integer> pq = new PriorityQueue<>(n*n, comparator);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
pq.add(matrix[i][j]);
}
}
int ans = -1;
// remove the min element k times
for (int i = 0; i < k; i++) {
ans = pq.poll();
}
return ans;
}

Kth smallest element in the matrix :
The problem can be narrowed down as below.
if k is 20, then take k*k matrix (where answer will definitely lie.)
Now you can merge the rows in pair repeatedly to build a sorted array and then find the kth smallest number.

//int arr[][] = {{1, 5, 10, 14},
// {2, 7, 12, 16},
// {4, 10, 15, 20},
// {6, 13, 19, 22}
//};
// O(k) Solution
public static int myKthElement(int arr[][], int k) {
int lRow = 1;
int lCol = 0;
int rRow = 0;
int rCol = 1;
int count = 1;
int row = 0;
int col = 0;
if (k == 1) {
return arr[row][col];
}
int n = arr.length;
if (k > n * n) {
return -1;
}
while (count < k) {
count++;
if (arr[lRow][lCol] < arr[rRow][rCol]) {
row = lRow;
col = lCol;
if (lRow < n - 1) {
lRow++;
} else {
if (lCol < n - 1) {
lCol++;
}
if (rRow < n - 1) {
lRow = rRow + 1;
}
}
} else {
row = rRow;
col = rCol;
if (rCol < n - 1) {
rCol++;
} else {
if (rRow < n - 1) {
rRow++;
}
if (lCol < n - 1) {
rCol = lCol + 1;
}
}
}
}
return arr[row][col];
}

Related

find number of pairs in an array that are out-of-order

I have written a program that inputs an array of n elements and outputs the number of pair of elements that are out-of-order.
We will call a pair of elements arr[i] and arr[j] out-of-order if i < j and arr[i] > arr[j].
The running time of my program is O(n^2). It's a naive approach with two nested for loops. I was wondering if there is another way to solve this problem in less time. maybe in O(nLogn) time?
The algorithm you are looking for is called Counting inversions. Yes you can solve this problem using divide and conquer approach and the time complexity will be O(nlogn). It's similar to merge sort and additionally we need to keep track of inversions count. I am only printing the inversions count.
public class InversionsInOrderNSquared {
public static void main(String[] args) {
int array[] = { 10, 15, 2, 2, -4, 100, 99999, -10 };
System.out.println("Inversions Count: "+inversions(array));
}
private static int inversions(int[] array) {
int n = array.length;
int inversionCountLeft = 0;
int inversionCountRight = 0;
int inversionCountCross = 0;
if (n >= 2) {
int mid = n / 2;
int[] leftArray = new int[mid];
int[] rightArray = new int[n - mid];
for (int i = 0; i < n; i++) {
if (i < mid) {
leftArray[i] = array[i];
} else {
rightArray[i - mid] = array[i];
}
}
inversionCountLeft = inversions(leftArray);
inversionCountRight = inversions(rightArray);
inversionCountCross = computeInversions(array, leftArray,
rightArray);
}
return (inversionCountLeft + inversionCountRight + inversionCountCross);
}
private static int computeInversions(int[] array, int[] leftArray,
int[] rightArray) {
int n_left = leftArray.length;
int n_right = rightArray.length;
int inversionCount = 0;
int i = 0;
int j = 0;
int k = 0;
while (i < n_left && j < n_right) {
if (leftArray[i] > rightArray[j]) {
array[k] = rightArray[j];
inversionCount += (n_left - i);// logic is we are doing index
// wise element comparison
// between 2 sorted arrays thus
// for any index if any element
// in left
// sub-array is grater than
// element in right sub array
// that mean all the elements
// after that element present in
// left sub-array should be
// grater than right sub-array
// elements. Thus we are
// considering (n_left - i) in
// inversion count calculation.
j++;
} else {
array[k] = leftArray[i];
i++;
}
k++;
}
while (i < n_left) {
array[k] = leftArray[i];
i++;
k++;
}
while (j < n_right) {
array[k] = rightArray[j];
j++;
k++;
}
return inversionCount;
}
}
Execution 1:
Output:
Input array:
int array[] = { 10, 15, 2, 2, -4, 100, 99999, -10 };
Inversions Count: 15
Execution 2:
Input array:
int array[] = { 1,2,3,4,5,6 };
Output:
Inversions Count: 0
Regarding time complexity calculation:
computeInversions() method will take theta(n) time.
inversions() method is getting called 2 times with array size n/2.
Hence the recurrence relation is,
T(n) = 2T(n/2) + theta(n);
It's following Master's theorem equation format.
Hence a =2, b=2 and f(n)=theta(n)
n^log a base b = n^log 2 base 2 = n^1 = n
Thus above recurrence is matching case 2 of Master's theorem.
Thus time complexity is O(nlogn)
You can calculate such out of order pairs in o(nlogn) complexity.
For example if arr[] = {1,5,3,2,4}
Out of order pairs are : (5,3), (5,2), (5,4), (3,2).
Below is the working code for the same :
public static int countOutOfOrder(int []nums) {
int len = nums.length, index=len-1, count=0, currindex=0, total=0;
List<Integer>sorted = new ArrayList<Integer>();
while(index>=0) {
currindex = search(sorted, nums[index]);
sorted.add(currindex, nums[index]);
total+=(currindex);
index--;
}
return total;
}
private static int search(List<Integer> sorted, int value) {
int start=0, end = sorted.size()-1, mid=0;
while(start<=end) {
mid = (start+end)/2;
if(sorted.get(mid) == value && (mid==start || sorted.get(mid-1) == value)) {
return mid;
} else if(sorted.get(mid) <= value) {
start = mid+1;
} else {
end = mid-1;
}
}
return start;
}
Explanation for o(nlogn) solution based on above example :
Maintain a list of sorted elements say sorted
Start from end index
search in sorted list where we can insert the current element in
Based on position we can insert , find total number of elements before this index that will be total inversions.
Add this element in the sorted list.
Time complexity :
We are looping through all elements so complexity for this is o(n)
For each element we are searching in sorted list , search complecity is o(logn).
So, total complexity is o(n)*o(logn) = o(nlogn)

Lowest Maximum Visits in the milestones problem

Hi I was given a problem where I was given the numbers like 1, 50000, 10000, 3, 10001, 10003 and assume that they are the milestones that a runner crosse.
So that means, first he will run from 1 to 50k and then comes back to 10k, and then to 3, and to 10001 and to 10003 etc. Now I have to find the lowest maximum visited milestone in his entire journey.
here is the program I have written. is there any better version for this, to use less space instead of 50k array.
public class LowestMaxVisits {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(50000);
list.add(10000);
list.add(3);
list.add(10001);
list.add(10003);
int [] arr = new int[50000];
long smillis = System.currentTimeMillis() % 1000;
for(int i=0; i<list.size()-1; i++){
int start = list.get(i)-1;
int end = list.get(i+1)-1;
if(start > end){
int temp = start;
start = end;
end = temp;
}
while(start < end){
arr[start]++;
arr[end]++;
start++;
end--;
}
}
int maxVisits = -1;
int index = -1;
for(int k=0;k<arr.length;k++){
if(arr[k] > maxVisits){
index = k;
maxVisits = arr[k];
}
}
long emillis = System.currentTimeMillis() % 1000;
System.out.println("Time taken---"+ (emillis-smillis));
System.out.println("Here is the highest---"+(index+1));
}
}
Here's the code based on how I explained to solve the problem in my comment:
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class LowestMaxVisits {
public static void main(String[] args) {
List<Integer> milestones = new ArrayList<Integer>(){{
add(1);
add(50000);
add(10000);
add(3);
add(10001);
add(10003);
}};
System.out.println(getHighestMilestone(milestones));
}
public static int getHighestMilestone(List<Integer> milestones) {
// Make a sorted milestones array
List<Integer> sortedMilestones = new ArrayList<>(milestones);
int t;
for (int i = 0; i < sortedMilestones.size() - 1; i++) {
for (int j = sortedMilestones.size() - 1; j > i; j--) {
if (sortedMilestones.get(i) > sortedMilestones.get(j)) {
t = sortedMilestones.get(i);
sortedMilestones.set(i, sortedMilestones.get(j));
sortedMilestones.set(j, t);
}
}
}
// Count the amount of times passed for each milestone
t = 0;
int[] mPassed = new int[sortedMilestones.size()];
for (int i = 0; i < milestones.size() - 1; i++) {
if (i == 0 || (milestones.get(i) > sortedMilestones.get(t))) {
for (int j = t + 1; j < sortedMilestones.size(); j++) {
mPassed[j]++;
if (Objects.equals(sortedMilestones.get(j), milestones.get(i))) {
t = j;
break;
}
}
} else {
for (int j = t - 1; j >= 0; j--) {
mPassed[j]++;
if (Objects.equals(sortedMilestones.get(j), milestones.get(i))) {
t = j;
break;
}
}
}
}
// Get the highest count and set it to t
t = 0;
for (int i = 0; i < mPassed.length; i++) {
if (t < mPassed[i]) {
t = mPassed[i];
}
}
// Get lowest milestone with the higest count
for (int i = 0; i < mPassed.length; i++) {
if (mPassed[i] == t) {
t = sortedMilestones.get(i);
break;
}
}
return t;
}
}
You need to sort the copied array in order to iterate through them as if they were "places", back and forth according to the order of stops. You also need it for finding the lowest number milestone with the most visits.
Edit: Instead of making a list as big as the largest number in our array (in your case 50,000), this only needs to make a copy of the milestones array and another integer array of the same size. Note: a int t; variable is also made and reused for multiple purposes throughout getHighestMilestone().
The key observation here is that only the relative order of the milestones matter, not their absolute positions. If we changed the numbers in your example to 0, 5, 2, 1, 3, 4, the problem is still the same, as long as we convert the final output back. If N is the number of milestones in your input, there are at most N distinct positions so we can map them to the integers from 0 to N - 1. One way we can do this quickly is to insert all the positions as keys into an ordered map structure, which I believe is called TreeMap in Java, and then iterating through the keys in increasing order and assigning the next integer as the value for each key.
Now we can count the number of times each milestone was passed using an array, which only needs to be N elements large. When we move from one milestone to the next we can just increment all the array elements in between. However, we might have to increment almost the entire array every time, and we can make this faster. If f(x) is the number of times the milestone x was passed and a is the array, instead of storing f(x) in a[x] we store f(0) in a[0] and f(x) - f(x - 1) in a[x] for x greater than 0. Now to increment the range [l, r], we only need to increment the a[l] and decrement the a[r + 1].
After we processed all the milestones this way, we can iterate through the array and accumulate the elements to obtain the number of times each milestone is passed. It's not hard to see that f(x) = a[0] + a[1] + ... + a[x].
Here's the pseudocode:
let mp be an ordered map structure such as a TreeMap which maps integers to integers and stores elements in order of their key
for each milestone ms:
if ms isn't in mp:
insert ms as a key into mp paired with an arbitrary value
let index = 0
for each key-value pair pos in ms in increasing order of key:
set the value of pos to index
increment index
for each milestone ms:
set ms to mp[ms]
let a be an array
define incrementRange(l, r):
increment a[l]
decrement a[r + 1]
for each milestone ms:
let prev be the previous milestone
if ms is greater than prev:
incrementRange(prev + 1, ms)
else:
incrementRange(ms, prev - 1)
for i from 1 to N - 1:
add a[i - 1] to a[i]
let maxVisited be the minimum index in a of an element with maximum value
output the key in mp with value maxVisited
Time complexity: O(N log N) Space: O(N)
I don't think it gets faster than this.

Algorithm for finding saddle-points in a 2-dimensional array

I'm looking for an algorithm to find the positions of all saddle points in an NxN matrix.
Searching through other answers on StackOverflow, as well as other sites in general, I've only found solutions regarding saddle points that operate in one direction. That is, I want to find a saddle point that can be a maximum in its row and minimum in its column, or a minimum in its row and maximum in its column.
For example, given:
array = {
{ 10, 15, 20, 15, 10 }
{ 5, 10, 15, 10, 5 }
{ 0, 5, 10, 5, 0 }
{ 5, 10, 15, 10, 5 }
{ 10, 15, 20, 15, 10 } },
the saddle points are the 10's in the corners and the 10 in the middle.
I can find them naively fairly easily, but I wanted something more efficient. I've been told it can be done in O(n^2).
I thought perhaps I could fix the x-coordinate and iterate through the y-coordinate to find all maximums and minimums, then reverse the process by fixing the y-coordinate and iterating through the x-coordinate, but I can't quite visualize it well enough to implement the idea.
Any help would be greatly appreciated.
Notice that in the naive implementation O(n3), you are recalculating the maximum value and minimum value for every element of a row/column you go through.
To eliminate this inefficiency, the idea is to loop through every row and column, and mark all positions with the maximum and minimum value in a separate N x N array. Each element of this separate array contains 2 pieces of boolean information: isMax and isMin (which can be encoded as bit if you want to). If all elements in a row/column are the same (i.e. maximum value = minimum value), then you might not want to mark any element.
For each row/column, this can be done in O(n) time. Use an n-element array to record the indices where the current maximum (minimum) value, and clear the array if there is a bigger (smaller) value than the current maximum (minimum). After you have finished looping through, use the information from the maximum (minimum) indices array to mark the corresponding isMax (isMin) field in the N x N array.
Since there are n rows and n columns, the complexity of this step is O(n2)
Then the rest is to loop through the N x N array which you have marked to search for any position with both isMax and isMin set.
O(n^2)
#include <stdio.h>
#define N 8
#define M 10
int arr[N][M] =
{ {1,2,0,3,9,4,5,3,6,7},
{2,4,3,5,9,0,2,3,4,1},
{5,3,4,7,6,1,9,0,4,2},
{6,9,7,8,6,7,7,4,5,6},
{8,3,1,9,2,0,6,2,8,2},
{2,7,3,0,3,6,3,1,5,3},
{8,2,5,9,7,7,8,3,7,3},
{1,7,4,8,5,8,5,0,0,6} };
int FindSaddlePoints(int arr[N][M])
{
int l_result = 0;
int l_row[M], l_column[N], i, j, index;
//find the min
for (i = 0; i < N; i++)
{
index = 0;
for (j = 1; j < M; j++)
{
if (arr[i][j] < arr[i][index])
{
index = j;
}
}
l_column[i] = index;
}
for (j = 0; j < M; j++)
{
index = 0;
//find the max
for (i = 1; i < N; i++)
{
if (arr[i][j] > arr[index][j])
{
index = i;
}
}
l_row[j] = index;
}
for (i = 0; i < N; i++)
{
for (j = 0; j < M; j++)
{
if (l_row[j] == i && l_column[i] == j && i != N && j != M)
{
//printf("found in row = %d column = %d", i, j);
l_result++;
}
}
}
return l_result;
}
void main()
{
int number = FindSaddlePoints(arr);
printf("%d", number);
}

Find Nth element from the two unsorted Array

Given two unsorted int arrays, find the kth element in the merged, sorted array.
example:
int[] a= [3 1 7]
int[] b = [4 9]
k: 3
return 4 (non-Zero based index)
Please do not provide the straight forward solution where merge two array and sort and find the Nth element. I am looking for more efficient solution i.e using Heap, QuickSort. and make sure arrays are unsorted.
P.S: I know there are many similar questions of above posted in SO but i couldn't find any correct way of implementation in any of them.
As it stands your example is wrong.
Assuming its int[] a= [3 1 7] int[] b = [4 9] k: 3 return 7.
Loop through both arrays and push to a min-heap. After your done, pop k times from the heap and you will have the kth (largest) element from the merged array.
PriorityQueue<Integer> minHeap=new PriorityQueue();
for (Integer i : a)
{
minHeap.add(i);
}
for (Integer i : b)
{
minHeap.add(i);
}
int count=1;// 1 based index
while(!minHeap.isEmpty())
{
Integer head=minHeap.poll();
count++;
if(count==k)
return head;
}
Code above is untested. But it should roughly look like the above.
The general term for this problem is Selection Algorithm, which Wikipedia has a great article on.
Finding the kth element of two unsorted arrays is equivalent to finding the kth element of one--just pretend you've concatenated the two. A simple algorithm from the linked page is Quickselect, which is essentially Quicksort but only recursing into the half that contains the kth element. Essentially,
Use the first element as the pivot
Iterate over the array, assigning items <= to the pivot to one array, and > to another, until an array has grown large enough that it must contain the desired element
Recurse on that array, offsetting k if necessary
C# code using quick select algorithm:
private void MergeUnsortedArray(int[] A1, int[] A2)
{
int[] c = new int[A1.Length + A2.Length];
int length = 0;
for (int i = 0; i < A1.Length; i++)
{
c[i] = A2[i];
length++;
}
for (int j = 0; j < A2.Length; j++)
{
c[length + j + 1] = A2[j];
}
quickselect(c, 0, c.Length, 3);
}
private int quickselect(int[] G, int first, int last, int k)
{
if (first <= last)
{
int pivot = partition(G, first, last);
if (pivot == k)
{
return G[k];
}
if (pivot < k)
{
return quickselect(G, first, pivot - 1, k);
}
return quickselect(G, pivot + 1, last, k);
}
return 0;
}
private int partition(int[] G, int first, int last)
{
int pivot = (first + last) / 2;
swap(G, last, pivot);
for (int i = first; i < last; i++)
{
if (G[i] < G[last])
{
swap(G, i, first);
first++;
}
}
swap(G, first, last);
return first;
}
private void swap(int[] G, int x, int y)
{
int tmp = G[x];
G[x] = G[y];
G[y] = tmp;
}

Rearrange an array so that arr[i] becomes arr[arr[i]] with O(1) extra space

The task is to rearrange an array so that arr[i] becomes arr[arr[i]] with O(1) extra space.
Example:
2 1 3 5 4 0
becomes:
3 1 5 0 4 2
I can think of an O(n²) solution. An O(n) solution was presented here:
Increase every array element arr[i] by (arr[arr[i]] % n)*n.
Divide every element by n.
But this is very limited as it will cause buffer overflow.
Can anyone come up with an improvement upon this?
If the values in the array are all positive (or all negative), one way to avoid overflow could be to run the permutation cycles and use the integer sign to mark visited indexes. (Alternatively, if the array length is smaller than 2^(number of bits for one array element - 1), rather than use the sign, we could shift all the values one bit to the left and use the first bit to mark visited indexes.) This algorithm results in both less iterations and less modifications of the original array values during run-time than the algorithm you are asking to improve.
JSFiddle: http://jsfiddle.net/alhambra1/ar6X6/
JavaScript code:
function rearrange(arr){
var visited = 0,tmp,indexes,zeroTo
function cycle(startIx){
tmp = {start: startIx, value: arr[startIx]}
indexes = {from: arr[startIx], to: startIx}
while (indexes.from != tmp.start){
if (arr[indexes.from] == 0)
zeroTo = indexes.to
if (indexes.to == visited){
visited++
arr[indexes.to] = arr[indexes.from]
} else {
arr[indexes.to] = -arr[indexes.from]
}
indexes.to = indexes.from
if (indexes.from != tmp.start)
indexes.from = arr[indexes.from]
}
if (indexes.to == visited){
visited++
arr[indexes.to] = tmp.value
} else {
arr[indexes.to] = -tmp.value
}
}
while (visited < arr.length - 1){
cycle(visited)
while (arr[visited] < 0 || visited == zeroTo){
arr[visited] = -arr[visited]
visited++
}
}
return arr
}
//Traverse the array till the end.
//For every index increment the element by array[array[index] % n]. To get //the ith element find the modulo with n, i.e array[index]%n.
//Again traverse to end
//Print the ith element after dividing the ith element by n, i.e. array[i]/n
class Rearrange
{
void rearrange(int arr[], int n)
{
for (int i = 0; i < n; i++)
arr[i] += (arr[arr[i]] % n) * n;
for (int i = 0; i < n; i++)
arr[i] /= n;
}
void printArr(int arr[], int n)
{
for (int i = 0; i < n; i++)
System.out.print(arr[i] + " ");
System.out.println("");
}
public static void main(String[] args)
{
Rearrange rearrange = new Rearrange();
int arr[] = {6, 4, 9, 2, 5, 7};
int n = arr.length;
System.out.println("Given Array is :");
rearrange.printArr(arr, n);
rearrange.rearrange(arr, n);
System.out.println("Modified Array is :");
rearrange.printArr(arr, n);
}
}

Resources