Solving Codility Algorithm - java

I tried the sample demo at Codility website, and posted my solution but I've a simple mistake but couldn't determine it.
The problem is described here (The problem is only described please don't care about the analysis there as that wasn't not my solution)
http://codility.com/cert/view/certHNPV9B-7M4GAQR985B54VYF/details
my solution is here:
public static int min_router_peripherality ( int[] T ) {
// write your code here
int sum=0;
for(int i=0;i<T.length;i++) sum+= T[i];
int min = sum;
int index = 0;
int array [] = new int [T.length];
for(int i=0;i<T.length;i++) {
min = sum -T[i];
array[i] = min;
}
int x = array[0];
for (int i=0; i<array.length;i++)
{
if (array[i]<x)
{
x = array[i];
index = i;
}
}
return index;
}

What I see as mistakes are the following:
for(int i=0;i<T.length;i++)
sum+= T[i];
Here you treat T[i] like some weight. But Node-Ids are no weights. Summing up node ids is useless.
Then: The text says: "if T[P] = Q and P ≠ Q, ...". I don't see anything which takes this into account.
Then: Not understanding the algorithm I tried a simple "line" like this:
int[] T = {1, 2, 3, 4, 5, 6, 7, 8, 9, 9};
The result is 8. But in a line the result should be somewhere in the middle.
Therefore I doubt that the linked page shows the results of the code you have posted.

When looking at the results I would say that your program is correct, but too slow to successfully complete all test cases. So you need to come up with better algorithm.
EDIT: As Ivan Benko Ivan Benko noted, your solution is O(N), so i looked at your code and I came up with a following input:
{ 4, 9, 4, 9, 4, 4, 8, 9, 0, 0 }
Although it is not the example input, it does describe the same network as in the task description. So the output should be same, but your solution gives a different answer.

All I did was look at your code, and the first thing I noticed is that it doesn't look like you need that array array at all, or that third for loop. The second for loop can just keep track of the lowest min value it generates as it goes, along with the index associated with that lowest min value, rather than storing all the values and making a second run like you're doing now.
Edit:
Like everyone else, I assumed that your link was to your own results. I'm not going to post an answer, because I think you're supposed to come up with that yourself. However, it looks to me like you got confused where they said "find the sum of distances to all other nodes", and that might be why you're starting off summing up the entire array. The array they're passing into your function isn't a set of distances by any means. It's a list of existing connections. If the first element (the one at the 0 index) in the array is a 5, then that means Router 0 has a connection to Router 5. So it looks to me like you're approaching it all wrong.

Two adjacent node has a one edge and its weight is 1.

Related

Count the number of integers in an array divisible by a given query k

