Refactor for loops into function - java

I've got this piece of java code:
int maxDigit = 4;
for(int a = 0; a <= maxDigit; a++)
{
for(int b = 0; b <= maxDigit; b++)
{
if(b != a){
for(int c = 0; c <= maxDigit; c++)
{
if(c != a && c != b)
{
for(int d = 0; d <= maxDigit; d++)
{
if(d != a && d != b && d != c)
{
for(int e = 0; e <= maxDigit; e++)
{
if(e != a && e != b && e != c && e != d)
{
String temp = a + "" + b + "" + c + "" + d + "" + e;
System.out.println(temp);
permutations.add(Integer.parseInt(temp));
}
}
}
}
}
}
}
}
}
How can you transform this piece of code into a function?
The purpose is to generate permutations of the digits 0 to 9 and here in the code above it is from 0 to 4. And it seems easy to put it in a function but i couldn't find it immediately.

This is a variant of the classic problem of getting all permutations of a string.
The induction your professor wants you to make is that this problem lends itself well to a solution that uses recursion.
The basic algorithm for the permutations of string s is as follows:
Select the first item in s.
Get all permutations of the other items in s (except the item selected).
Prepend selected item to each permutation from step 2.
Repeat for the next character of s.
Here's an efficient solution using the Functional Java library.
Import these...
import fj.F;
import fj.P2;
import fj.P1;
import fj.data.Stream;
import static fj.data.Stream.nil;
import static fj.data.Stream.cons;
import static fj.data.Stream.range;
import static fj.data.Enumerator.charEnumerator;
import static fj.data.Show.streamShow;
import static fj.data.Show.charShow;
import static fj.P2.map2_;
A recursive function to find permutations:
public Stream<Stream<Character>> permutations(final Stream<Character> s) {
return selections(s).bind(
new F<P2<Character, Stream<Character>>, Stream<Stream<Character>>>() {
public Stream<Stream<Character>>()
f(final P2<Character, Stream<Character>> ys) {
return permutations(ys._2()).bind(cons(ys._1()));
}
});
}
A recursive function to select each element in turn:
public Stream<P2<Character, Stream<Character>>>
selections(final Stream<Character> s) {
if (xs.isEmpty())
return nil();
else {
final char x = xs.head();
final Stream<Character> xs = s.tail()._1();
return cons(P.p(x, xs),
new P1<Stream<P2<Character, Stream<Character>>>>() {
public Stream<P2<Character, Stream<Character>>> _1() {
return selections(xs).map(map2_().f(cons(x))));
}
});
}
}
and then, to get all permutations of characters '0' through '9':
Show<Stream<Character>> s = streamShow(charShow);
for (Stream<Character> ps : permutations(range(charEnumerator, '0', '9'))) {
System.out.println(s.showS(ps));
}
EDIT: This is actually a great use case for comonads. Using the latest trunk head of Functional Java, you can do this with the Zipper comonad, like so:
public static Stream<Stream<Character>> perms(Stream<Character> s) {
Stream<Stream<Character>> r = single(Stream.<Character>nil());
for (final Zipper<Character> z : fromStream(s))
r = join(z.cobind(
new F<Zipper<Character>, Stream<Stream<Character>>>() {
public Stream<Stream<Character>> f(final Zipper<Character> zp) {
return perms(zp.lefts().reverse().append(zp.rights())).map(compose(
Stream.<Character>cons().f(zp.focus()),
P.<Stream<Character>>p1()));
}
}).toStream());
return r;
}

Fill the holes:
int[] indexes = { 0, 0, 0, 0, 0 };
addPermutations(maxDigit, indexes, 0, permutations);
void addPermutations(int max, int[] indexes, int currentIndex, List<Integer> permutations) {
if (currentIndex == indexes.length) {
// terminal case
String temp = ...;
System.out.println(temp);
permutations.add(Integer.parseInt(temp));
} else {
// recursive case
for (int i = 0; i <= max; i++) {
if (... != i) {
indexes[currentIndex] = i;
addPermutations(max, indexes, currentIndex+1, permutations);
}
}
}
}

