aboutsummaryrefslogtreecommitdiff
path: root/challenge-236/packy-anderson/java/Ch2.java
blob: 3ce68300e80f05d032a45ac8100030ca07b08408 (plain)
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.stream.Collectors;

public class Ch2 {
  public static ArrayList<Integer> loopExistsAt(
    int start, int[] ints, HashMap<Integer, Integer> seen
  ) {
    // bail early if we're in a loop we've seen before
    if (seen.get(start) != null) {
      // return an empty ArrayList
      return new ArrayList<Integer>();
    }

    // initialize an empty list to start
    ArrayList<Integer> loop = new ArrayList<Integer>();
    // initialize i to starting point
    int i = start;
    while (true) {
      // keep track of the values in the order we visit them
      loop.add(ints[i]);

      // track where we've already been
      // to avoid double-counting loops
      seen.put(i, 1);

      // get the next index
      i = ints[i];

      // make sure the index is in bounds
      if (i < 0 || i >= ints.length) {
        break;
      }

      // make sure we haven't seen the index before
      if (seen.get(i) != null) {
        break;
      }
    }

    // if the last element points back to
    // the start, it's a loop!
    if (loop.get(loop.size() - 1) == start) {
        return loop;
    }

    // otherwise, return an empty ArrayList
    return new ArrayList<Integer>();
  }

  public static ArrayList<ArrayList<Integer>> identifyLoops(int[] ints) {
    ArrayList<ArrayList<Integer>> loops =
      new ArrayList<ArrayList<Integer>>();
    HashMap<Integer, Integer> seen =
      new HashMap<Integer, Integer>();

    for (int i = 0; i < ints.length; i++) {
      ArrayList<Integer> loop = loopExistsAt(i, ints, seen);
      if (loop.size() > 0) {
        loops.add(loop);
      }
    }
    return loops;
  }

  public static String comma_joined(int[] ints) {
    // we're using it more than once, make it a method
    return Arrays.stream(ints)
                 .mapToObj(String::valueOf)
                 .collect(Collectors.joining(","));
  }

  public static void solution(int[] ints) {
    System.out.println("Input: @ints = (" + comma_joined(ints) +
                       ")");
    ArrayList<ArrayList<Integer>> loops = identifyLoops(ints);
    int count = loops.size();
    System.out.println(String.format("Output: %1$d", count));
    if (count > 0) {
      String loop_noun = (count == 1) ? "Loop" : "Loops";
      String are_verb  = (count == 1) ? "is"   : "are";
      System.out.println("\n" + loop_noun + " " + are_verb +
                         " as below:");

      for (ArrayList<Integer> loop : loops) {
        String as_list = loop.stream()
                             .map(String::valueOf)
                             .collect(Collectors.joining(" "));
        System.out.println("[" + as_list + "]");
      }
    }
  }

  public static void main(String[] args) {
    System.out.println("Example 1:");
    solution(new int[] {4,6,3,8,15,0,13,18,7,16,14,
                        19,17,5,11,1,12,2,9,10});

    System.out.println("\nExample 2:");
    solution(new int[] {0,1,13,7,6,8,10,11,2,14,16,
                        4,12,9,17,5,3,18,15,19});

    System.out.println("\nExample 3:");
    solution(new int[] {9,8,3,11,5,7,13,19,12,4,14,
                        10,18,2,16,1,0,15,6,17});
  }
}