Related
I am learning to code in Khan academy. It uses processing as its base language. I learnt that Java doesn't have goto function with it. Then how to implement goto function using processing. Explanatio with snippet is appreciated.
Here's my code and I have comment the places where I want to use the goto functionality:
/* Returns either the index of the location in the array,
or -1 if the array did not contain the targetValue */
var doSearch = function(array, targetValue) {
var min = 0;
var max = array.length - 1;
var guess;
//startover:
if (guess === max || guess === min) {
//goto notFound;
}
guess = round((min + max) / 2);
if (targetValue === array[guess]) {
return guess;
} else {
if (targetValue > array[guess]) {
min = guess + 1;
//goto startover;
} else {
max = guess - 1;
//goto startover;
}
}
}
//notFound:
return -1;
};
var primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37,
41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
];
var result = doSearch(primes, 73);
println("Found prime at index " + result);
//Program.assertEqual(doSearch(primes, 73), 20);
The best you could probably do is to use a for loop and use break or continue for gotos.
for(var unusedVariable = 0;1==1;unusedVariable++){//equivalent of "startover:"
if(condition1){
continue;//goto startover;
}
if(condition2){
continue;//goto startover;
}
if(condition1){
break;//goto notFound;
}
}//notFound:
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]]
)
If I have a number x which can change, say its now 25... how do I do the below in a simpler way?
colQty.DataSource = new List<Int16> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };
Something like
var range = Enumerable.Range(start: 1, count: x).ToList();
And you could use ToList<Int16>() but I wouldn't.
Use this:
var numbers = Enumerable.Range(1, 25);
This will create an IEnumerable<int> with the numbers 1 to 25. If you need a List<int> instead, add .ToList() after Range:
var numbers = Enumerable.Range(1, 25).ToList();
var list = new List<int>();
for(var i = 1; i <= x; i++){ list.Add(i);}
colQty.DataSource = list;
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.
I've been struggling with level 3 of the Greplin challenge. For those not familiar, here is the problem:
you must find all subsets of an array where the largest number is the sum of the remaining numbers. For example, for an input of:
(1, 2, 3, 4, 6)
the subsets would be
1 + 2 = 3
1 + 3 = 4
2 + 4 = 6
1 + 2 + 3 = 6
Here is the list of numbers you should
run your code on. The password is the
number of subsets. In the above case
the answer would be 4.
3, 4, 9, 14, 15, 19, 28, 37, 47, 50, 54, 56, 59, 61, 70, 73, 78, 81, 92, 95, 97, 99
I was able to code a solution that builds all 4 million plus combinations of the 22 numbers and then tests them all which will get me the right answer. Problem is it takes over 40 minutes to crunch through. Searching around the web it seems like several people were able to write an algorithm to get the answer to this in less than a second. Can anyone explain in pseudo-code a better way to tackle this than the computationally expensive brute-force method? It's driving me nuts!
The trick is that you only need to keep track of counts of how many ways there are to do things. Since the numbers are sorted and positive, this is pretty easy. Here is an efficient solution. (It takes under 0.03s on my laptop.)
#! /usr/bin/python
numbers = [
3, 4, 9, 14, 15, 19, 28, 37, 47, 50, 54, 56,
59, 61, 70, 73, 78, 81, 92, 95, 97, 99]
max_number = max(numbers)
counts = {0: 1}
answer = 0
for number in numbers:
if number in counts:
answer += counts[number]
prev = [(s,c) for (s, c) in counts.iteritems()]
for (s, c) in prev:
val = s+number;
if max_number < val:
continue
if val not in counts:
counts[val] = c
else:
counts[val] += c
print answer
We know the values are nonzero and grow monontonically left to right.
An idea is to enumerate the the possible sums (any order, left to right is fine)
and then enumerate the subsets to the left of of that value,
because values on the right can't possibly participate (they'd make the sum
too big). We don't have have to instantiate the set; just as we consider
each value, see how if affects the sum. It can either be too big (just ignore
that value, can't be in the set), just right (its the last member in the set),
or too small, at which point it might or might not be in the set.
[This problem made me play with Python for the first time. Fun.]
Here's the Python code; according to Cprofile.run this takes .00772 seconds
on my P8700 2.54Ghz laptop.
values = [3, 4, 9, 14, 15, 19, 28, 37, 47, 50, 54, 56, 59, 61, 70, 73, 78, 81, 92, 95, 97, 99]
def count():
# sort(values) # force strictly increasing order
last_value=-1
duplicates=0
totalsets=0
for sum_value in values: # enumerate sum values
if last_value==sum_value: duplicates+=1
last_value=sum_value
totalsets+=ways_to_sum(sum_value,0) # faster, uses monotonicity of values
return totalsets-len(values)+duplicates
def ways_to_sum(sum,member_index):
value=values[member_index]
if sum<value:
return 0
if sum>value:
return ways_to_sum(sum-value,member_index+1)+ways_to_sum(sum,member_index+1)
return 1
The resulting count I get is 179. (Matches another poster's result.)
EDIT: ways_to_sum can be partly implemented using a tail-recursion loop:
def ways_to_sum(sum,member_index):
c=0
while True:
value=values[member_index]
if sum<value: return c
if sum==value: return c+1
member_index+=1
c+=ways_to_sum(sum-value,member_index)
This takes .005804 seconds to run :-} Same answer.
This runs in less than 5ms (python). It uses a variant of dynamical programming called memoized recursion. The go function computed the number of subsets of the first p+1 elements, which sum up to target. Because the list is sorted it's enough to call the function once for every element (as target) and sum the results:
startTime = datetime.now()
li = [3, 4, 9, 14, 15, 19, 28, 37, 47, 50, 54, 56, 59, 61, 70, 73, 78, 81, 92, 95, 97, 99]
memo = {}
def go(p, target):
if (p, target) not in memo:
if p == 0:
if target == li[0]:
memo[(p,target)] = 1
else:
memo[(p,target)] = 0
else:
c = 0
if li[p] == target: c = 1
elif li[p] < target: c = go(p-1,target-li[p])
c += go(p-1, target)
memo[(p,target)] = c
return memo[(p,target)]
ans = 0
for p in range(1, len(li)):
ans += go(p-1, li[p])
print(ans)
print(datetime.now()-startTime)
This works
public class A {
static int[] a = {3,4,9,14,15,19,28,37,47,50,54,56,59,61,70,73,78,81,92,95,97,99};
public static void main(String[] args) {
List<Integer> b = new ArrayList<Integer>();
int count = 0;
for (int i = 0; i < a.length; i++) {
System.out.println(b);
for (Integer t:b) {
if(a[i]==t)
{
System.out.println(a[i]);
count++;
}
}
int size = b.size();
for (int j = 0; j < size; j++) {
if(b.get(j) + a[i] <=99)
b.add(b.get(j) + a[i]);
}
b.add(a[i]);
}
System.out.println(count);
}
}
pseudo code(with explanation):
store the following variables
i.) 'count' of subsets till now
ii.)an array b which contains sums of all possible subsets
2.iterate through the array (say a). for each element a[i]
i.)go through array b and count the number of occurrences of a[i]. add this to 'count'
ii.)go through array b and for each element b[j].add (a[i]+b[j]) to b because this is a possible subset sum. (if a[i]+b[j]> max element in a, u can ignore to add it)
iii.)add a[i] to b.
3.u have count :)
I used the combination generator class in Java available here:
http://www.merriampark.com/comb.htm
Iterating through the combos and looking for valid subsets took less than a second. (I don't think using outside code is in keeping with the challenge, but I also didn't apply.)
public class Solution {
public static void main(String arg[]) {
int[] array = { 3, 4, 9, 14, 15, 19, 28, 37, 47, 50, 54, 56, 59, 61,
70, 73, 78, 81, 92, 95, 97, 99 };
int N = array.length;
System.out.println(N);
int count = 0;
for (int i = 1; i < 1 << N; i++) {
int sum = 0;
int max = 0;
for (int j = 0; j < N; j++) {
if (((i >> j) & 1) == 1) {
sum += array[j];
max = array[j];
}
}
if (sum == 2 * max)
count++;
}
System.out.println(count);
}
public static boolean isP(int N) {
for (int i = 3; i <= (int) Math.sqrt(1.0 * N); i++) {
if (N % i == 0) {
System.out.println(i);
// return false;
}
}
return true;
}
}
Hope it helps, but don't just copy and paste.
I don't want to beat a dead horse, but most of the solutions posted here miss a key opportunity for optimization and therefore take 6 times longer to execute.
Rather than iterating through the input array and searching for sums that match each value, it is far more efficient to calculate all the possible RELEVANT sums only once, then see which of those sums appear in the original input array. (A "relevant" sum is any subset sum <= the max value in the array.)
The second approach runs approximately 6 times faster -- generally milliseconds rather than centiseconds -- simply because it calls the recursive sum-finding function about 1/6th as many times!
The code for this approach and full explanation can be found in this github repo (it's in PHP because that's what was called for by the person who gave me this challenge):
https://github.com/misterrobinson/greplinsubsets