The current running time is 0(m+n) where
m = length(list1) and
n = length(list2). Combining the loops reduces the running time to 0(n) where
n is the length of the longer list.
Single Loop Example
Procedure in psuedo code:
length1 = list1.length
length2 = list2.length
stop = maximum(length1, length2)
min1 = list1
max1 = list1
min2 = list2
max2 = list2
loop from i = 1 to stop
if i< length1
min1 = minimum(min1, list1[i])
max1 = maximum(max1, list1[i])
if i< length2
min2 = minimum(min2, list2[i])
max2 = maximum(max2, list2[i])
return list(min1, max1, min2, max2)
Further refactoring is possible, but not shown to make the high level structure read more clearly.
In the review code there is a bit of disconnect between the form of the output and the execution path of the implementation:
The output of the review code is in tuple value form - i.e. the results of both lists are treated as single value and returned simultaneously:
System.out.println("List 1 Range: "+(max - min)+"\tList 2 Range: "+(max2 - min2));
The review code execution path explicitly processes the lists sequentially making
List2.range dependent on finding
Looping over the array lists one at a time creates a compositional type dependency that could be abstracted as
list2(list1()). As way of illustration:
print("List1 range: %d", (list1.max - list1.min))
print("\tList2 range: %d", (list2.max - list2.min))
Is structurally consistent with the 2 loop semantics because with two loops
list1 has execution priority.
Using a single loop which partially processes both lists on each iteration directly reflects the tuple semantics of the output. The tuple output implies that the input is also a tuple.
Treating the input as a tuple is Java's default function semantics as well - it is not normal to assume that the first argument to a Java function of airity 2 has execution priority over the second argument. Multiple arguments are parsed to a random access structure, not into a sequential one.
Processing both loops in a single loop has the form of a fixed point calculation that converges toward the ordered pair value
(list1.range, list2.range) with each iteration.
The single loop form allows for the possibility of returning the best current value of
list2.range at any time. This facilitates working with streams of arbitrary length and operating closer to real time.
Neither the single loop or double loop approach is objectively better. There are tradeoffs and benefits to each. These can only be evaluated in context. The hazard is that the context for a code snippet on the internet is often assumed to be trivial.