No code, but an algorithm should be as follows.
Suppose you want all permutations of 5 digits from 0 to 7. To do that:
Calculate j = decimal value of base-7 value of 100000 (1 + 5 zeroes)
Loop for i = 0; i < j; ++i, converting each i to base-7 system, optionally prepending with zeroes.

You could use an N-ary tree, with 4 branches at each point, recursively navigate the tree and step over branches where that node's digit had already been seen?

Related

Computing All Valid IP Addresses From Raw IP String

I'm now solving leetcode problem 93. Restore IP Addresses.
Here's the url link: https://leetcode.com/problems/restore-ip-addresses/
The description looks like this:
Given a string s containing only digits. Return all possible valid IP addresses that can be obtained from s. You can return them in any order.
A valid IP address consists of exactly four integers, each integer is between 0 and 255, separated by single points and cannot have leading zeros. For example, "0.1.2.201" and "192.168.1.1" are valid IP addresses and "0.011.255.245", "192.168.1.312" and "192.168#1.1" are invalid IP addresses.
However, as I was trying to solve my problem via backtracking, I couldn't figure out the reason that I'm always returning an empty ArrayList. I double checked my base case and my recursion and still couldn't find the bug. Any help would be greatly appreciated, thank you!
public List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<>();
if(s.length() == 0){
return res;
}
int[] path = new int[4];
snapshotIP(res,s,0,path,0);
return res;
}
public void snapshotIP(List<String> res, String s, int index, int[] path, int segment){
if(segment == 4 && index == s.length()){
res.add(path[0]+"."+path[1]+"."+path[2]+"."+path[3]);
return;
}
else if(segment == 4 || index == s.length()){
return;
}
for(int len = 1; len <= 3 && index + len <= s.length(); len++){
String snap = s.substring(index,index+len);
int val = Integer.parseInt(snap);
if(val > 225 || len >= 2 && s.charAt(index) == '0'){
break;
}
path[segment] = val;
snapshotIP(res,s,index+len,path,segment+1);
path[segment] = -1; //undo the choice
}
}
You have written a pretty advanced code. It's working for all the cases where IP address segment is lower than 225, but the first test case has 255s in there.
The fix is trivial, just replace "val > 225" to "val > 255".
It should be like this:
if(val > 255 || len >= 2 && s.charAt(index) == '0')
P.S.
I would do this differently, I would add dots into every possible place and validate every received combination.
Your code looks pretty good, not bad at all, not sure where your bug is though.
Here is an alternative solution, not so pretty though, it would pass just fine:
public final class Solution {
public static final List<String> restoreIpAddresses(
final String ip
) {
List<String> res = new ArrayList<>();
int length = ip.length();
for (int i = 1; i < 4 && i < length - 2; i++)
for (int j = i + 1; j < i + 4 && j < length - 1; j++)
for (int k = j + 1; k < j + 4 && k < length; k++) {
final String part1 = ip.substring(0, i);
final String part2 = ip.substring(i, j);
final String part3 = ip.substring(j, k);
final String part4 = ip.substring(k, length);
if (isValid(part1) && isValid(part2) && isValid(part3) && isValid(part4)) {
res.add(part1 + "." + part2 + "." + part3 + "." + part4);
}
}
return res;
}
private static final boolean isValid(
final String s
) {
if (s.length() > 3 || s.length() == 0 || (s.charAt(0) == '0' && s.length() > 1) || Integer.parseInt(s) > 255) {
return false;
}
return true;
}
}
Something a bit suspicious in your code is that the backtracking helper function is void, maybe you've to define a variable to make it work, still unsure.
Similarly in C++, if you'd be interested:
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
std::cout.tie(NULL);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <vector>
#include <string>
#define LIMIT 256
using ValueType = std::uint_fast16_t;
static const struct Solution {
static const std::vector<std::string> restoreIpAddresses(
const std::string s
) {
const ValueType len = std::size(s);
std::vector<std::string> ips;
std::string ip;
ValueType a, b, c, d;
ValueType A, B, C, D;
for (a = 1; a < 4; ++a) {
for (b = 1; b < 4; ++b) {
for (c = 1; c < 4; ++c) {
for (d = 1; d < 4; ++d) {
if (a + b + c + d == len) {
A = std::stoi(s.substr(0, a));
B = std::stoi(s.substr(a, b));
C = std::stoi(s.substr(a + b, c));
D = std::stoi(s.substr(a + b + c, d));
if (A < LIMIT && B < LIMIT && C < LIMIT && D < LIMIT) {
ip = std::to_string(A) + "." +
std::to_string(B) + "." +
std::to_string(C) + "." +
std::to_string(D);
if (std::size(ip) == len + 3) {
ips.emplace_back(ip);
}
}
}
}
}
}
}
return ips;
}
};
Here is LeetCode's backtracking depth first search algorithm that is similar to yours, that might help you figure it out.
class Solution {
int n;
String s;
LinkedList<String> segments = new LinkedList<String>();
ArrayList<String> output = new ArrayList<String>();
public boolean valid(String segment) {
/*
Check if the current segment is valid :
1. less or equal to 255
2. the first character could be '0'
only if the segment is equal to '0'
*/
int m = segment.length();
if (m > 3)
return false;
return (segment.charAt(0) != '0') ? (Integer.valueOf(segment) <= 255) : (m == 1);
}
public void update_output(int curr_pos) {
/*
Append the current list of segments
to the list of solutions
*/
String segment = s.substring(curr_pos + 1, n);
if (valid(segment)) {
segments.add(segment);
output.add(String.join(".", segments));
segments.removeLast();
}
}
public void backtrack(int prev_pos, int dots) {
/*
prev_pos : the position of the previously placed dot
dots : number of dots to place
*/
// The current dot curr_pos could be placed
// in a range from prev_pos + 1 to prev_pos + 4.
// The dot couldn't be placed
// after the last character in the string.
int max_pos = Math.min(n - 1, prev_pos + 4);
for (int curr_pos = prev_pos + 1; curr_pos < max_pos; curr_pos++) {
String segment = s.substring(prev_pos + 1, curr_pos + 1);
if (valid(segment)) {
segments.add(segment); // place dot
if (dots - 1 == 0) // if all 3 dots are placed
update_output(curr_pos); // add the solution to output
else
backtrack(curr_pos, dots - 1); // continue to place dots
segments.removeLast(); // remove the last placed dot
}
}
}
public List<String> restoreIpAddresses(String s) {
n = s.length();
this.s = s;
backtrack(-1, 3);
return output;
}
}
References
For additional details, please see the Discussion Board where you can find plenty of well-explained accepted solutions with a variety of languages including low-complexity algorithms and asymptotic runtime/memory analysis1, 2.
internal static IEnumerable<string> FetchPossibleIPs(string input, int currentSection = 1)
{
List<string> possibleIPs = new List<string>();
if (input.Length > 0)
{
// If section is 4 then no need
// to break further and simply verify.
if (currentSection == 4)
{
if (int.Parse(input) <= 255 && input[0].ToString() != "0")
{
possibleIPs.Add(input);
}
}
// Else if section is < 4 then break the string
// with substring of length of 1,2 or 3 to
// figure out possible combinations.
else
{
for (int i = 1; i <= 3; ++i)
{
var section = input.Substring(0, i);
if (int.Parse(section) <= 255 && section[0].ToString() != "0")
{
var otherSections = FetchPossibleIPs(input.Substring(i), currentSection + 1);
foreach (var item in otherSections)
{
possibleIPs.Add($"{section}.{item}");
}
}
}
}
}
return possibleIPs;
}
A sample solution in C# using recursion to solve it.
It uses recursion and backtracking to solve the problem.