In this problem I have a number of queries for which I have to output the count of integers in the array which is divisible by k(one of the queries).The array contains duplicate elements. I am trying to optimise the problem and my approach is given below :
Code:
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int[] ar={2,4,6,9,11,34,654,23,32,54,76,21432,32543,435,43543,643,2646,4567,457654,75,754,7,567865,8765877,53,2};
int query=sc.nextInt();
int length=ar.length;
int count=0;
for (int i=0;i<query ;i++ ) {
int x=sc.nextInt();
for (int j=0;j<length ;j++ ) {
if(ar[j]>x){
if(ar[j]%x==0){
count++;
}
}
}
System.out.println("Count:"+count);
}
}
The above code gives the correct output, but the complexity is O(query*length) and what if the array size is much bigger,the program will timeout.
Can anyone help me optimize the problem?
One optimization that you could do is to take advantage of short-circuiting, and use one if statement (instead of two).
So change this:
if(ar[j]>x) {
if(ar[j]%x==0) {
to this:
if(ar[j]>x && ar[j]%x==0) {
This will not affect the time complexity of your algorithm, but it will help Branch Prediction.
and maximum value of an element in an array is 10^5
This makes it trivial. Use boolean[10001] and mark all multiples of all queries. Then use it for testing the elements.
The new problem is how to mark all the multiples when there are many small queries. The worst case would be queries like {1, 1, 1, ...}, but duplicates can be trivial removed e.g., using a HashSet. Now the worst case is {1, 2, 3, 4, ...}, which needs 10001/1 + 10001/2 + 10001/3... steps. You can do some special treatment for the smallest queries like removing multiples.
For example, when you look at all queries up to 10 and remove multiples among them, then the worst case is {2, 3, 5, 7, 11, 12, 13, 14...}, which should make the marking pretty fast. This step may not be needed at all.
You can do a precomputation step to build a divisors' table. For every element in the array calculate its divisors. You can calculate divisors of a number efficiently in O(sqrt(V)) assuming V is the maximum value in the array. Building the full table will cost O(n * sqrt(V)) which according to your constraints equals 100,000 * sqrt(100,000) =~ 32M which shouldn't be a lot. Memory complexity would be the same.
Then you can answer your queries in O(1) by a lookup in the table.
You can check this link for how to generate divisors in O(sqrt(V)).

Is there any way to shorten a for-each loop in java?

I want to iterate just the half of an array in java. Is there any elegant way to shorten this up, eg with a for-each loop?
int[] array = {0,1,2,3,4,5};
for (int i = 0; i<array.length/2; i++)
{
System.out.println(array[i]);
}
If you converted the array into a list using the asList method of the Arrays class in Java, then you can use the forEach method in the List class in Java to print out each element of the list in one single line,
Arrays.asList(array).forEach(System.out::println);
To print only half the array, I'd suggest copying half the array into a new array using the copyOfRange method,
Integer[] newArray = Arrays.copyOfRange(array, 0, array.length/2);
Arrays.asList(newArray).forEach(System.out::println);
EDIT: Like Marko Topolnik pointed out, we're actually starting out with an array of primitive types instead of object types, so in order to use the asList method we're going to have to convert the array into an array of objects (from int to Integer using Integer[] integerArray = ArrayUtils.toObject(array);). However this just seems tedious/inefficient and OP asked for a shorter way so my suggestion would be to use Marko's method,
Arrays.stream(array).limit(array.length/2).forEach(System.ou‌​t::println);
EDIT 2: Like Amber Beriwal pointed out, it should be noted that although the one-line solution above looks pretty due to its conciseness, it is still very inefficient/slow compared to the OP's original method. Therefore, I would like to reiterate Amber's comments that the OP and others should just stick with the original for-loop.
for (int i = 0; i < array.length/2; i++)
{
System.out.println(array[i]);
}
How about:
IntStream.range(0, array.length / 2).map(i -> array[i]).forEach(System.out::println);
One line, and no array copies.
Broken down:
IntStream.range(0, array.length / 2) //get the range of numbers 0 - (array length)/2
.map(i -> array[i]) //map from index to value
.forEach(System.out::println); //print result
The answer you have posted is good. Although, I couldn't find a better way to make it compact keeping the performance same, but performance can be improved. Remember following practices while coding:
Algorithm's memory requirement should be optimum
Algorithm's time i.e. performance should be optimum
Algorithm's complexity should not be too much. For significant gains in 1 & 2, this can be skipped.
Considering 1 & 2, lines of code comes at least priority.
Solution 1: This solution will be 4-5 times slower than your approach, plus Stream will take extra space.
Arrays.stream(array).limit(array.length/2).forEach(System.ou‌​t::println);
Solution 2: This solution is faster than the above code and your code (based on my testing), but Stream will take extra space. Also, it is not compact.
Arrays.stream(array).limit(array.length / 2).forEach(new IntConsumer() {
#Override
public void accept(int value) {
System.out.println(value);
}
});
Solution 3: As suggested by you.
int[] array = new int[] { 0, 1, 2, 3, 4, 5 };
int limit = array.length / 2;
for (int i = 0; i < limit; i++) {
System.out.println(array[i]);
}
Recommendation: Don't go over to reduce the LOC at the stake of losing performance and memory. It is better to keep up with the solution that gives you best performance..

algorithm to get subset of array with target sum is not giving working

The problem is given an unsorted array, give subsets of array that can produce target sum:
For eg:
target = 15
data = {3,4,5,7,1,2,9};
Expected results (note the results are sorted for simplicity. not a requirement) :
[1, 2, 3, 4, 5]
[1, 2, 3, 9]
[1, 2, 5, 7]
[1, 3, 4, 7]
[1, 5, 9]
[2, 4, 9]
[3, 5, 7]
Here is my naive approach to this problem - simple and brute force.
public static void naiveSubset(int[] arr, int target){
int sum=0;
List<Integer> result = new ArrayList<>();
for (int i=0; i< arr.length;i++){
sum =arr[i];
result.add(arr[i]);
for (int j=0;j<arr.length;i++){
if (sum==target){
System.out.println(result);
result.clear();
break;
}
else if (i!=j && sum+arr[j] <= target){
sum+=arr[j];
result.add(arr[j]);
}
}
}
}
For some reasons, I am not expecting the results. I tried browsing through the code to dig out any issues. But I could not find any. please algo experts, point me in correct direction!!
The results I get (for same input as above)
[3, 3, 3, 3, 3]
[9, 3, 3]
Your solution is wrong because it's a greedy approach. It decides if you should add a number or not based on the fact that adding it does not violate the sum, at the moment.
However, this greedy approach does not work, with a simple example of the following array: [1,9,6,5] and with sum=11.
Note that for any element you choose in the outer loop, next you will add 1 to the current set. But that will deny you the possibility to get the sum of 5+6.
Once you choose 5, you start adding number, starting with '1', and adding it. Once it is added - you will never get the correct solution.
Also note: Your double loop approach can generate at most O(n^2) different subsets, but there could be exponential number of subsets - so something must be wrong.
If you want to get all possible subsets that sum to the given sum, you can use a recursive solution.
At each step "guess" if the current element is in the set or not, and recurse for both options for the smaller problem - if the data is in the set, or if it's not.
Here is a simple java code that does it:
public static void getAllSubsets(int[] elements, int sum) {
getAllSubsets(elements, 0, sum, new Stack<Integer>());
}
private static void getAllSubsets(int[] elements, int i, int sum, Stack<Integer> currentSol) {
//stop clauses:
if (sum == 0 && i == elements.length) System.out.println(currentSol);
//if elements must be positive, you can trim search here if sum became negative
if (i == elements.length) return;
//"guess" the current element in the list:
currentSol.add(elements[i]);
getAllSubsets(elements, i+1, sum-elements[i], currentSol);
//"guess" the current element is not in the list:
currentSol.pop();
getAllSubsets(elements, i+1, sum, currentSol);
}
Note that if you are looking for all subsets, there could be exponential number of those - so an inefficient and exponential time solution is expected.
If you are looking for finding if such a set exist, or finding only one such set, this can be done much more efficiently using Dynamic Programming. This thread explains the logic of how it can be done.
Note that the problem is still NP-Hard, and the "efficient" solution is actually only pseudo-polynomial.
I think the major issue in your previous approach is that simply doing loops based upon the input array will not cover all the combinations of numbers matching the target value. For example, if your major loop is in ith, and after you iterate through the jth element in your secondary loop, your future combination based on what you have collected through ith element will never include jth one anymore. Intuitively speaking, this algorithm will collect all the visible combinations through numbers near each other, but not far away from each other.
I wrote a iterative approach to cope with this subset sum problem through C++ (sorry, not have a java environment at hand:P), the idea is basically the same as the recurrsive approach, which means you would record all the existing number combinations during each iteration in your loop. I have one vector<vector> intermediate used to record all the encountered combination whose value is smaller than target, and vector<vector> final used to record all the combinations whose sum is equal to target.
The detailed explanation is recorded inline:
/* sum the vector elements */
int sum_vec(vector<int> tmp){
int sum = 0;
for(int i = 0; i < tmp.size(); i++)
sum += tmp[i];
return sum;
}
static void naiveSubset(vector<int> arr, int target){
/* sort the array from big to small, easier for us to
* discard combinations bigger than target */
sort(arr.begin(), arr.end(), greater<int>());
int sum=0;
vector<vector<int> > intermediate;
vector<vector<int> > final;
for (int i=0; i< arr.size();i++){
int curr_intermediate_size = intermediate.size();
for(int j = 0; j < curr_intermediate_size; j++){
int tmpsum = sum_vec(intermediate[j]);
/* For each selected array element, loop through all
* the combinations at hand which are smaller than target,
* dup the combination, put it into either intermediate or
* final based on the sum */
vector<int> new_comb(intermediate[j]);
if(tmpsum + arr[i] <= target){
new_comb.push_back(arr[i]);
if(tmpsum + arr[i] == target)
final.push_back(new_comb);
else
intermediate.push_back(new_comb);
}
}
/* finally make the new selected element a separate entry
* and based on its value, to insert it into either intermediate
* or final */
if(arr[i] <= target){
vector<int> tmp;
tmp.push_back(arr[i]);
if(arr[i] == target)
final.push_back(tmp);
else
intermediate.push_back(tmp);
}
}
/* we could print the final here */
}
Just wrote it so please bear with me if there is any corner case that I did not consider well. Hope this helps:)

Check whether list of number is sequential or not

I have quite a layman question about Java programming.
I would like to write a function to check whether a list of number is sequential or not.
Say [1, 2, 3, 4, 5], the function will return true,
but for [1, 3, 4, 9, 10], the function will return false.
Could anyone help me?
Thank so much!
Write a loop that looks at each element of the list.
For each position i in the list, test that listi + 1 equals listi + 1.
You can code it yourself as an exercise. (Don't forget to deal with the edge cases ...)
UPDATE: ... for people treating this problem as a learning exercise.
A simple direct implementation approach is probably the best idea; e.g. #Joe's final answer. However, the simple approach doesn't always work well ... or at all:
Some Java List implementations have a get method that is O(N). That would lead to an O(N^2) algorithm overall.
Sometimes a a list can only be accessed using an iterator; i.e. list.get(i) might not be an option.
In such cases, you could implement the algorithm with one pass through the list using an iterator. You need to keep "the previous element" in variable, etcetera.
Logic is simple. Just get the first number and check whether it matches with the next value. Like that check adjacent values. Break if the condition fails at any point. The list will be sequential if all the if condition is true.
As Stephen C said, it is a very simple logic
int a[] = { 1, 2, 3, 4, 5,7 };
boolean flag = true;
for (int i = 0; i < a.length - 1; i++) {
if (a[i + 1] != a[i] + 1) {
flag = false;
break;
}
}
System.out.println("Flag is " + flag);

Whats the most efficient way of doing this?

I've got an array array of size N. For every 3 indexes in it I want to take them out and declare and assign those values to another array of size 3. I then want to go back to that array and take the next 3 and put it in a different array of size 3. I'll iterate like this for 3 different arrays of size 3 a1,a2,a3 once this is done I want to empty a1,a2,a3 and re add the NEXT 3 values to the 3 arrays of size 3 repeating this on till we reach array.length
What would be the best / most efficient way of doing this?
As a general strategy I would not worry about efficiency at first.
Code it as explicitly as possible, and then write a load of unit tests confirming it works. The iteratively improve performance.
Its easier to make correct code fast than it is to make fast code correct.
for (int i=0; i<=N-9; i+=9) {
System.arrayCopy(arrayN, i, a1, 0, 3);
System.arrayCopy(arrayN, i+3, a2, 0, 3);
System.arrayCopy(arrayN, i+6, a3, 0, 3);
// presumably do other stuff here
}
That's a pretty brittle but fast way of doing it. Each time the previous values are overwritten, so no need to clear. If you do need to have arrayN clear, you can just Arrays.fill(arrayN, null) after the loop.
EDIT: For the less brittle answer, I'm going to assume you'd be inflating m x n arrays. Instead of hard coding a1, a2, ... am, make a 2D array a[m][n].
for (i=0; i<=N-m*n; i+=m*n) {
for (int j=0; j<m; j++) System.arrayCopy(arrayN, i+n*j, a[j], 0, n);
// presumably do other stuff here
}
and, as Adrian suggests in the comments, declare i outside the loop and use its value relative to N to deal with leftovers as appropriate.
Its very easy, you can do it in the following way....
It is code snippet below....
byte[] YourBigArray = new byte[SomeValue];
int temp = 0;
while(temp < YourBigArray.size - 1 )
{
System.arrayCopy(YourBigArray, temp, smallarray, 0, 3);
temp+=3;
}
Try this code and also see the documentation of arrayCopy function....
Enjoy.....
for(int i = 0; i < ##; i++){if(i%3==0){startNewArray}}

Categories