Related
In Book allocation problem in isPossible() function why even if studentsRequired are less than m (students we need to allocate books for ) results the curr_min to be a viable sollution and we return true ? Does't it mean that books are not allocated to all the students ?
for example if the array is [5, 82, 52, 66, 16, 37, 38, 44, 1, 97, 71, 28, 37, 58, 77, 97, 94, 4, 9]
with m = 16. Maximum value studentsRequired gets is 13. does't it mean that only 13 students got the books but 16 should have ?
here is the code in JS, for other languages ( cpp, java, python ) please get to this GFG page
function isPossible(arr, n, m, curr_min) {
let studentsRequired = 1;
let curr_sum = 0;
for (let i = 0; i < n; i++) {
if (arr[i] > curr_min) return false;
if (curr_sum + arr[i] > curr_min) {
studentsRequired++;
curr_sum = arr[i];
if (studentsRequired > m) return false;
} else {
curr_sum += arr[i];
}
}
return true;
}
function findPages(arr, n, m) {
let sum = 0;
if (n < m) return -1;
for (let i = 0; i < n; i++) sum += arr[i];
let start = 0,
end = sum;
let result = Number.MAX_VALUE;
while (start <= end) {
let mid = Math.floor((start + end) / 2);
if (isPossible(arr, n, m, mid)) {
result = Math.min(result, mid);
end = mid - 1;
} else start = mid + 1;
}
return result;
}
const ans = findPages(
[5, 82, 52, 66, 16, 37, 38, 44, 1, 97, 71, 28, 37, 58, 77, 97, 94, 4, 9],
19,
16
);
console.log("Ans : ", ans);
What i think is happening =>
When i dry run the code for test case arr = [10,20,30,40] with m = 4, the result is S1 = [10,20], S2 = [30], S3 = [40] and we did not allocated a book to S4.
Are we assuming that students with more books (like S1 had [10,20]) can transfer there last book, 20 in this case to there right student ? And then S2 will have [20,30] so 30 will be then transferred to S3 and in the end S3 will tranfer its last book to S4 making the condition "Every student must have a book" true as now S1 = [10], S = [20], S3 = [30], S4 = [40]? Or its something else ?
I am trying to write the most efficient algorithm to find out which numbers exist in all lists of numbers without using third party code.
Consider this figure. Number 36 and 41 exist in all lists.
I have written a program that finds those numbers using this algorithm written in a Golang-like pseudo code:
func findAllEqualValues(lists []List) {
foreach list in lists {
label: foreach value in list.Values {
var existsInAll = false
foreach list2 in lists {
if Exists(list2.Values, value) {
existsInAll = true
} else {
existsInAll = false
continue label
}
}
if existsInAll {
printf("Value %d exists in all lists", value)
}
}
}
}
func Exists(values []Value, value Value) bool {
foreach v in values {
if v == value {
return true
}
}
return false
}
This algorithm works good. But are there any better and more efficient ways to find the numbers without using any third party code?
Maybe this can help. This is in js code.
const x = [[8,36,23,51,41], [2,19,23,36,41], [7,36,23,41,2], [41,2,47,36,51]];
findDuplicates = (arr) => {
let ans = [];
if(arr.length === 0) return ans;
ans = arr[0];
for(let i = 1; i < arr.length; i++) {
ans = arr[i].filter((a) => ans.includes(a));
}
return ans;
};
console.log(findDuplicates(x));
It's definitely possible to do this in linear time. I would iterate through one of the lists and check each number for presence in the others. The other lists would need to be hashsets for O(1) lookups.
Something like this:
numbers = [
[8, 36, 23, 51, 41],
[2, 19, 23, 36, 41],
[7, 36, 23, 41, 7],
[41, 2, 47, 36, 51]
]
lookup = [set(l) for l in numbers[1:]]
result = [x for x in numbers[0] if all(x in l for l in lookup)]
print(result) # prints [36, 41]
or as #AndrewScott suggested just intersect the sets
lookup = [set(l) for l in numbers]
result = set.intersection(*lookup)
i have tow queries
one is
List<int> Scores = new List<int>() { 97, 92, 81, 60 };
IEnumerable<int> queryHighScores =
from a in Scores
where a < 5
select a;
and the other is
int[] numbers = { 12, 43, 44, 323, 44, 45, 34 };
var query1 = from a in numbers
where a < 5
select a;
now anybody tell me what is IEnumerable and why we use this . both query return same result so why we use IEnumerable
Given N arrays with sizeof N, and they are all sorted, if it does not allow you to use extra space, how will find their common datas efficiently or with less time complexity?
For ex:
1. 10 160 200 500 500
2. 4 150 160 170 500
3. 2 160 200 202 203
4. 3 150 155 160 300
5. 3 150 155 160 301
This is an interview question, I found some questions which were similar but they didn't include the extra conditions of input being sorted or not being able to use extra memory.
I couldn't think of any solution less than O(n^2 lg n) complexity. In that case, I'd prefer to go with the simplest solution which gives me this complexity, which is:
not_found_flag = false
for each element 'v' in row-1
for each row 'i' in the remaining set
perform binary search for 'v' in 'i'
if 'v' not found in row 'i'
not_found_flag = true
break
if not not_found_flag
print element 'v' as it is one of the common element
We could improve this by comparing the min and max of each row and decide based on that whether it is possible for a number 'num' to fall between 'min_num' and 'max_num' of that row.
Binary search -> O(log n)
For searching 1 num in n-1 rows : O(nlogn)
Binary search for each number in first row : O(n2logn)
I selected first row, we can pick any row and if a no element of the row picked is found in any of the (N-1) rows then we don't really have common data.
It seems this can be done in O(n^2); i.e., just looking at each element once. Note that if an element is common to all the arrays then it must exist in any one of them. Also for purposes of illustration (and since you used the for loop above) I will assume we can keep an index for each of the arrays, but I'll talk about how to get around this later.
Let's call the arrays A_1 through A_N, and use indices starting at 1. Pseudocode:
# Initial index values set to first element of each array
for i = 1 to N:
x_i = 1
for x_1 = 1 to N:
val = A_1[x_1]
print_val = true
for i = 2 to N:
while A_i[x_i] < val:
x_i = x_i + 1
if A_i[x_i] != val:
print_val = false
if print_val:
print val
Explanation of algorithm. We use the first array (or any arbitrary array) as the reference algorithm, and iterate through all the other arrays in parallel (kind of like the merge step of a merge sort, except with N arrays.) Every value of the reference array that is common to all the arrays must be present in all the other arrays. So for each other array (since they are sorted), we increase the index x_i until the value at that index A_i[x_i] is at least the value we are looking for (we don't care about lesser values; they can't be common.) We can do this since the arrays are sorted and thus monotonically nondecreasing. If all the arrays had this value, then we print it, otherwise we increment x_1 in the reference array and keep going. We have to do this even if we don't print the value.
By the end, we've printed all the values that are common to all the arrays, while only having examined each element once.
Getting around the extra storage requirement. There are many ways to do this, but I think the easiest way would be to check the first element of each array and take the max as the reference array A_1. If they are all the same, print that value, and then store the indices x_2 ... x_N as the first element of each array itself.
Java implementation (for brevity, without the extra hack), using your example input:
public static void main(String[] args) {
int[][] a = {
{ 10, 160, 200, 500, 500, },
{ 4, 150, 160, 170, 500, },
{ 2, 160, 200, 202, 203, },
{ 3, 150, 155, 160, 300 },
{ 3, 150, 155, 160, 301 } };
int n = a.length;
int[] x = new int[n];
for( ; x[0] < n; x[0]++ ) {
int val = a[0][x[0]];
boolean print = true;
for( int i = 1; i < n; i++ ) {
while (a[i][x[i]] < val && x[i] < n-1) x[i]++;
if (a[i][x[i]] != val) print = false;
}
if (print) System.out.println(val);
}
}
Output:
160
This is a solution in python O(n^2), uses no extra space but destroys the lists:
def find_common(lists):
num_lists = len(lists)
first_list = lists[0]
for j in first_list[::-1]:
common_found = True
for i in range(1,num_lists):
curr_list = lists[i]
while curr_list[len(curr_list)-1] > j:
curr_list.pop()
if curr_list[len(curr_list)-1] != j:
common_found = False
break
if common_found:
return j
An O(n^2) (Python) version that doesn't use extra storage, but modify the original array. Allows to store the common elements without printing them:
data = [
[10, 160, 200, 500, 500],
[4, 150, 160, 170, 500],
[2, 160, 200, 202, 203],
[3, 150, 155, 160, 300],
[3, 150, 155, 160, 301],
]
for k in xrange(len(data)-1):
A, B = data[k], data[k+1]
i, j, x = 0, 0, None
while i<len(A) or j<len(B):
while i<len(A) and (j>=len(B) or A[i] < B[j]):
A[i] = x
i += 1
while j<len(B) and (i>=len(A) or B[j] < A[i]):
B[j] = x
j += 1
if i<len(A) and j<len(B):
x = A[i]
i += 1
j += 1
print data[-1]
What I'm doing is basically get every array in the data and comparing with it's next, element by element, removing those that are not common.
Here is the Java implementation
public static Integer[] commonElementsInNSortedArrays(int[][] arrays) {
int baseIndex = 0, currentIndex = 0, totalMatchFound= 0;
int[] indices = new int[arrays.length - 1];
boolean smallestArrayTraversed = false;
List<Integer> result = new ArrayList<Integer>();
while (!smallestArrayTraversed && baseIndex < arrays[0].length) {
totalMatchFound = 0;
for (int array = 1; array < arrays.length; array++) {
currentIndex = indices[array - 1];
while (currentIndex < arrays[array].length && arrays[array][currentIndex] < arrays[0][baseIndex]) {
currentIndex ++;
}
if (currentIndex < arrays[array].length) {
if (arrays[array][currentIndex] == arrays[0][baseIndex]) {
totalMatchFound++;
}
} else {
smallestArrayTraversed = true;
}
indices[array - 1] = currentIndex;
}
if (totalMatchFound == arrays.length - 1) {
result.add(arrays[0][baseIndex]);
}
baseIndex++;
}
return result.toArray(new Integer[0]);
}
Here is the Unit Tests
#Test
public void commonElementsInNSortedArrayTest() {
int arr[][] = { {1, 5, 10, 20, 40, 80},
{6, 7, 20, 80, 100},
{3, 4, 15, 20, 30, 70, 80, 120}
};
Integer result[] = ArrayUtils.commonElementsInNSortedArrays(arr);
assertThat(result, equalTo(new Integer[]{20, 80}));
arr = new int[][]{
{23, 34, 67, 89, 123, 566, 1000},
{11, 22, 23, 24,33, 37, 185, 566, 987, 1223, 1234},
{23, 43, 67, 98, 566, 678},
{1, 4, 5, 23, 34, 76, 87, 132, 566, 665},
{1, 2, 3, 23, 24, 344, 566}
};
result = ArrayUtils.commonElementsInNSortedArrays(arr);
assertThat(result, equalTo(new Integer[]{23, 566}));
}
This Swift solution makes a copy of the original but could be modified to take an inout parameter so that it takes no additional space. I left it as a copy because I think it is better to not modify the original since it deletes elements. It is possible to not remove elements by keeping indices, but this algorithm removes elements to keep track of where it is. This is a functional approach, and may not be super efficient but works. Since it is functional less conditional logic is necessary. I posted it because I thought it might be a different approach which might be interesting to others, and maybe others can figure out ways of making it more efficient.
func findCommonInSortedArrays(arr: [[Int]]) -> [Int] {
var copy = arr
var result: [Int] = []
while (true) {
// get first elements
let m = copy.indices.compactMap { copy[$0].first }
// find max value of those elements.
let mm = m.reduce (0) { max($0, $1) }
// find the value in other arrays or nil
let ii = copy.indices.map { copy[$0].firstIndex { $0 == mm } }
// if nil present in of one of the arrays found, return result
if (ii.map { $0 }).count != (ii.compactMap { $0 }.count) { return result }
// remove elements that don't match target value.
copy.indices.map { copy[$0].removeFirst( ii[$0] ?? 0 ) }
// add to list of matching values.
result += [mm]
// remove the matched element from all arrays
copy.indices.forEach { copy[$0].removeFirst() }
}
}
findCommonInSortedArrays(arr: [[9, 10, 12, 13, 14, 29],
[3, 5, 9, 10, 13, 14],
[3, 9, 10, 14]]
)
findCommonInSortedArrays(arr: [[],
[],
[]]
)
findCommonInSortedArrays(arr: [[9, 10, 12, 13, 14, 29],
[3, 5, 9, 10, 13, 14],
[3, 9, 10, 14],
[9, 10, 29]]
)
findCommonInSortedArrays(arr: [[9, 10, 12, 13, 14, 29],
[3, 5, 9, 10, 13, 14],
[3, 9, 10, 14],
[9, 10, 29]]
)
I have a two dimensional array of integers. I would like to write an optimized and fast code to sum all the columns of the two dimensional array.
Any thoughts how I might be able to do this using LINQ/PLINQ/TASK parallelization ?
Ex:
private int[,] m_indexes = new int[6,4] { {367, 40, 74, 15},
{535, 226, 74, 15},
{368, 313, 74, 15},
{197, 316, 74, 15},
{27, 226, 74, 15},
{194, 41, 74, 15} };
The simplest parallel implementation:
int[,] m_indexes = new int[6, 4] { {367, 40, 74, 15},
{535, 226, 74, 15},
{368, 313, 74, 15},
{197, 316, 74, 15},
{27, 226, 74, 15},
{194, 41, 74, 15} };
var columns = Enumerable.Range(0, 4);
int[] sums = new int[4];
Parallel.ForEach(columns, column => {
int sum = 0;
for (int i = 0; i < 6; i++) {
sum += m_indexes[i, column];
}
sums[column] = sum;
});
This code can obviously be "generalized" (use m_indexes.GetLength(0) and m_indexes.GetLength(1)).
LINQ:
var sums = columns.Select(
column => {
int sum = 0;
for (int i = 0; i < 6; i++) {
sum += m_indexes[i, column];
} return sum;
}
).ToArray();
Be sure to profile on real-world data here if you truly need to optimize for performance here.
Also, if you truly care about optimizing for performance, try to load up your array so that you summing across rows. You'll get better locality for cache performance that way.
Or maybe without for's :
List<List<int>> m_indexes = new List<List<int>>() { new List<int>(){367, 40, 74, 15},
new List<int>(){535, 226, 74, 15},
new List<int>(){368, 313, 74, 15},
new List<int>(){197, 316, 74, 15},
new List<int>(){27, 226, 74, 15},
new List<int>(){194, 41, 74, 15} };
var res = m_indexes.Select(x => x.Sum()).Sum();
Straightforward LINQ way:
var columnSums = m_indexes.OfType<int>().Select((x,i) => new { x, col = i % m_indexes.GetLength(1) } )
.GroupBy(x => x.col)
.Select(x => new { Column = x.Key, Sum = x.Sum(g => g.x) });
It might not be worth it to parallelize. If you need to access the array by index, you spend some cycles on bounds checking, so, as always with performance, do measure it.