Iterate through TreeSet without repeating solutions

I am making combinations of 3 different values that give a requested sum, in this case the requested sum is 0.I can't find a way to iterate through a TreeSet with 2 for loops in order to receive a set of 3 numbers without repeating that solution. The third number I would like to obtain by using the contains method of the TreeSet.
This is my code so far, it gives good solutions but it repeats them.
import java.util.*;
public class Tree
{
public static void main(String[] args)
{
TreeSet<Integer> ts = new TreeSet<>();
int array[] = {-5, 1, -4, 6, 2, 3, 9, 5};
int sumSearching = 0;
int valueSearching;
for(int i = 0; i < array.length; i++)
ts.add(array[i]);
for(Integer i: ts)
{
for(Integer j : ts)
{
if(i != j)
{
valueSearching = sumSearching - (i + j);
if(valueSearching != i && valueSearching != j)
if(ts.contains(valueSearching))
System.out.println("Solution: "
+ i + ", " + j + ", " + valueSearching);
}
}
}
}
}
Thanks for any kind of help!
Go for j > i, removing one symmetry.
This does not exclude doubles on {i, j, valueSearching} as negative numbers are involved. So one needs to maintain all solutions.
Set<Set<Integer>> solutions = new HashSet<>();
for (int i: ts)
{
for (int j : ts.tailSet(i, false))
{
valueSearching = sumSearching - (i + j);
if (valueSearching != i && valueSearching != j)
if (ts.contains(valueSearching)) {
Set<Integer> solution = new TreeSet<>();
Collections.addAll(solution, i, j, valueSearching);
if (solutions.add(solution)) {
System.out.println("Solution: "
+ i + ", " + j + ", " + valueSearching);
}
}
}
}
Also note: i != j for Integers should better be i.intValue() != j.intValue() as only in the range -128 .. 127 the object for a number is unique.
Here simply the int primitive type is used, which is more appropriate. Also Set.tailSet(value, exclusive) gives the set after the value. Using an Iterator probably would be more efficient.
Implement a reversable pair class:
class ReversablePair<T>
{
private final T first;
private final T second;
ReversablePair(final T first, final T second)
{
this.first = first;
this.second = second;
}
// Some getters...
#Override
public boolean equals(final Object o)
{
if (o == null) return false;
if (!(o instanceof ReversablePair)) return false;
final ReversablePair that = (ReversablePair) o;
return (this.first.equals(that.first) && this.second.equals(that.second))
|| (this.first.equals(that.second) && this.second.equals(that.first));
}
#Override
public int hashCode()
{
return first.hashCode() + second.hashCode();
}
}
Then maintain a set of previous solutions:
Set<ReversablePair<Integer>> previousSolutions = new HashSet();
And check the set before printing:
if (! previousSolutions.contains(new ReversablePair<>(i, j))
{
// whatever
}
To exclude repeating solutions, it's enough to include only those triples which are in ascending order.
So, try changing this line:
if (valueSearching != i && valueSearching != j)
to:
if (i < j && j < valueSearching)

How to generate combination of numbers in more optimized way in Java?

I had a problem statement which requires passing 3 different numbers to a method and checking which 3 numbers satisfies a certain constraint.
Here is my code, but I wanted to know instead of creating nested loops, is there any more optimized way of checking which set of triplet satisfies a certain constraint. ?
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Solution
{
static List l = new ArrayList();
static int geometricTrick(String s)
{
int count = 0;
for (int i = 0; i < s.length(); i++)
{
for (int j = 0; j < s.length(); j++)
{
for (int k = 0; k < s.length(); k++)
{
if (is1stConstraintTrue(s, i, j, k) && is2ndConstraintTrue(i, j, k))
{
l.add(new Triplet(i, j, k));
}
}
}
}
count = l.size();
return count;
}
static boolean is2ndConstraintTrue(int i, int j, int k)
{
boolean retVal = false;
double LHS = Math.pow((j + 1), 2);
double RHS = (i + 1) * (k + 1);
if (LHS == RHS)
retVal = true;
else
retVal = false;
return retVal;
}
static boolean is1stConstraintTrue(String s, int i, int j, int k)
{
boolean retVal = false;
char[] localChar = s.toCharArray();
if (localChar[i] == 'a' && localChar[j] == 'b' && localChar[k] == 'c')
{
retVal = true;
}
return retVal;
}
static class Triplet
{
public int i, j, k;
public Triplet(int i, int j, int k)
{
this.i= i;
this.j= j;
this.k= k;
}
}
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int n = in.nextInt();
String s = in.next();
int result = geometricTrick(s);
System.out.println(result);
}
}
Here are some hints:
Computing the square by multiplication will be faster than using pow
String::toCharray() is expensive. It copies all characters into a new array. Each time you call it. Don't call it multiple times.
If the result is the number of triples, you don't need to build a list. You don't even need to create Triple instances. Just count them.
Nested loops are not inefficient, if you need to iterate all combinations.
To provide you a simple and "stupid" solution to not use those inner loops.
Let's use a Factory like an Iterator. This would "hide" the loop by using condition statement.
public class TripletFactory{
final int maxI, maxJ, maxK;
int i, j ,k;
public TripletFactory(int i, int j, int k){
this.maxI = i;
this.maxJ = j;
this.maxK = k;
}
public Triplet next(){
if(++k > maxK){
k = 0;
if(++j > maxJ){
j = 0;
if(++i > maxI){
return null;
}
}
}
return new Triplet(i,j,k);
}
}
That way, you just have to get a new Triple until a null instance in ONE loop
TripletFactory fact = new TripletFactory(2, 3 ,5);
Triplet t = null;
while((t = fact.next()) != null){
System.out.println(t);
}
//no more Triplet
And use it like you want.
Then, you will have to update your constraint method to take a Triplet and use the getters to check the instance.
That could be a method of Triplet to let it validate itself by the way.
Note :
I used the same notation as the Iterator because we could implement Iterator and Iterable to use a notation like :
for(Triplet t : factory){
...
}
The naive approach you presented has cubic time complexity (three nested for-loops). If you have many occurrences of 'a', 'b' and 'c' within your input, it may be worth wile to first determine the indices of all 'a''s, 'b''s and 'c''s and then check your second condition only over this set.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static List<Integer> getAllOccurrences(String input, char of) {
List<Integer> occurrences = new ArrayList<Integer>();
char[] chars = input.toCharArray();
for (int idx = 0; idx < chars.length; ++idx) {
if (of == chars[idx]) {
occurrences.add(idx);
}
}
return (occurrences);
}
static List<Triplet> geometricTrick(String input){
List<Integer> allAs = getAllOccurrences(input, 'a');
List<Integer> allBs = getAllOccurrences(input, 'b');
List<Integer> allCs = getAllOccurrences(input, 'c');
List<Triplet> solutions = new ArrayList<Triplet>();
// reorder the loops, so that the c-loop is the innermost loop (see
// below why this is useful and how it is exploited).
for (int a : allAs) {
for (int c : allCs) {
// calculate lhs as soon as possible, no need to recalculate the
// same value multiple times
final int lhs = ((a + 1) * (c + 1));
for (int b : allBs) {
final int rhs = ((b + 1) * (b + 1));
if (lhs > rhs) {
continue;
}
/* else */ if (lhs == rhs) {
solutions.add(new Triplet(a, b, c));
}
// by construction, the b-values are in ascending or der.
// Thus if the rhs-value is larger or equal to the
// lhs-value, we can skip all other rhs-values. for this
// lhs-value.
// if (lhs <= rhs) {
break;
// }
}
}
}
return (solutions);
}
static class Triplet {
public final int i;
public final int j;
public final int k;
public Triplet(int i, int j, int k) {
this.i = i;
this.j = j;
this.k = k;
}
}
}
Searching all occurrences of one char within a given String takes O(n) (method getAllOccurrences(...)), calling it three times does not change the complexity (3 * n \in O(n)). Iterating through all possible combinations of a, b and c takes #a * #b * #c time, where #a, #b and #c stay for the count of a's, b's and c's in your input. This gives a total time complexity of O(n + #a * #b * #c).
Note that the worst case time complexity, i.e. if 1/3 of your string consists of a's, 1/3 consists of b's and 1/3 consists of c's, is still cubic.

