Find the maximum consecutive elements matching the given condition.
I have a list of numbers called A, another list called B and a limit called Limit.
The task is find the maximum k consecutive elements in A such that they satisfy below condition.
Max(B[i],B[i+1],...B[i+k]) + Sum(A[i], A[i+1], ..., A[i+k]) * k ≤ Limit
Example:
A = [2,1,3,4,5]
B = [3,6,1,3,4]
Limit = 25
Take 2 consecutive elements:
Highest sum occurs with elements in A = 4,5. The corresponding max in B is Max(3,4) = 4.
So value = 4 + (4+5) * 2 = 22. Here 22 ≤ 25, so 2 consecutive is possible
Take 3 consecutive elements:
Taking sum for 1st 3 elements of A = 2,1,3. The corresponding max in B is Max(3,6,1) = 6.
So value = 6 + (2+1+3) * 3 = 24. Here 24 ≤ 25, so 3 consecutive is possible
Take 4 consecutive elements:
Taking sum for 1st 4 elements of A = 2,1,3,4. The corresponding max in B is Max(3,6,1,3) = 6.
So value = 6 + (2+1+3+4) * 4 = 46. Here 46 > 25, so 4 consecutive is not possible
So correct answer to this input is 3.
Constraints:
n (Size of A) is up to 10⁵, A elements up to 10¹⁴, B elements up to 10⁹, Limit up to 10¹⁴.
Here is my code:
public int getMax(List<Integer> A, List<Integer> B, long limit) {
int result = 0;
int n = A.size();
for(int len=1; len<=n; len++) {
for(int i=0; i<=n-len; i++) {
int j=i+len-1;
int max = B.get(i);
long total = 0;
for(int k=i; k<=j; k++) {
total += A.get(k);
max = Math.max(max, B.get(k));
}
total = max + total * len;
if(total < limit) {
result = len;
break;
}
}
}
return result;
}
This code works for smaller range of inputs.
But fails with a time out for larger inputs. How can I reduce time complexity of this code?
Updated:
Updated code based on dratenik answer, but the sample test case mentioned in my post itself is failing. The program is returning 4 instead of 3.
public int getMax(List<Integer> A, List<Integer> B, long limit) {
int from = 0, to = 0, max = -1;
int n = A.size();
for (; from < n;) {
int total = 0;
int m = B.get(from); // updated here
for (int i = from; i < to; i++) {
total += A.get(i); // updated here
m = Math.max(m, B.get(i)); // updated here
}
total = m + total * (to - from); // updated here
if (total <= limit && to - from + 1 > max) {
max = to - from + 1;
}
if (total < limit && to < n) { // below target, extend window
to++;
} else { // otherwise contract window
from++;
}
if (from > to) {
to = from;
}
}
return max;
}
Since all the elements of A and B are positive, you can solve this with the usual two-pointer approach to finding a maximum length subarray:
Initialize two pointers s and e to the start of the arrays, and then advance e as far as possible without violating the limit. This finds the longest valid subarray that starts at s.
While e isn't at the end of the arrays, advance s by one position, and then again advance e as far as possible without violating the limit. This finds the longest valid subarray that starts at every position. This leads to an O(n) algorithm, because e can advance monotonically.
Your answer is the longest valid sequence you see.
In order to determine in O(1) whether or not a particular range from s to e is valid, you need to track the cumulative sum of A elements and the current maximum of B elements.
The sum is easy -- just add elements that e passes and subtract elements that s passes.
To track the current maximum of elements in B, you can use the standard sliding-window-maximum algorithm described here: Sliding window maximum in O(n) time. It works just fine with expanding and contracting windows, maintaining O(1) amortized cost per operation.
Here's an O(n) solution in Java. Note that I multiplied the sum of A elements by the length of the sequence, because it's what you seem to intend, even though the formula you wrote multiplies by length-1:
public static int getMax(List<Integer> A, List<Integer> B, long limit) {
final int size = A.size();
// a Queue containing indexes of elements that may become max in the window
// they must be monotonically decreasing
final int maxQ[] = new int[size];
int maxQstart = 0, maxQend = 0;
// current valid window start and end
int s=0, e = 0;
int bestLen = 0;
long windowSum = 0;
while (s < size && e < size) {
// calculate longer window max
long nextMax = maxQstart < maxQend ? B.get(maxQ[maxQstart]) : 0;
nextMax = Math.max(nextMax, B.get(e));
long sumPart = (windowSum + A.get(e)) * (e+1-s);
if (nextMax + sumPart <= limit) {
// extending the window is valid
int lastB = B.get(e);
while (maxQstart < maxQend && B.get(maxQ[maxQend-1]) <= lastB) {
--maxQend;
}
maxQ[maxQend++] = e;
windowSum += A.get(e);
++e;
if (e-s > bestLen) {
bestLen = e-s;
}
} else if (e > s) {
// extending the window is invalid.
// move up the start instead
windowSum -= A.get(s);
++s;
while(maxQstart < maxQend && maxQ[maxQstart] < s) {
++maxQstart;
}
} else {
// we need to move the start up, but the window is empty, so move them both
++s;
++e;
}
}
return bestLen;
}
Sliding window approach? Slightly pseudocodey version:
int from=0, to=0, max = -1;
for(;from<n;) {
total = (target expression on elements between from-to inclusive)
if (total<=target && to-from+1 > max) {max = to-from+1;}
if (total<target && to<n) { // below target, extend window
to++;
} else { // otherwise contract window
from++;
}
if (from>to) {to=from;}
}
return max;
The sum could be updated incrementally, but I don't know how to sensibly update the max(B[i],B[i+1],...B[i+k]) part when contracting the window, so let's recompute the whole thing at each step.
I tried to use meanigful names to make the code readable. Don't hesitate to ask where it is not clear:
public int getMax(List<Integer> a, List<Integer> b, long limit) {
int max = -1;
int numberOfElements = 2;
boolean found;
do{
found = false;
for ( int index = 0; index <= a.size() - numberOfElements; index++) {
int totalA = 0;
int maxB = b.get(index);
for (int i = index; i < index + numberOfElements; i++) {
totalA += a.get(i);
maxB = Math.max(maxB,b.get(i)); // updated here
}
int total = maxB + totalA * numberOfElements;
if (total <= limit && numberOfElements >= max) {
max = numberOfElements;
found = true;
break;
}
}
numberOfElements++;
} while(found && numberOfElements <= a.size());
return max;
}
(more test cases can be helpful for further debugging)
I think the main obstacle there is how to efficiently track maximum over sliding window.
Easy optimization in this respect without diving into dynamic programming is to make use of MaxHeap.
In java it is implemented as PriorityQueue.
Please consider following code.
private int findMaxRange(List<Long> listA, List<Long> listB, long limit) {
int maxRange = 0;
while (maxRange < listA.size() && isRangePossible(listA, listB, limit, maxRange+1)) {
maxRange++;
}
return maxRange;
}
private boolean isRangePossible(List<Long> listA, List<Long> listB, long limit, int rangeSize) {
//calculate initial values of max and sum
PriorityQueue<Long> maxHeap = new PriorityQueue<>(rangeSize, Comparator.reverseOrder());
listB.stream().limit(rangeSize).forEach(maxHeap::add);
Long max = maxHeap.peek();
Long sum = listA.stream().limit(rangeSize).mapToLong(i->i).sum();
//iterate with sliding window
for (int i = 0; i < listA.size() - rangeSize; i++) {
if (isConditionMet(max, sum, rangeSize, limit)) {
return true;
}
sum = sum + listA.get(i+rangeSize) - listA.get(i);
maxHeap.remove(listB.get(i));
maxHeap.add(listB.get(i+rangeSize));
max = maxHeap.peek();
}
return isConditionMet(max, sum, rangeSize, limit);
}
private boolean isConditionMet(Long max, Long sum, int rangeSize, long limit) {
return max + sum * rangeSize < limit;
}
Also please pay attention to value ranges. Such big values can easily overflow long and may require specialized types like BigInteger. You should also consider how much memory is used by auxiliary datatypes.
The problem here seems to be use of three nested for loops for calculating max and sum for every window.
We can avoid this unnecessary iterations by using calculations of previous iteration in the new iteration with the help of Dynamic programming.
In my solution, I made 2 2d Arrays, one to store max values for each windows and other to store sums for each windows, storing values of previous iterations will greatly reduce the time complexity.
here is the Java code:
import java.util.*;
public class MyClass {
public static void main(String[] args) {
System.out.println("Hello, World!");
List A = Arrays.asList(2,1,3,4,5);
List B = Arrays.asList(3,6,1,3,4);
System.out.println(MyClass.getMax(A, B, 25L));
}
public static int getMax(List<Integer> A, List<Integer> B, long limit) {
int n = A.size();
int[][] dp1 = new int[n + 1][n + 1];
int[][] dp2 = new int[n + 1][n + 1];
for(int i = 1; i <= n; i++) {
for(int j = i; j <= n; j++) {
dp1[i][j] = Math.max(dp1[i - 1][j- 1], B.get(j - 1));
dp2[i][j] = dp2[i - 1][j- 1] + A.get(j - 1);
}
}
for(int i = 0; i <= n; i++) {
for(int j = 0; j <= n; j++) {
System.out.print("{" + dp1[i][j] + ", " + dp2[i][j] + "}, ");
}
System.out.println();
}
int kMax = 0;
for(int i = 0; i <= n; i++) {
for(int j = i; j <= n; j++) {
if(dp1[i][j] + dp2[i][j] * i <= limit) {
kMax = i;
}
}
}
System.out.println("Max K: " + kMax);
return 0;
}
}
if you are dependent only on algorithms and not making any app or game, it's not necessary that you have to use java, try using python or c++ (or even c, c#), python is used mostly for algorithms,
or if you need java only then add breakpoints or make the program to print all work it does (ask it to print j, i, k, result variables in console) then you can easily debug.
Related
I'm trying to solve this problem:
Given an array of positive integers, and an integer Y, you are allowed to replace at most Y array-elements with lesser values. Your goal is for the array to end up with as large a subset of identical values as possible. Return the size of this largest subset.
The array is originally sorted in increasing order, but you do not need to preserve that property.
So, for example, if the array is [10,20,20,30,30,30,40,40,40] and Y = 3, the result should be 6, because you can get six 30s by replacing the three 40s with 30s. If the array is [20,20,20,40,50,50,50,50] and Y = 2, the result should be 5, because you can get five 20s by replacing two of the 50s with 20s.
Below is my solution with O(nlogn) time complexity. (is that right?) I wonder if I can further optimize this solution?
Thanks in advance.
public class Nails {
public static int Solutions(int[] A, int Y) {
int N = A.length;
TreeMap < Integer, Integer > nailMap = new TreeMap < Integer, Integer > (Collections.reverseOrder());
for (int i = 0; i < N; i++) {
if (!nailMap.containsKey(A[i])) {
nailMap.put(A[i], 1);
} else {
nailMap.put(A[i], nailMap.get(A[i]) + 1);
}
}
List < Integer > nums = nailMap.values().stream().collect(Collectors.toList());
if (nums.size() == 1) {
return nums.get(0);
}
//else
int max = nums.get(0);
int longer = 0;
for (int j = 0; j < nums.size(); j++) {
int count = 0;
if (Y < longer) {
count = Y + nums.get(j);
} else {
count = longer + nums.get(j);
}
if (max < count) {
max = count;
}
longer += nums.get(j);
}
return max;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String[] input = scanner.nextLine().replaceAll("\\[|\\]", "").split(",");
System.out.println(Arrays.toString(input));
int[] A = new int[input.length - 1];
int Y = Integer.parseInt(input[input.length - 1]);
for (int i = 0; i < input.length; i++) {
if (i < input.length - 1) {
A[i] = Integer.parseInt(input[i]);
} else {
break;
}
}
int result = Solutions(A, Y);
System.out.println(result);
}
}
}
A C++ implementation would like the following where A is the sorted pin size array and K is the number of times the pins can be hammered.
{1,1,3,3,4,4,4,5,5}, K=2 should give 5 as the answer
{1,1,3,3,4,4,4,5,5,6,6,6,6,6,6}, K=2 should give 6 as the answer
int maxCount(vector<int>& A, int K) {
int n = A.size();
int best = 0;
int count = 1;
for (int i = 0; i < n-K-1; i++) {
if (A[i] == A[i + 1])
count = count + 1;
else
count = 1;
if (count > best)
best = count;
}
int result = max(best+K, min(K+1, n));
return result;
}
Since the array is sorted to begin with, a reasonably straightforward O(n) solution is, for each distinct value, to count how many elements have that value (by iteration) and how many elements have a greater value (by subtraction).
public static int doIt(final int[] array, final int y) {
int best = 0;
int start = 0;
while (start < array.length) {
int end = start;
while (end < array.length && array[end] == array[start]) {
++end;
}
// array[start .. (end-1)] is now the subarray consisting of a
// single value repeated (end-start) times.
best = Math.max(best, end - start + Math.min(y, array.length - end));
start = end; // skip to the next distinct value
}
assert best >= Math.min(y + 1, array.length); // sanity-check
return best;
}
First, iterate through all the nails and create a hash H that stores the number of nails for each size. For [1,2,2,3,3,3,4,4,4], H should be:
size count
1 : 1
2 : 2
3 : 3
4 : 3
Now create an little algorithm to evaluate the maximum sum for each size S, given Y:
BestForSize(S, Y){
total = H[S]
while(Y > 0){
S++
if(Y >= H[S] and S < biggestNailSize){
total += H[S]
Y -= H[S]
}
else{
total += Y
Y = 0
}
}
return total;
}
Your answer should be max(BestForSize(0, Y), BestForSize(1, Y), ..., BestForSize(maxSizeOfNail, Y)).
The complexity is O(n²). A tip to optimize is to start from the end. For example, after you have the maximum value of nails in the size 4, how can you use your answer to find the maximum number of size 3?
Here is my java implementation: First I build a reversed map of each integer and its occurence for example {1,1,1,1,3,3,4,4,5,5} would give {5=2, 4=2, 3=2, 1=4}, then for each integer I calculate the max occurence that we can get of it regarding the K and the occurences of the highest integers in the array.
public static int ourFunction(final int[] A, final int K) {
int length = A.length;
int a = 0;
int result = 0;
int b = 0;
int previousValue = 0;
TreeMap < Integer, Integer > ourMap = new TreeMap < Integer, Integer > (Collections.reverseOrder());
for (int i = 0; i < length; i++) {
if (!ourMap.containsKey(A[i])) {
ourMap.put(A[i], 1);
} else {
ourMap.put(A[i], ourMap.get(A[i]) + 1);
}
}
for (Map.Entry<Integer, Integer> entry : ourMap.entrySet()) {
if( a == 0) {
a++;
result = entry.getValue();
previousValue = entry.getValue();
} else {
if( K < previousValue)
b = K;
else
b = previousValue;
if ( b + entry.getValue() > result )
result = b + entry.getValue();
previousValue += entry.getValue();
}
}
return result;
}
Since the array is sorted, we can have an O(n) solution by iterating and checking if current element is equals to previous element and keeping track of the max length.
static int findMax(int []a,int y) {
int n = a.length,current = 1,max = 0,diff = 0;
for(int i = 1; i< n; i++) {
if(a[i] == a[i-1]) {
current++;
diff = Math.min(y, n-i-1);
max = Math.max(max, current+diff);
}else {
current = 1;
}
}
return max;
}
given int array is not sorted than you should sort
public static int findMax(int []A,int K) {
int current = 1,max = 0,diff = 0;
List<Integer> sorted=Arrays.stream(A).sorted().boxed().collect(Collectors.toList());
for(int i = 1; i< sorted.size(); i++) {
if(sorted.get(i).equals(sorted.get(i-1))) {
current++;
diff = Math.min(K, sorted.size()-i-1);
max = Math.max(max, current+diff);
}else {
current = 1;
}
}
return max;
}
public static void main(String args[]) {
List<Integer> A = Arrays.asList(3,1,5,3,4,4,3,3,5,5,5,1);
int[] Al = A.stream().mapToInt(Integer::intValue).toArray();
int result=findMax(Al, 5);
System.out.println(result);
}
I've been struggling for hours to eliminate a bug that I don't understand.
In line 190 of the code below (int s = n[0]) I get an array out of bounds exception which as I've narrowed down has to do with array e. Array e is declared at the top of the code given below with the length/size of an object list a (a.size()) and if I replace size with an arbitrary integer (for example 10) the error disappears.
Why can't I set a.size as the length of my array? Is there a way to go around this?
Summary of the code: powerize(int n) is supposed to Write a number n as a power with maximal exponent. factorize decomposes a number into the product of primes and gcd returns the greatest common divisor of an array of integers.
public static Power powerize(int n) throws IllegalArgumentException {
List<Power> a = MathStuff.factorize(n); //make a list of Power objects from factorize n
int size = a.size();
int[] e = new int[size];
int[] b = new int[size];
for (int i = 0; i < size; i++) { //collect all the base and exponent of each object in a. This LOOP 1
if(i >= a.size() || i >= e.length || i > b.length){System.out.print("Out of bounds in LOOP 1");} //test for out of bounds
e[i] = a.get(i).exponent;
b[i] = a.get(i).base;
}
int g = gcd(e);
int h = 1; //endproduct base
for (int i = 1; i < b.length; i++) { //Construct the base by taking the product of each base with its exponent divided by g.
if(i >= e.length || i >= b.length){System.out.print("Out of bounds in LOOP 3");} //test for out of bounds
h *= MathStuff.power(b[i], e[i] / g);
}
return new Power(h, g); //replace 2
}
/**
* factorize n
*
* #param n the number to 'powerize'
* #modifies none
* #pre {#code 2 <= n}
* #return factorization of n
*/
public static List<Power> factorize(int n) {
List<Integer> f = new ArrayList<Integer>(); // f are factors
for (int i = 2; i <= n; i++) {
while (n % i == 0) {
f.add(i);
n /= i;
}
}
//return f; //returns factors
List<Power> p = new ArrayList<Power>(); // p are the factors with powers
for (int j = 2; j <= n; j++) { //j will be the base
int e = 0; //exponent
for (int k = 0; k <= f.size(); k++) {
if (f.get(k) == j) {
e++;
}
}
p.add(new Power(j, e));
}
return p; //returns factors in powered form
}
/**
* gcd returns the greatest common divisor of an integer array
* #param n
* #return greatest common divisor
*/
public static int gcd(int... n) {
//------------------------------------------------THE ERROR OCCURS HERE
int s = n[0];
for (int i = 1; i < n.length; i++) {
if (n[i] < s) {
s = n[i];
}
}
while (s > 1) {
int counter = 0;
int modTot = 0;
while (counter < n.length) {
modTot += n[counter] % s;
counter++;
}
if (modTot == 0) {
return s;
}
s--;
}
//return 0 if there is no gcd
return 0;
}
Here:
public static int gcd(int... n) {
int s = n[0];
This code assumes (without any further checking) that gcd() was invoked with at least one array element. But obviously that is not true.
Keep in mind that you can invoke that method like:
gcd(); // NO array at all or
gcd(someArray); // but someArray happens to be null !
So you have to step back and check your source code for all situations where gcd() is called. There must be one where you pass 0 parameters; or you pass an array of int that is actually null.
I'll assume that your question is why you can't set the size of an array using the size property.
When an array is initialized (via new int[x]), the OS will look for a continuous block of memory that will be big enough to hold x ints. Once that memory is found, the size of the array will be fixed as x.
Think of what would happen if you could change the array size using size. This would mean that, if you wanted to expand this array, you would have to take over the memory that comes immediately after it. What if that memory is being used by something else? That would present a problem.
However, java.util.ArrayList solves this problem for you as and when necessary. So that's the work-around if you need it.
I'm a beginner, and I'm trying to write a working travelling salesman problem using dynamic programming approach.
This is the code for my compute function:
public static int compute(int[] unvisitedSet, int dest) {
if (unvisitedSet.length == 1)
return distMtx[dest][unvisitedSet[0]];
int[] newSet = new int[unvisitedSet.length-1];
int distMin = Integer.MAX_VALUE;
for (int i = 0; i < unvisitedSet.length; i++) {
for (int j = 0; j < newSet.length; j++) {
if (j < i) newSet[j] = unvisitedSet[j];
else newSet[j] = unvisitedSet[j+1];
}
int distCur;
if (distMtx[dest][unvisitedSet[i]] != -1) {
distCur = compute(newSet, unvisitedSet[i]) + distMtx[unvisitedSet[i]][dest];
if (distMin > distCur)
distMin = distCur;
}
else {
System.out.println("No path between " + dest + " and " + unvisitedSet[i]);
}
}
return distMin;
}
The code is not giving me the correct answers, and I'm trying to figure out where the error is occurring. I think my error occurs when I add:
distCur = compute(newSet, unvisitedSet[i]) + distMtx[unvisitedSet[i]][dest];
So I've been messing around with that part, moving the addition to the very end right before I return distMin and so on... But I couldn't figure it out.
Although I'm sure it can be inferred from the code, I will state the following facts to clarify.
distMtx stores all the intercity distances, and distances are symmetric, meaning if distance from city A to city B is 3, then the distance from city B to city A is also 3. Also, if two cities don't have any direct paths, the distance value is -1.
Any help would be very much appreciated!
Thanks!
Edit:
The main function reads the intercity distances from a text file. Because I'm assuming the number of cities will always be less than 100, global int variable distMtx is [100][100].
Once the matrix is filled with the necessary information, an array of all the cities are created. The names of the cities are basically numbers. So if I have 4 cities, set[4] = {0, 1, 2, 3}.
In the main function, after distMtx and set is created, first call to compute() is called:
int optRoute = compute(set, 0);
System.out.println(optRoute);
Sample input:
-1 3 2 7
3 -1 10 1
2 10 -1 4
7 1 4 -1
Expected output:
10
Here's a working iterative solution to the TSP with dynamic programming. What would make your life easier is to store the current state as a bitmask instead of in an array. This has the advantage that the state representation is compact and can be cached easily.
I made a video detailing the solution to this problem on Youtube, please enjoy! Code was taken from my github repo
/**
* An implementation of the traveling salesman problem in Java using dynamic
* programming to improve the time complexity from O(n!) to O(n^2 * 2^n).
*
* Time Complexity: O(n^2 * 2^n)
* Space Complexity: O(n * 2^n)
*
**/
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
public class TspDynamicProgrammingIterative {
private final int N, start;
private final double[][] distance;
private List<Integer> tour = new ArrayList<>();
private double minTourCost = Double.POSITIVE_INFINITY;
private boolean ranSolver = false;
public TspDynamicProgrammingIterative(double[][] distance) {
this(0, distance);
}
public TspDynamicProgrammingIterative(int start, double[][] distance) {
N = distance.length;
if (N <= 2) throw new IllegalStateException("N <= 2 not yet supported.");
if (N != distance[0].length) throw new IllegalStateException("Matrix must be square (n x n)");
if (start < 0 || start >= N) throw new IllegalArgumentException("Invalid start node.");
this.start = start;
this.distance = distance;
}
// Returns the optimal tour for the traveling salesman problem.
public List<Integer> getTour() {
if (!ranSolver) solve();
return tour;
}
// Returns the minimal tour cost.
public double getTourCost() {
if (!ranSolver) solve();
return minTourCost;
}
// Solves the traveling salesman problem and caches solution.
public void solve() {
if (ranSolver) return;
final int END_STATE = (1 << N) - 1;
Double[][] memo = new Double[N][1 << N];
// Add all outgoing edges from the starting node to memo table.
for (int end = 0; end < N; end++) {
if (end == start) continue;
memo[end][(1 << start) | (1 << end)] = distance[start][end];
}
for (int r = 3; r <= N; r++) {
for (int subset : combinations(r, N)) {
if (notIn(start, subset)) continue;
for (int next = 0; next < N; next++) {
if (next == start || notIn(next, subset)) continue;
int subsetWithoutNext = subset ^ (1 << next);
double minDist = Double.POSITIVE_INFINITY;
for (int end = 0; end < N; end++) {
if (end == start || end == next || notIn(end, subset)) continue;
double newDistance = memo[end][subsetWithoutNext] + distance[end][next];
if (newDistance < minDist) {
minDist = newDistance;
}
}
memo[next][subset] = minDist;
}
}
}
// Connect tour back to starting node and minimize cost.
for (int i = 0; i < N; i++) {
if (i == start) continue;
double tourCost = memo[i][END_STATE] + distance[i][start];
if (tourCost < minTourCost) {
minTourCost = tourCost;
}
}
int lastIndex = start;
int state = END_STATE;
tour.add(start);
// Reconstruct TSP path from memo table.
for (int i = 1; i < N; i++) {
int index = -1;
for (int j = 0; j < N; j++) {
if (j == start || notIn(j, state)) continue;
if (index == -1) index = j;
double prevDist = memo[index][state] + distance[index][lastIndex];
double newDist = memo[j][state] + distance[j][lastIndex];
if (newDist < prevDist) {
index = j;
}
}
tour.add(index);
state = state ^ (1 << index);
lastIndex = index;
}
tour.add(start);
Collections.reverse(tour);
ranSolver = true;
}
private static boolean notIn(int elem, int subset) {
return ((1 << elem) & subset) == 0;
}
// This method generates all bit sets of size n where r bits
// are set to one. The result is returned as a list of integer masks.
public static List<Integer> combinations(int r, int n) {
List<Integer> subsets = new ArrayList<>();
combinations(0, 0, r, n, subsets);
return subsets;
}
// To find all the combinations of size r we need to recurse until we have
// selected r elements (aka r = 0), otherwise if r != 0 then we still need to select
// an element which is found after the position of our last selected element
private static void combinations(int set, int at, int r, int n, List<Integer> subsets) {
// Return early if there are more elements left to select than what is available.
int elementsLeftToPick = n - at;
if (elementsLeftToPick < r) return;
// We selected 'r' elements so we found a valid subset!
if (r == 0) {
subsets.add(set);
} else {
for (int i = at; i < n; i++) {
// Try including this element
set |= 1 << i;
combinations(set, i + 1, r - 1, n, subsets);
// Backtrack and try the instance where we did not include this element
set &= ~(1 << i);
}
}
}
public static void main(String[] args) {
// Create adjacency matrix
int n = 6;
double[][] distanceMatrix = new double[n][n];
for (double[] row : distanceMatrix) java.util.Arrays.fill(row, 10000);
distanceMatrix[5][0] = 10;
distanceMatrix[1][5] = 12;
distanceMatrix[4][1] = 2;
distanceMatrix[2][4] = 4;
distanceMatrix[3][2] = 6;
distanceMatrix[0][3] = 8;
int startNode = 0;
TspDynamicProgrammingIterative solver = new TspDynamicProgrammingIterative(startNode, distanceMatrix);
// Prints: [0, 3, 2, 4, 1, 5, 0]
System.out.println("Tour: " + solver.getTour());
// Print: 42.0
System.out.println("Tour cost: " + solver.getTourCost());
}
}
I know this is pretty old question but it might help somebody in the future.
Here is very well written paper on TSP with dynamic programming approach
https://github.com/evandrix/SPOJ/blob/master/DP_Main112/Solving-Traveling-Salesman-Problem-by-Dynamic-Programming-Approach-in-Java.pdf
I think you have to make some changes in your program.
Here there is an implementation
http://www.sanfoundry.com/java-program-implement-traveling-salesman-problem-using-nearest-neighbour-algorithm/
Trying to solve codility lessons for practice and working on this.
Written my code in Java and tested the code on a wide range of inputs, however the code fails for extreme_min_max, single and double in the codility test results.
Assumption given:
N is an integer within the range [1..100,000].
Each element of array A is an integer within the range [1..1,000,000,000].
Explanation of my code:
1. Sort the given array.
2. Iterate over each element in the array to find the difference between every consecutive pair. If the difference is not 1, Then its not a perm hence return 0. In case there is only one element in the array, return 1.
Can anyone please help me find out the bug(s) in my code?
My code:
public int solution(int[] A)
{
if(A.length == 1)
return 1;
Arrays.sort(A);
for (int i = 0; i < A.length-1; i++)
{
long diff = Math.abs(A[i] - A[i+1]);
if(diff!=1)
return 0;
}
return 1;
}
Here is simple and better implementation which runs in O(N) time complexity and takes O(N) space complexity.
public int solution(int[] A)
{
int size = A.length;
int hashArray[] = new int[size+1];
for (int i = 0; i < size; i++)
{
if(A[i]>size)
return 0;
else
hashArray[A[i]]+=1;
}
for(int i=1;i<=size;i++)
if(hashArray[i]!=1)
return 0;
return 1;
}
Try this in C# (Score 100%) :
using System;
using System.Linq;
class Solution {
public int solution(int[] A) {
if (A.Any(x => x == 0)) { return 0; }
var orderSelect = A.OrderBy(x => x).GroupBy(x => x);
if (orderSelect.Any(x => x.Count() > 1)) { return 0; }
var res = Enumerable.Range(1, A.Length).Except(A);
return res.Any() ? 0 : 1;
}
}
Pretty simple:
Your code doesn't check this condition:
A permutation is a sequence containing each element from 1 to N once, and only once.
Ensure that the first element after sorting is 1, and everything should work.
I'm not big on Java syntax, but what you want to do here is:
Create an array temp the length of A - initialized to 0.
Go over A and do temp[A[i]]++.
Go over temp, and if any place in the array is not 1, return false.
If duplicate exists - return 0 I have implemented with 100% pass
https://codility.com/demo/results/trainingWX2E92-ASF/
public static int permCheck(int A[]){
Set<Integer> bucket = new HashSet<Integer>();
int max = 0;
int sum=0;
for(int counter=0; counter<A.length; counter++){
if(max<A[counter]) max=A[counter];
if(bucket.add(A[counter])){
sum=sum+A[counter];
}
else{
return 0;
}
}
System.out.println(max+"->"+sum);
int expectedSum = (max*(max+1))/2;
if(expectedSum==sum)return 1;
return 0;
}
Here's my first 100% code.
I can't say if it's the fastest but it seems all correct -- watch the double OR ( || ) condition.
import java.util.Arrays;
class Solution
{
public int solution(int[] A)
{
int i = 0;
int size = A.length;
if ( size > 0 && size < 100001)
{
// Sort the array ascending:
Arrays.sort(A);
// Check each element:
for(i = 0; i < size; i++)
if ( A[i] > size || A[i] != (i + 1) )
return 0;
return 1;
}
return 0;
}
}
EDIT
Actually, we need not worry about valid first element data (i.e. A[i] > 0) because, after sorting, a valid perm array must have A[0] = 1 and this is already covered by the condition A[i] = i + 1.
The upper limit for array entries (> 1,000,000,000) is restricted further by the limit on the array size itself (100,000) and we must check for conformity here as there will be a Codility test for this. So I have removed the lower limit condition on array entries.
Below code runs and gave me a 100%, the time complexity is O(n):
private static int solution(int[] A) {
int isPermutation = 1; // all permutations start at 1
int n = A.length;
Arrays.sort(A);
if (n == 0) return 0; // takes care of edge case where an empty array is passed
for (int i = 0; i < n; i++) {
if (A[i] != isPermutation) { //if current array item is not equals to permutation, return 0;
return 0;
}
isPermutation++;
}
return 1;
}
100% score with complexity O(N)
public int solution(int[] A) {
int res = 1;
if (A.length == 1 && A[0]!=1)
return 0;
int[] B = new int[A.length];
for (int j : A) {
int p = j - 1;
if (A.length > p)
B[p] = j;
}
for (int i = 0; i < B.length - 1; i++) {
if (B[i] + 1 != B[i + 1]) {
res = 0;
break;
}
}
return res;
}
I'm having trouble figuring out how exactly to make it find the max number and minimum number in the array.
Write a method range that accepts an ArrayList of integers as a parameter and that returns the range of values contained in the list, which is defined as 1 more than the difference between the largest and smallest elements. For example if a variable called list stores the following values:
[18, 14, 29, 12, 7, 25]
The call of range(list) should return 23, because this is one more than the largest difference between any pair of values (29 - 7 + 1 = 23). An empty list is defined to have a range of 0.
So far I have this:
public static int range(ArrayList<Integer> list)
{
int min = 0;
int max = 0;
int range = 0;
for (int i: list)
{
if (list.size() > 0)
{
range = max - min + 1;
}
}
return range;
}
Thank you VERY MUCH!
You have more than method to achive this goal.
Using Collections (more compact but expensive because it iterates two times on the list, one to find the max and one to find the min):
public static int range(final ArrayList<Integer> list) {
if (list.isEmpty()) {
return 0;
} else {
return (Collections.max(list) - Collections.min(list)) + 1;
}
}
Or using your own algorithm like this (more code but finds min and max with just one loop):
public static int range(final ArrayList<Integer> list) {
if (list.isEmpty()) {
return 0;
} else {
int max = list.get(0);
int min = list.get(0);
for (final int i : list) {
if (i > max) {
max = i;
} else if (i < min) {
min = i;
}
}
return (max - min) + 1;
}
}
Why not use Collections.min and Collections.max
int difference = Collections.max(list) - Collections.min(list);
You never calculate the max and the min value in your loop.
Hint : In this loop, find the max and the min value. Then calculate the range and return it.
int min = 0;
int max = 0;
for (int i: list){
//find max and min here
}
return max - min + 1;
This task only needs two lines:
Collections.sort(list);
return list.isEmpty() ? 0 : list.get(list.size() - 1) - list.get(0);
Use the java JDK's API to do the heavy lifting for you
It's how you look at a problem that's important
Less code is good (as long as it's legible
You could sort it and then peek fist and last item.
public static int range(List<Integer> input)
{
if(input == null || input.size() == 0) throw new IllegalArgumentException("");
if(input.size() == 1) return 0;
List<Integer> copy = new ArrayList(input);
Collections.sort(copy);
int min = copy.get(0);
int max = copy.get(copy.lenght-1);
return max - min;
}
This is not a perfect solution as list may contain nulls.
You can start with simple comparison.
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for(Integer integer : input) {
if(i == null) continue;
int i = integer.intValue();
if(i < min) {
min = i;
}
if(i > max) {
max = i;
}
}
return max - min;
public static int range(ArrayList<Integer> list){
int min = list.get(0);
int max = list.get(0);
for (int i = 0; i < list.size(); i++){
if (list.get(i) > max)
max = list.get(i);
if ((list.get(i) < min))
min = list.get(i);
}
return max-min+1;
}
I have another solution that works. Let me explain how it works.
The first if statement checks for the empty list case.
Afterwards, I declared an integer variable int diff to return at the end. Two numbers are selected by the two for loops where the first one starts at index 0 while the nested loop starts at index 1 so that no same numbers are considered when looping through. The difference between two numbers are obtained using the formula declared as int calc. Since we're looking for the biggest difference between two numbers, we set diff = calc and keep it updating.
Lastly, we return diff + 1 as the problem stated.
public int range(ArrayList<Integer> list) {
if (list.size() == 0) {
return 0;
}
int diff = 0;
for (int i = 0; i < list.size(); i++) {
for (int j = 1; j < list.size(); j++) {
int calc = Math.abs(list.get(i) - list.get(j));
if (diff < calc) {
diff = calc;
}
}
}
return diff + 1;
}