I am working on a problem, and have spent some time on it.
Problem statement:
You are given an array of positive and negative integers. If a number n at an index is positive, then move forward n steps. Conversely, if it's negative (-n), move backward n steps. Assume the first element of the array is forward next to the last element, and the last element is backward next to the first element. Determine if there is a loop in this array. A loop starts and ends at a particular index with more than 1 element along the loop. The loop must be "forward" or "backward'.
Example 1: Given the array [2, -1, 1, 2, 2], there is a loop, from index 0 -> 2 -> 3 -> 0.
Example 2: Given the array [-1, 2], there is no loop.
Note: The given array is guaranteed to contain no element "0".
Can you do it in O(n) time complexity and O(1) space complexity?
And this is my solution in progress, however, I am not sure how should I end the do-while condition, when there is no loop detected. I believe my code will run infinitely if there is no loop detected.
public static boolean circularArrayLoop(int[] nums) {
int size = nums.length;
if(size < 2) return false;
int loopStart = nums[0];
int index = 0;
int start = nums[0];
do{
if(nums[index] > 0){
index = moveForward(index, nums[index], size);
}else {
index = moveBackward(index, Math.abs(nums[index]), size);
}
}while (loopStart != nums[index]);
}
This can be seen as a version of cycle detection in a directed (possibly disconnected) graph or more like finding a minimum spanning trees for all the connected subgraphs in the given graph. The numbers in the array are vertices and an edge will be formed between the vertices based on the vertice value. There are no known graph parsing algorithms which can possibly solve it in O(1) space complexity. This might be solved in O(n) time complexity as the best graph parsing algorithms can be solved in O(V+E) time and V=E in this case which makes it possible to solve with O(n) time complexity in some cases. The best-known algorithm is Kruskal's: http://www.geeksforgeeks.org/greedy-algorithms-set-2-kruskals-minimum-spanning-tree-mst/ which solves in O(nlogn) time.
Since there are guaranteed no elements with value 0, there is always going to be a loop. The qualifier is loops must be greater than a single element long.
With this condition, when advancing to the next index as directed by the array element value results in the same index being reached, "no" loop is present.
The fast and slow moving cursors can be used to find the beginning of the loop. Then advancing a single cursor until it returns to the same index would let you iterate over the elements of the loop. If a single advancement returns the cursor to the same index no loop is present.
public static void main(String[] args) {
int[] loop = {2, -1, 1, 2, 2};
int[] noloop = {-1, 2};
System.out.println(circularArrayLoop(loop));
System.out.println(circularArrayLoop(noloop));
}
static int nextIndex(int[] nums, int cur) {
// Get next index based on value taking into account wrapping around
}
static boolean circularArrayLoop(int[] nums) {
int fast = 0;
int slow = 0;
do {
// advance fast cursor twice
// advance slow cursor once
} while (fast != slow);
int next = nextIndex(nums, fast);
// return if the loop has more than a single element
}
Am I wrong to think there is no guarantee that the loop will go on with the first element ? Thus, you can't just do int loopStart = nums[0];
What if your example 1 was rather [2, -1, 1, 4, 2], then the loop would be from index 0 -> 2 -> 3 -> 2. And, your check with loopstart wouldn't work, since it checks sums[0].
A good solution is to use 2 variables and move them at different speed (one twice the speed). If the array/linked list is circular, you'll get to a point where var1 equals var2.
Here's the pseudocode:
if array.length<=1
return false
int i=0;
//loop is when "var1 == var2"
//end is when "var1 == abs(array.length)"
loop (until var1 == var2 or var1 reaches the end)
var1 = moveToNext(var1)
if (i++ % 2 == 0)
var2 = moveToNext(var2)
return var1 == var2;
This is quite similar to a question generally asked using linked list: How to detect a loop in a linked list?
Related
For an assignment, I have to write some Bogosort code, and empirically determine the program's Big O notation.
However, I am unsure of whether the code works, because even though it sorts it for 3 and 4 element arrays of type int, I don't think it should be doing it in 0 ms.
Conversely, it's taking really long for 5 elements (still haven't gotten a successful case within 15 minutes yet), which indicates to me that there may be something wrong with the program. Since there are no errors being thrown, I believe any problem found would be a logic error.
I've tried running the IDE debugger on the program. Each of the methods used for the bogosort seemed to be working as intended, although I was not able to reach the case where it sorted an array properly while using the debugger.
However, by changing the values of the array to have it already sorted, I was able to test the case where the array was sorted, and the code was executed successfully.
This seems to indicate that the problem if there is any, would have to do with a logic error in sorting, where the sort method is somehow never getting to the correct solution.
The file is as shown below, and is commented.
Any suggestions for the program will have to pertain to the current structure (no adding methods, no using ArrayLists) since this is a homework assignment.
public class BogoSort {
public static void main(String[] args) {
int[] myArray = {20, 142, 115, 120, 140};
//sets start time
long start = System.currentTimeMillis();
bogoSort(myArray);
//sets end time
long end = System.currentTimeMillis();
printArray(myArray);
//print time (end time - start time)
System.out.println((end - start) + "ms");
}
// Places the elements of a into sorted order.
public static void bogoSort(int[] a) {
while(!isSorted(a)){
//calls the shuffle method if it's not sorted
shuffle(a);
}
}
// Returns true if a's elements are in sorted order.
public static boolean isSorted(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i+1]) {
//returns false if the number in this index is greater than
//the number in the next index aka not sorted
return false;
}
}
//else return true
return true;
}
// Shuffles an array of ints by randomly swapping each
// element with an element ahead of it in the array.
public static void shuffle(int[] a){
Random r = new Random();
for(int i = a.length - 1;i > 0;i--){
//random number between 0 and i
int j = r.nextInt(i);
//calls swap method
swap(a, i, j);
}
}
// Swaps a[i] with a[j].
public static void swap(int[] a, int i, int j) {
//temp variable to hold value of a[i] for swap
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void printArray(int[] a)
{
for(int i = 0; i < a.length; i++)
{
System.out.println(a[i]);
}
}
}//end of BogoSort class
Results should be as follows:
20
115
120
140
142
???ms
??? is a value for how long the program runs for, maybe about 720 ms, if I understand bogosort's Big O notation correctly.
Currently, I have not gotten a result for an array above a size of 4.
The time it takes for an array of 3 or 4 elements to sort is 0 ms, which is a bit odd to me, I feel like it should be about 24 ms for 3 elements, and 120 ms for 4 elements.
The result of the sorting of a 3 or 4 element array is that the numbers are sorted correctly, as per the expected result.
Your shuffle algorithm is broken due to an off-by-1 error. If you try it with int[] myArray = {2,1,3};, you'll see that it fails to complete for 3 elements as well.
When dealing with randomness, it's better to use statistics than eyeballing, because it's hard to notice this at a glance:
$ java BogoSort | head -n 100000 > file
$ sort file | uniq -c
33325 [1, 3, 2]
33315 [2, 1, 3]
33360 [3, 2, 1]
As you can see, you only ever generate 3 out of 6 possible permutations.
When you shuffle, like your comment indicates, you swap each element with one earlier in the array. You need to additionally allow the element to stay in place. You can do this by adding 1 to the index you choose:
// Shuffles an array of ints by randomly swapping each
// element with an element ahead of it in the array **or leave it in place**.
public static void shuffle(int[] a){
Random r = new Random();
for(int i = a.length - 1;i > 0;i--){
//random number between 0 and i
int j = r.nextInt(i+1); // <-- +1 here to select the current element
//calls swap method
swap(a, i, j);
}
}
The result now looks better (I rigged the program to keep printing even when it's sorted):
$ sort file | uniq -c
16807 [1, 2, 3]
16579 [1, 3, 2]
16745 [2, 1, 3]
16697 [2, 3, 1]
16361 [3, 1, 2]
16811 [3, 2, 1]
and indeed, it now finishes in 0-1ms. Running it on 8 numbers takes ~10ms, and 10 numbers take ~150ms, in line with the expected factorial curve.
The accepted answer correctly identified the fault and a straight forward solution.
I attempted to dig a bit deeper into why there were missing permutations. From that answers suggested starting point, [2,1,3], the incorrect shuffle would result can only produce two outcomes: [1,3,2] and [3,2,1]. This is already a mistake, since you expect a shuffle to be able to produce any of the 6 permutations. However, in addition, under the incorrect shuffle, those outcomes can only produce each other on another iteration of the bad shuffle.
So, to think about it differently, the only way for [2,1,3] to shuffle into [1,2,3] would be if the third element was allowed to stay in place. The only way for [1,3,2] to shuffle into [1,2,3] would be if the first element was allowed to stay in place. Finally, the only way for [3,2,1] to shuffle into [1,2,3] would be if the second element was allowed to stay in place. But the algorithm does not allow elements to stay, and any moved element during the shuffle iteration is not moved again.
The bad shuffle only produces the permutations that cause all the elements to be in a different position. In other words, it can only produce rotations!Only for the 3 element case
So, if the starting point is not a rotation of the sorted array, the algorithm will never terminate.
In comments, I had suggested an alternative shuffle implementation:
public static void shuffle(int[] a){
Random r = new Random();
int x = r.nextInt(a.length);
for(int i = a.length-1;i > 0;i--){
int j = r.nextInt(i);
if (j < x) break;
swap(a, i, j);
}
}
However, the weakness of this shuffle is that itself still lacks the ability to generate any possible permutation. The ability of the bogosort to eventually see all possible permutations using this implementation depends on each successive call to shuffle producing slightly different inputs for the next call.
public class TestPossibleNumbers {
public static void main(String[] args) {
int input[] = { 1, 2, 3 };
// int input[] = {10,11,12,13};
possibleNumbers(input, 0);
}
public static void possibleNumbers(int[] x, int index) {
if (index == x.length) {
for (int i = 0; i < x.length; i++) {
System.out.print(x[i] + " ");
}
System.out.println();
}
for (int i = index; i < x.length; i++) {
int temp = x[index];
x[index] = x[i];
x[i] = temp;
possibleNumbers(x, index + 1);
temp = x[index];
x[index] = x[i];
x[i] = temp;
}
}}
Can anyone help me to understand the code inside for loop?
This program run perfectly. But, I am unable to figure out how it is working
You are recursively calling the method again at:
possibleNumbers(x, index + 1);
Thus the method runs the method again, with index + 1 passed. It checks if
if(index == x.length)
If the statement is correct it prints the numbers.
It then enters the 2nd for loop again(if the if statement was incorrect it will still enter it). And calls the recurring method again. It will keep entering 2nd for loop but when "index" will be equal to or greater than "i.length" no iterations of the for loop will run because you specified for loop to run only when:
i<i.length
When 2 for loop does not do any iterations the method will stop recurring. So in your case when index is equal to 3 no iterations of 2nd for loop will run.
Try running debug step by step to see what is happening more in depth.
The Program prints permutation of numbers not combination.
Permutation - Order matters
Combination - Order doesnt matter and more of choosing k elements out of n
for example
int a= {a,b};
permutation = {ab,ba}
whereas combination ={{},{a},{b},{a,b}}
To understand how the program works
go through the following link will
https://www.geeksforgeeks.org/write-a-c-program-to-print-all-permutations-of-a-given-string/
Don't get confused on recursion inside for loop.
if (index == x.length) is the terminating condition for recursion.
Inside the for loop before and after calling the recursive call possibleNumberselements are swapped.
Before swap helps to generate all possible outcomes and after swap elements will swap to previous position so that all other permutation will be generated from the for loop. It may sounds confusing please go through the link.
I'll provide an alternative explanation that I feel is more intuitive.
Consider the case of only 1 number in the list: [a]. This is pretty trivial: there's a single combination [a].
Now consider the case of 2 numbers in the list: [a, b]. In this case you can take each of the elements in turn and then look at all combinations of the remaining element using the previous method and then add the element back.
Now consider the case of 3 numbers in the list: [a, b, c]. In this case you can take each of the elements in turn and then look at all combinations of the other 2 elements using the previous method and then add the element back.
And so on for 3, 4, 5... elements.
So, in general, consider the case of n numbers in the list: [a1, a2, ... an]. In this case take each of the elements in turn and then look at all combinations of the other n-1 elements using the exact same method and then add the element back.
Converting to pseudo code:
getCombos(values)
for each value
for each combo in getCombos(values with value removed)
add value + combo to results
return results
The only thing to add is the base case which is necessary for all recursive implementations. One possibility is the case of a single item. However there's an even simpler one: if there are no values then the result is a single empty list.
So converting that to Java, using sets to make clear that the elements need to be unique (to avoid duplicate results), using streams and making it generic so it'll work for any type:
Stream<List<C>> combos(Set<C> values) {
if (values.isEmpty())
return Stream.of(new ArrayList<>());
else
return values.stream().flatMap(value ->
combos(values.stream()
.filter(v -> !v.equals(value))
.collect(toSet())).peek(r -> r.add(value)));
}
Your code is really just an alternate implementation of the same algorithm that swaps the element under consideration to the front of the array instead of creating a new collection.
I was confronted not so long ago to an algorithmic problem.
I needed to find if a value stored in an array was at it "place".
An example will be easier to understand.
Let's take an Array A = {-10, -3, 3, 5, 7}. The algorithm would return 3, because the number 3 is at A[2] (3rd place).
On the contrary, if we take an Array B = {5, 7, 9, 10}, the algorithm will return 0 or false or whatever.
The array is always sorted !
I wasn't able to find a solution with a good complexity. (Looking at each value individualy is not good !) Maybe it is possible to resolve that problem by using an approach similar to merge sorting, by cuting in half and verifying on those halves ?
Can somebody help me on this one ?
Java algorithm would be the best, but pseudocode would also help me a lot !
Here is an algorithm (based on binary search) to find all matching indices that has a best-case complexity of O(log(n)) and a worst case complexity of O(n):
1- Check the element at position m = array.length / 2
2- if the value array[m] is strictly smaller than m, you can forget about the left half of the array (from index 0 to index m-1), and apply recursively to the right half.
3- if array[m]==m, add one to the counter and apply recursively to both halves
4- if array[m]>m, forget about the right half of the array and apply recursively to the left half.
Using threads can accelerate things here. I suppose that there is no repetitions in the array.
Since there can be no duplicates, you can use the fact that the function f(x): A[x] - x is monotonous and apply binary search to solve the problem in O(log n) worst-case complexity.
You want to find a point where that function A[x] - x takes value zero. This code should work:
boolean binarySearch(int[] data, int size)
{
int low = 0;
int high = size - 1;
while(high >= low) {
int middle = (low + high) / 2;
if(data[middle] - 1 == middle) {
return true;
}
if(data[middle] - 1 < middle) {
low = middle + 1;
}
if(data[middle] - 1 > middle) {
high = middle - 1;
}
}
return false;
}
Watch out for the fact that arrays in Java are 0-indexed - that is the reason why I subtract -1 from the array.
If you want the find the first number in the array that is at its own place, you just have to iterate the array:
static int find_in_place(int[] a) {
for (int i=0; i<a.length; i++) {
if (a[i] == i+1) {
return a[i];
}
}
return 0;
}
It has a complexity of O(n), and an average cost of n/2
You can skip iterating if there is no such element by adding a special condition
if(a[0]>1 && a[a.length-1]>a.length){
//then don't iterate through the array and return false
return false;
} else {
//make a loop here
}
Using binary search (or a similar algorithm) you could get better than O(n). Since the array is sorted, we can make the following assumptions:
if the value at index x is smaller than x-1 (a[x] <= x), you know that all previous values also must be smaller than their index (because no duplicates are allowed)
if a[x] > x + 1 all following values must be greater than their index (again no duplicates allowed).
Using that you can use a binary approach and pick the center value, check for its index and discard the left/right part if it matches one of the conditions above. Of course you stop when a[x] = x + 1.
simply use a binary search for the 0 and use for compare the value in the array minus index of the array. O(log n)
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:)
I had an interview and there was the following question:
Find unique numbers from sorted array in less than O(n) time.
Ex: 1 1 1 5 5 5 9 10 10
Output: 1 5 9 10
I gave the solution but that was of O(n).
Edit: Sorted array size is approx 20 billion and unique numbers are approx 1000.
Divide and conquer:
look at the first and last element of a sorted sequence (the initial sequence is data[0]..data[data.length-1]).
If both are equal, the only element in the sequence is the first (no matter how long the sequence is).
If the are different, divide the sequence and repeat for each subsequence.
Solves in O(log(n)) in the average case, and O(n) only in the worst case (when each element is different).
Java code:
public static List<Integer> findUniqueNumbers(int[] data) {
List<Integer> result = new LinkedList<Integer>();
findUniqueNumbers(data, 0, data.length - 1, result, false);
return result;
}
private static void findUniqueNumbers(int[] data, int i1, int i2, List<Integer> result, boolean skipFirst) {
int a = data[i1];
int b = data[i2];
// homogenous sequence a...a
if (a == b) {
if (!skipFirst) {
result.add(a);
}
}
else {
//divide & conquer
int i3 = (i1 + i2) / 2;
findUniqueNumbers(data, i1, i3, result, skipFirst);
findUniqueNumbers(data, i3 + 1, i2, result, data[i3] == data[i3 + 1]);
}
}
I don't think it can be done in less than O(n). Take the case where the array contains 1 2 3 4 5: in order to get the correct output, each element of the array would have to be looked at, hence O(n).
If your sorted array of size n has m distinct elements, you can do O(mlogn).
Note that this is going to efficient when m << n (eg m=2 and n=100)
Algorithm:
Initialization: Current element y = first element x[0]
Step 1: Do a binary search for the last occurrence of y in x (can be done in O(log(n)) time. Let it's index be i
Step 2: y = x[i+1] and go to step 1
Edit: In cases where m = O(n) this algorithm is going to work badly. To alleviate it you can run it in parallel with regular O(n) algorithm. The meta algorithm consists of my algorithm and O(n) algorithm running in parallel. The meta algorithm stops when either of these two algorithms complete.
Since the data consists of integers, there are a finite number of unique values that can occur between any two values. So, start with looking at the first and last value in the array. If a[length-1] - a[0] < length - 1, there will be some repeating values. Put a[0] and a[length-1] into some constant-access-time container like a hash set. If the two values are equal, you konow that there is only one unique value in the array and you are done. You know that the array is sorted. So, if the two values are different, you can look at the middle element now. If the middle element is already in the set of values, you know that you can skip the whole left part of the array and only analyze the right part recursively. Otherwise, analyze both left and right part recursively.
Depending on the data in the array you will be able to get the set of all unique values in a different number of operations. You get them in constant time O(1) if all the values are the same since you will know it after only checking the first and last element. If there are "relatively few" unique values, your complexity will be close to O(log N) because after each partition you will "quite often" be able to throw away at least one half of the analyzed sub-array. If the values are all unique and a[length-1] - a[0] = length - 1, you can also "define" the set in constant time because they have to be consecutive numbers from a[0] to a[length-1]. However, in order to actually list them, you will have to output each number, and there are N of them.
Perhaps someone can provide a more formal analysis, but my estimate is that this algorithm is roughly linear in the number of unique values rather than the size of the array. This means that if there are few unique values, you can get them in few operations even for a huge array (e.g. in constant time regardless of array size if there is only one unique value). Since the number of unique values is no grater than the size of the array, I claim that this makes this algorithm "better than O(N)" (or, strictly: "not worse than O(N) and better in many cases").
import java.util.*;
/**
* remove duplicate in a sorted array in average O(log(n)), worst O(n)
* #author XXX
*/
public class UniqueValue {
public static void main(String[] args) {
int[] test = {-1, -1, -1, -1, 0, 0, 0, 0,2,3,4,5,5,6,7,8};
UniqueValue u = new UniqueValue();
System.out.println(u.getUniqueValues(test, 0, test.length - 1));
}
// i must be start index, j must be end index
public List<Integer> getUniqueValues(int[] array, int i, int j) {
if (array == null || array.length == 0) {
return new ArrayList<Integer>();
}
List<Integer> result = new ArrayList<>();
if (array[i] == array[j]) {
result.add(array[i]);
} else {
int mid = (i + j) / 2;
result.addAll(getUniqueValues(array, i, mid));
// avoid duplicate divide
while (mid < j && array[mid] == array[++mid]);
if (array[(i + j) / 2] != array[mid]) {
result.addAll(getUniqueValues(array, mid, j));
}
}
return result;
}
}