Finding nearest non-coprime number

Given an array, I need to find the indices of nearest non-coprime number (i.e. GCD(Ai, Aj) > 1 , for any Ai and Aj in the array, i != j ) Example, let the array be
[2 17 4 6 10]
The answer will be
[3 -1 4 3 4]
I've written this brute force code (which is O(n^2)) using Binary GCD method, which is not very efficient. I'm wondering if there's a faster way to do this. Particularly in O(NlogN)
import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.StringTokenizer;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.InputStream;
/**
* Built using CHelper plug-in
* Actual solution is at the top
*
* #author Mayur Kulkarni
*/
public class Main {
public static void main(String[] args) {
InputStream inputStream = System.in;
OutputStream outputStream = System.out;
BladeReader in = new BladeReader(inputStream);
PrintWriter out = new PrintWriter(outputStream);
GCDPuz solver = new GCDPuz();
solver.solve(1, in, out);
out.close();
}
static class GCDPuz {
public static int gcd(int p, int q) {
if (q == 0) return p;
if (p == 0) return q;
// p and q even
if ((p & 1) == 0 && (q & 1) == 0) return gcd(p >> 1, q >> 1) << 1;
// p is even, q is odd
else if ((p & 1) == 0) return gcd(p >> 1, q);
// p is odd, q is even
else if ((q & 1) == 0) return gcd(p, q >> 1);
// p and q odd, p >= q
else if (p >= q) return gcd((p - q) >> 1, q);
// p and q odd, p < q
else return gcd(p, (q - p) >> 1);
}
public int coprime(int p, int q) {
if (p % 2 == 0 && q % 2 == 0) {
return 2;
} else if (p == q + 1 || q == p + 1) {
return 1;
} else {
return gcd(p, q);
}
}
public void solve(int testNumber, BladeReader in, PrintWriter out) {
int size = in.nextInt();
int[] arr = in.readIntArray(size);
int[] ans = new int[size];
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 1) {
ans[i] = -1;
continue;
}
int left = i == 0 ? -1 : findLeft(arr, i);
int right = i == arr.length - 1 ? -1 : findRight(arr, i);
int leftDist = left == -1 ? -1 : i - left;
int rightDist = right == -1 ? -1 : right - i;
int anss = findNearestIndex(left, leftDist, right, rightDist);
ans[i] = anss == -1 ? -1 : anss + 1;
}
printa(ans, out);
}
private void printa(int[] ans, PrintWriter out) {
StringBuilder sb = new StringBuilder();
for (int an : ans) {
sb.append(an).append(" ");
}
out.println(sb.toString());
}
private int findRight(int[] arr, int i) {
if (arr[i] == -1) return -1;
for (int j = i + 1; j < arr.length; j++) {
if (coprime(arr[i], arr[j]) > 1) return j;
}
return -1;
}
private int findLeft(int[] arr, int i) {
if (arr[i] == -1) return -1;
for (int j = i - 1; j >= 0; j--) {
if (coprime(arr[i], arr[j]) > 1) return j;
}
return -1;
}
private int findNearestIndex(int one, int oneDist, int two, int twoDist) {
if (oneDist == -1 && twoDist == -1) return -1;
if (oneDist == -1) return two;
if (twoDist == -1) return one;
if (oneDist == twoDist) {
return Math.min(one, two);
}
return oneDist < twoDist ? one : two;
}
}
static class BladeReader {
public BufferedReader reader;
public StringTokenizer tokenizer;
public BladeReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public int[] readIntArray(int size) {
int[] array = new int[size];
for (int i = 0; i < size; i++) {
array[i] = nextInt();
}
return array;
}
}
}
If you know your max value for your numbers and can afford to keep a list of primes, then factoring them may be a better solution for the average/random case. Otherwise, worst case complexity, it's still O(N*N) - think "all of them are primes" for the worst case.
Approach:
factor them and store a Map<prime, multiplicity>[N] + int closestNeigh[]
take a factor and O(N) determine for each of them the closest that contain that factor (prefix/sufix sums will be involved)
eliminate that factor from all the factor maps
take the next factor. Adjust the closest neighbor index only if new one is closest.
This may bring some "relief" on the line of O(N*<num_distict_factors>), but again if <num_distict_factors> == N (all primes), then it is still O(N*N)
If you are willing to get into factorization, one could traverse the list, once from the left, factoring each number, hashing the index of each new prime (with the prime as the key), updating the index of each prime already seen, and, of course, noting the nearest seen prime. Since this traversal would miss the nearest on the right, conduct another traversal from the right to update any nearer shared prime, using the factor lists already saved.

Dynamic programming approach to TSP in Java

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/

Categories

Resources