Find groups of continuous integers in a list in Java - java

I have a list of integers placed in order.
I want to get groups of consecutive integers as arrays with 1st and last integer of each group.
For example, for (2,3,4,5,8,10,11,12,15,16,17,18,25) I want to get a list with those arrays: [2,5] [8,8] [10,12] [15,18] [25,25]
Here is my code:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MyRangesTest {
public static void main(String[] args) {
//create list of integers
List<Integer> list=Arrays.asList(2,3,4,5,8,10,11,12,15,16,17,18,25);
System.out.println("list:" + list);
//create a list with integers where a new sequense of consecutive integers starts or ends
List<Integer> sublistsStarsAndEnds= new ArrayList<>();
sublistsStarsAndEnds.add(list.get(0));//1st line (always in sublistsStarsAndEnds list)
for (int i=1; i<list.size()-1; i++){
if (list.get(i)>1+list.get(i-1)){
sublistsStarsAndEnds.add(list.get(i-1));
sublistsStarsAndEnds.add(list.get(i));
}
}
sublistsStarsAndEnds.add(list.get(list.size()-1));//last line (always in sublistsStarsAndEnds list)
System.out.println("sublistsStarsAndEnds: " + sublistsStarsAndEnds);//present the result
//create list with arrays that represents start and end of each subrange of consequent integers
List<Integer[]> ranges= new ArrayList<>();
for (int i=0; i<sublistsStarsAndEnds.size()-1; i=i+2){
Integer[] currentrange=new Integer[2];
currentrange[0]=sublistsStarsAndEnds.get(i);
currentrange[1]=sublistsStarsAndEnds.get(i+1);
ranges.add(currentrange);//present the result
}
//present the result
String rangestxt="";//create result text
for (int i=0; i<ranges.size(); i++){
rangestxt=rangestxt+ranges.get(i)[0]+ " " + ranges.get(i)[1]+ " ";
}
System.out.println("ranges: " + rangestxt);//present the result
}
}
This code works in the general case for what I want but when the last sequence has only 1 integer it fails to get the right result.
For example when using this list: (2,3,4,5,8,10,11,12,15,16,17,18,25) instead of getting the ranges [2,5] [8,8] [10,12] [15,18] [25,25] we get the ranges [2,5] [8,8] [10,12] [15,25].
The problem is with the detection of where the ranges start or end. In my code those places are stored in the sublistsStarsAndEnds list. Here instead of getting [2, 5, 8, 8, 10, 12, 15, 15, 25, 25] we get [2, 5, 8, 8, 10, 12, 15, 25].
I tried to correct the code but I without good results.
Any suggestions please?
P.S. Someone wanted to get the result I want and asked a question for Python here "Identify groups of continuous numbers in a list
But I don't know Python so I tried my own coding.

try this
public static void main(String[] args) {
List<Integer> list=Arrays.asList(2,3,4,5,8,10,11,12,15,16,17,18,19,25);
List<List<Integer>>lList=new ArrayList<List<Integer>>(); //list of list of integer
System.out.println("list:" + list);
int i=0;
int start=0;
List<Integer> sList=new ArrayList<Integer>(2);
for( i = 1; i <list.size();i++){
if( list.get(i - 1) + 1 != list.get(i)){
sList.add(list.get(start));
sList.add(list.get(i-1));
lList.add(sList);
sList=new ArrayList<Integer>(2);
start=i;
}
}
sList.add(list.get(start)); // for last range
sList.add(list.get(list.size()-1));
lList.add(sList);
System.out.println("Range :"+lList);
}
output :
list:[2, 3, 4, 5, 8, 10, 11, 12, 15, 16, 17, 18, 19, 25]
Range :[[2, 5], [8, 8], [10, 12], [15, 19], [25, 25]]

If I understand your question, you could write a POJO class Range like
static class Range {
private int start;
private int end;
Range(int start, int end) {
this.start = start;
this.end = end;
}
#Override
public String toString() {
return String.format("%d - %d", start, end);
}
}
Then your problem becomes adding a start to an end position where the end position is i-1 in list.get(i - 1) + 1 != list.get(i). Something like,
public static void main(String[] args) {
List<Integer> list = Arrays.asList(2, 3, 4, 5, 8, 10, 11, 12, 15, 16,
17, 18, 25);
System.out.println("list:" + list);
int start = 0;
List<Range> ranges = new ArrayList<>();
for (int i = 1; i < list.size(); i++) {
if (list.get(i - 1) + 1 != list.get(i)) {
ranges.add(new Range(list.get(start), list.get(i - 1)));
start = i;
}
}
ranges.add(new Range(list.get(start), list.get(list.size() - 1)));
System.out.println(ranges);
}
Output is (as requested)
[2 - 5, 8 - 8, 10 - 12, 15 - 18, 25 - 25]
I will point out that this is very nearly Run-length Encoding.

Elegant Solution:
static String pair(int[] array){
String res = "";
int i = 0, j = 1;
//loop through all items in array.
while(i < array.length){
//increase j while array[j] - array[j - 1] equals 1
while(j < array.length && array[j] - array[j - 1] == 1){
j++;
}
//we came out of that loop, no longer in a sequence.
//write to the output.
res += toTuple(i,j - 1, array);
//i now points to j.
//j is now i + 1;
i = j;
j = i + 1;
}
return res;
}
static String toTuple(int low, int high, int[] array){
return "[" + array[low] + "," + array[high] + "]";
}
Sample Input: {1, 2, 3, 6, 7,9,10,11,13,14,15,20}
Output: [1,3][6,7][9,11][13,15][20,20]

Another short answer in kotlin, Assuming no repetition in the list
list.fold(mutableListOf<MutableList<Int>>()) { acc, i ->
acc.also { outer ->
outer.lastOrNull()?.takeIf { it[1] + 1 == i }?.also {
it[1] = i
} ?: mutableListOf(i, i).also {
outer.add(it)
}
}
}

Here's a simple little algorithm that I sometimes adapt and use.
public void printRanges(int[] input) {
if (input.length == 0)
return;
// Only necessary if not already sorted
Arrays.sort(input);
int start = input[0];
int end = input[0];
for (int rev : input) {
if (rev - end > 1) {
// break in range
System.out.println("Range: [" + start + ", " + end + "]");
start = rev;
}
end = rev;
}
System.out.println("Range: [" + start + ", " + end+"]");
}

I'd like to contribute a solution written in kotlin:
#Test
fun test_extract_continuous_range() {
val inputList = listOf(0, 2, 3, 4, 5, 8, 10, 11, 12, 15, 16, 17, 18, 19, 25, 26, 27, 30)
println("Input: $inputList")
val result = mutableListOf<IntRange>()
result.add(inputList.first()..inputList.first()) // add the first item as the first range
inputList.windowed(2)
.map { w -> w.first() to w.second() } // optional map to Pair for convenient
.forEach { p ->
if (p.first + 1 == p.second) {
// same range, extend it
val updatedLastRange = result.last().start..p.second
result[result.lastIndex] = updatedLastRange
} else {
// new range
result.add(p.second..p.second)
}
}
println("Result: $result")
val sizes = result.map(IntRange::count)
println("Sizes: $sizes")
}

Related

Find the index of array where corruption begins

What will be the best solution to this question? (Less than O(n))
Given an array of positive integers where successive elements increase by 1
(except for a single element that does NOT increase by one--the start of the
"corruption"), return the index of where the corruption starts.
Example 1:
array: [5, 6, 7, 8, 12, 13] indices: 0 1 2 3 4 5
The corruption starts at index 4.
Example 2:
array: [5, 2, 3, 4, 5, 6] indices: 0 1 2 3 4 5
The corruption starts at index 1.
P.S. My solution was of O(n), also I tried to branch it in two parts still it will reduce half.
Hint: I was told I can use binary search.
Edit:
My solution was simply to iterate the array and see if difference is greater or less than one.
Try something like this
public class Main {
public static void main(String[] args) {
int[] nums = {5, 6, 7, 8, 12, 13};
int res = checkArray(nums, 0, nums.length - 1);
System.out.println("res = " + res);
}
public static int checkArray(int[] nums, int start, int end) {
if (end - start < 2) {
return end;
} else {
int middle = (start + end) / 2;
int a = nums[start];
int b = nums[middle];
if (b - a != middle - start) {
return checkArray(nums, start, middle);
} else {
return checkArray(nums, middle, end);
}
}
}
}
It use the fact that difference between first and last element of subarray is equal to its length if array do not have corruption.
public static void main(String[] args) {
// corruption starts at 13
int[] arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 16, 17};
int corruptionIndex = -1;
int start = 0;
int end = arr.length;
while (end - start > 1) {
int middle = (start + end) / 2;
// we add the first element onto our value as an offset
int expectedValue = middle + arr[0];
if (arr[middle] != expectedValue) {
// something has already gone wrong, let's check the first half
end = middle;
}
else {
// so far so good, let's check the second half
start = middle;
}
corruptionIndex = end;
}
System.out.println("Corruption Index: " + corruptionIndex);
}
var arr1 = [5, 9, 7, 8, 9, 13] ;
var arr2 = [5, 2] ;
var arr3 = [5, 6, 7, 8, 9, 13] ;
check(arr1);
check(arr2);
check(arr3);
function check(arr){
for(var i=1;i<arr.length;i++){
if(arr[i]-arr[i-1] !=1 ){
console.log('corroption begins at '+i);
break;
}
}
}
we can check for current and prev element difference , right. if diff is not 1, we need to break. its in js
O(n) is your only option. Binary search is O(log(n)) but that only works for searching for a specific number in a sorted list. You neither have a sorted list nor a specific number you are searching for
class FindCorruptionIndex
{
public static void main(String[] args)
{
int i,j;
int array[]={1,2,3,4,7,8,9};
System.out.print("The array is [ ");
for (int x :array )
{
System.out.print(x+",");
}
System.out.print("\b ] ");
System.out.println();
for(i=0;i<array.length-1;i++)
{
j=array[i+1]-array[i];
if (j>=2)
{
System.out.println("The corruption Index position is "+(i+1));
}
}
}
}

Java: Convert int[] to smallest representation as ranges

Given an array of int values, how could one parse the series into counting sequence notation?
Examples:
{1, 2, 3, 4, 5, 9, 13, 14, 15} -> "1-5,9,13-15"
{4, 6, 8, 10, 11, 12, 15, 17} -> "4,6,8,10-12,15,17"
I'm looking for a method that would produce these results. This is what I have so far, but I'm very much stumped at this point:
Test Code:
import java.util.Arrays;
public class TestSequencing {
public static void main(String[] args) {
int[] numbers1 = {1, 2, 3, 4, 5, 9, 13, 14, 15};
String numbers1s = "1-5,9,13-15";
System.out.println(Arrays.toString(numbers1));
System.out.println("Expected:\t" + numbers1s);
System.out.println("Produced:\t" + sequenceNums(numbers1) + "\n");
int[] numbers2 = {3, 5, 6, 9, 12};
String numbers2s = "3,5-6,9,12";
System.out.println(Arrays.toString(numbers2));
System.out.println("Expected:\t" + numbers2s);
System.out.println("Produced:\t" + sequenceNums(numbers2) + "\n");
int[] numbers3 = {1, 2, 3, 4, 5, 6, 7};
String numbers3s = "1-7";
System.out.println(Arrays.toString(numbers3));
System.out.println("Expected:\t" + numbers3s);
System.out.println("Produced:\t" + sequenceNums(numbers3) + "\n");
}
public static String sequenceNums(int[] nums) {
StringBuilder sb = new StringBuilder();
int rangeStart = nums[0];
int previous = nums[0];
int current;
int expected = previous + 1;
for (int i = 1 ; i < nums.length ; i++) {
current = nums[i];
expected = previous + 1;
if (current != expected || i == (nums.length - 1)) {
if (current == rangeStart) {
sb.append(previous + ",");
} else {
sb.append(rangeStart + "-" + previous + ",");
}
rangeStart = current;
}
previous = current;
}
if (sb.charAt(sb.length() - 1) == ',') {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
}
Output:
[1, 2, 3, 4, 5, 9, 13, 14, 15]
Expected: 1-5,9,13-15
Produced: 1-5,9-9,13-14
[3, 5, 6, 9, 12]
Expected: 3,5-6,9,12
Produced: 3-3,5-6,9-9
[1, 2, 3, 4, 5, 6, 7]
Expected: 1-7
Produced: 1-6
Try this:
private static void appendRange(StringBuilder sb, int begin, int end) {
sb.append(",").append(begin);
if (end != begin)
sb.append("-").append(end);
}
public static String sequenceNums(int[] nums) {
StringBuilder sb = new StringBuilder();
if (nums.length == 0) return sb.toString();
int begin = nums[0], end = nums[0];
for (int cur : nums)
if (cur - end <= 1)
end = cur;
else {
appendRange(sb, begin, end);
begin = end = cur;
}
appendRange(sb, begin, end);
return sb.substring(1);
}
#Test
public void testSequenceNums() {
assertEquals("1-5,9,13-15", sequenceNums(new int[] {1, 2, 3, 4, 5, 9, 13, 14, 15}));
assertEquals("4,6,8,10-12,15,17", sequenceNums(new int[] {4, 6, 8, 10, 11, 12, 15, 17}));
assertEquals("1-7", sequenceNums(new int[] {1, 2, 3, 4, 5, 6, 7}));
assertEquals("", sequenceNums(new int[] {}));
}
In the for loop you have two issues:
1) The second if should be if (previous == rangeStart) {
2) You're not dealing with the last number in the loop (where i == (nums.length - 1)).
I would do this with the following code:
public static String sequenceNums(int[] nums) {
StringBuilder sb = new StringBuilder();
int rangeStart = nums[0];
int previous = nums[0];
int current;
int expected = previous + 1;
int size = nums.length;
for (int i = 1 ; i < size ; i++) {
current = nums[i];
expected = previous + 1;
if (current != expected) {
addRange(sb, rangeStart, previous);
rangeStart = current;
}
previous = current;
}
addRange(sb, rangeStart, nums[size - 1]);
return sb.toString();
}
private void addRange(StringBuilder sb, int from, int to) {
if (sb.length() > 0) {
sb.append(",");
}
if (from == to) {
sb.append(from);
} else {
sb.append(from + "-" + to);
}
}
Here is your fixed code.
public class TestSequencing {
public static void main(String[] args) {
int[] numbers1 = {1, 2, 3, 4, 5, 9, 13, 14, 15};
String numbers1s = "1-5,9,13-15";
System.out.println(Arrays.toString(numbers1));
System.out.println("Expected:\t" + numbers1s);
System.out.println("Produced:\t" + sequenceNums(numbers1) + "\n");
int[] numbers2 = {3, 5, 6, 9, 12};
String numbers2s = "3,5-6,9,12";
System.out.println(Arrays.toString(numbers2));
System.out.println("Expected:\t" + numbers2s);
System.out.println("Produced:\t" + sequenceNums(numbers2) + "\n");
int[] numbers3 = {1, 2, 3, 4, 5, 6, 7};
String numbers3s = "1-7";
System.out.println(Arrays.toString(numbers3));
System.out.println("Expected:\t" + numbers3s);
System.out.println("Produced:\t" + sequenceNums(numbers3) + "\n");
}
public static String sequenceNums(int[] nums) {
StringBuilder sb = new StringBuilder();
int rangeStart = nums[0];
int previous = nums[0];
int current;
int expected = previous + 1;
for (int i = 1 ; i < nums.length ; i++) {
current = nums[i];
expected = previous + 1;
if (current != expected || i == (nums.length - 1)) {
if (current == rangeStart) {
sb.append(previous + ",");
} else {
if(rangeStart != previous) {
if(i == nums.length - 1)
sb.append(rangeStart + "-" + current);
else
sb.append(rangeStart + "-" + previous + ",");
} else {
if(i == nums.length - 1)
sb.append(rangeStart + "," + current);
else
sb.append(rangeStart + ",");
}
}
rangeStart = current;
}
previous = current;
}
if (sb.charAt(sb.length() - 1) == ',') {
sb.deleteCharAt(sb.length() - 1);
}
return sb.toString();
}
}
Problem was, if current is not same as range starting value, you need to check for two cases
i) if range was starting with the same previous value. If so, no need to have same number separated by range (ex: 9-9 doesn't make sense. only 9 does). Another case to be handled is end of array reached. In case end of array is reached, it should just be added at the end even thought it does not fall in any range
ii) other wise, range starts and ends with previous value if end of array is not reached. If end of array is reached that would be end value of range
I took the below approach to represent integer array in ranges.
Note: The numbers should be pre-sorted in ascending order.
We will have two variables start & current, which we will use in the iterations to identify the range. index will be the current index of the array.
Once a range is found, we will keep pushing it into the StringBuilder.
This is the Code:
// We will take this set of integers
int[] temp = new int[] { 0, 1, 4, 5, 8, 9, 11, 12, 13 };
// Helper variables
Integer start = null, current = null;
// The found range(s) will be stored in this variable.
StringBuilder rangeBuilder = new StringBuilder();
// The current index of the array in iteration
int index = 0;
do {
// During the first iteration both start & current will be null. So setting the current index value to them.
if (start == null) {
start = current = temp[index];
} else {
// Checking if the index value is the next number of current.
if (temp[index] == (current + 1)) {
current = temp[index];
} else {
if (start == current) {
rangeBuilder.append(start + ",");
} else {
rangeBuilder.append(start + "-" + current + ",");
}
start = current = temp[index];
}
}
// Checking if we have reached the end of the array.
if (index + 1 == temp.length) {
if (start == current) {
rangeBuilder.append(start);
} else {
rangeBuilder.append(start + "-" + current);
}
}
} while (index++ < temp.length - 1);
// Printing the range.
System.out.println("Range: " + rangeBuilder.toString());
Explanation:
We are taking this example:
{ 0, 1, 4, 5, 8, 9, 11, 12, 13 }
Note: We will represent start -> s & current -> c
Iteration-1:
Entry: start = null, current = null, rangeBuilder = ""
sc
0, 1, 4, 5, 8, 9, 11, 12, 13
^
Is the index value the next number of current ? No
Has the index reached the last element ? No
Exit: start = 0, current = 0, rangeBuilder = ""
Iteration-2:
Entry: start = 0, current = 0, rangeBuilder = ""
s c
0, 1, 4, 5, 8, 9, 11, 12, 13
^
Is the index value the next number of current ? Yes. So we move c from 0 -> 1.
Has the index reached the last element ? No
Exit: start = 0, current = 1, rangeBuilder = ""
Iteration-3:
Entry: start = 0, current = 1, rangeBuilder = ""
sc
0, 1, 4, 5, 8, 9, 11, 12, 13
^
Is the index value the next number of current ? No. So we push s and c into the String Builder (rangeBuilder). While pushing, we check if s and c are same to avoid duplicates. Then we move s & c to the index value.
Has the index reached the last element ? No
Exit: start = 4, current = 4, rangeBuilder = "0-1,"
Iteration-4:
Entry: start = 4, current = 4, rangeBuilder = "0-1,"
s c
0, 1, 4, 5, 8, 9, 11, 12, 13
^
Is the index value the next number of current ? Yes. So we move c from 4 -> 5.
Has the index reached the last element ? No
Exit: start = 4, current = 5, rangeBuilder = "0-1,"
Iteration-5:
Entry: start = 4, current = 5, rangeBuilder = "0-1,"
sc
0, 1, 4, 5, 8, 9, 11, 12, 13
^
Is the index value the next number of current ? No. So we push s and c into the String Builder (rangeBuilder). While pushing, we check if s and c are same to avoid duplicates. Then we move s & c to the index value.
Has the index reached the last element ? No
Exit: start = 8, current = 8, rangeBuilder = "0-1,4-5,"
Iteration-6:
Entry: start = 8, current = 8, rangeBuilder = "0-1,4-5,"
s c
0, 1, 4, 5, 8, 9, 11, 12, 13
^
Is the index value the next number of current ? Yes. So we move c from 8 -> 9.
Has the index reached the last element ? No
Exit: start = 8, current = 9, rangeBuilder = "0-1,4-5,"
Iteration-7:
Entry: start = 8, current = 9, rangeBuilder = "0-1,4-5,"
sc
0, 1, 4, 5, 8, 9, 11, 12, 13
^
Is the index value the next number of current ? No. So we push s and c into the String Builder (rangeBuilder). While pushing, we check if s and c are same to avoid duplicates. Then we move s & c to the index value.
Has the index reached the last element ? No
Exit: start = 11, current = 11, rangeBuilder = "0-1,4-5,8-9,"
Iteration-8:
Entry: start = 11, current = 11, rangeBuilder = "0-1,4-5,8-9,"
s c
0, 1, 4, 5, 8, 9, 11, 12, 13
^
Is the index value the next number of current ? Yes. So we move c from 11 -> 12.
Has the index reached the last element ? No
Exit: start = 11, current = 12, rangeBuilder = "0-1,4-5,8-9,"
Iteration-9:
Entry: start = 11, current = 12, rangeBuilder = "0-1,4-5,8-9,"
s c
0, 1, 4, 5, 8, 9, 11, 12, 13
^
Is the index value the next number of current ? Yes. So we move c from 12 -> 13.
Has the index reached the last element ? Yes. So we push s and c into the String Builder (rangeBuilder). While pushing, we check if s and c are same to avoid duplicates.
End of iteration. The String Builder (rangerBuilder) will have this value: 0-1,4-5,8-9,11-13
Feel free to improve this code :)
I was able to solve your problem by introducing a boolean flag and reworking the method to test for consecutive numbers. If the current and next numbers are consecutive, inRangeFlag is triggered for the next iteration. See the code comments below for further breakdown:
public static String sequenceNums(int[] nums) {
StringBuilder sb = new StringBuilder();
int current;
int next;
boolean inRangeFlag = false;
for (int i = 0; i < nums.length; i++) {
current = nums[i];
// TRUE: if element is not last element, because last number is
// always appended.
if (i < nums.length - 1) {
next = nums[i + 1];
// TRUE: if current element and next are consecutive
if (next - current == 1) {
// If rangeflag is false, the current number is the start
// of a range. Append the number with hyphen.
if (!inRangeFlag) {
sb.append(current + "-");
}
// Trigger inRange Flag for next iteration.
inRangeFlag = true;
} else {
sb.append(current + ",");
inRangeFlag = false; // Turn flag false because not inRange.
}
} else {
sb.append(current);
}
}
return sb.toString();
}

Java program to group consecutive number from given numbers in a list<list>

Suppose you are given unique numbers like
11,2,7,6,17,13,8,9,3,5,12
The result will be group of numbers list containing sub list i.e.,
[2,3]-[5,6,7,8,9]-[11,12,13]-[17]
I took this approach to solve this below:
int[] a = { 11, 2, 7, 6, 13,17, 8, 9, 3, 5, 12 };
Arrays.sort(a);
List<List<Integer>> ListMain = new ArrayList<>();
List<Integer> temp = new ArrayList<>();
for (int i = 0; i < a.length; i++) {
if (a[i + 1] == a[i] + 1) {
temp.add(a[i + 1]);
} else {
ListMain.add(temp);
temp.clear();
}
}
Your overall logic is mostly correct. You have a few problems in your execution, though.
You get an array index out of bounds exception because you call a[i+1] when i = a.length. Change the loop condition to a.length - 1.
You need to use a new inner ArrayList each time, otherwise each array will get wiped out. Change temp.clear(); to temp = new ArrayList<>();.
You need to initialize the new list to the first element, not the empty list. Add temp.add(a[0]); at the beginning and temp.add(a[i+1]) when you've detected you need a new sublist.
You need to add the final list at the end, because your condition won't get called at the end of the loop.
Here's the modified program:
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
public class SubList {
public static void main(String... args) {
int[] a = { 11, 2, 7, 6, 13,17, 8, 9, 3, 5, 12 };
Arrays.sort(a);
List<List<Integer>> ListMain = new ArrayList<>();
List<Integer> temp = new ArrayList<>();
temp.add(a[0]);
for (int i = 0; i < a.length - 1; i++) {
if (a[i + 1] == a[i] + 1) {
temp.add(a[i + 1]);
} else {
ListMain.add(temp);
temp = new ArrayList<>();
temp.add(a[i+1]);
}
}
ListMain.add(temp);
System.out.println(ListMain);
}
}
Output:
[[2, 3], [5, 6, 7, 8, 9], [11, 12, 13], [17]]
Thanks Garis M Suero for your suggestion after which i got answer
int[] a = { 11, 2, 7, 6, 13,17, 8, 9, 3, 5, 12 };
Arrays.sort(a);
List<List<Integer>> listMain = new ArrayList<List<Integer>>();
List<Integer> temp = new ArrayList<>();
for (int i = 0; i < a.length; i++) {
if ((i + 1<a.length)&&( a[i] + 1==a[i + 1])) {
temp.add(a[i]);
} else {
temp.add(a[i]);
listMain.add(temp);
temp = new ArrayList<>();
}
}
for (List<Integer> lstI : listMain) {
for (Integer i : lstI) {
System.out.println(i);
}
System.out.println("================");
}

Grouping an array of integers that skip numbers in Java

Say I have the following int array:
[1,2,3,6,7, 8, 9,20, 22]
I'd like to be able to display to the user the following based off the above array:
Numbers 1 through 3, 6 through 9, 20, 22
How could I go about doing this? Essentially checking if the number previous equals the current number - 1? Guess I just answered my own question, but any shortcuts/pointers would be welcome.
Note: only dealing with integers, nothing negative (wouldn't be an integer would it).
A live example using Ideone can be found here. Runs in O(n) time.
Integer[] A = {1, 2, 3, 6, 7, 8, 9, 20, 22};
int start = 0, end;
System.out.print("Numbers ");
while((end = start) < A.length){
// Increment the 'end' pointer while consecutive numbers exist.
while(end + 1 < A.length && A[end + 1] == A[end] + 1) end++;
// If end == start: 'A[start]'
// Else : 'A[start] through A[end]'
System.out.print(A[start] +
(end == start ? "":(" through " + A[end])) +
(end < A.length - 1 ? ", ":""));
// Increment start pointer to next element in A
start = end + 1;
}
Not the best looking code, but works:
public static void display(int[] input) {
String out = "Numbers ";
int first = input[0];
int last = -1;
int older = first;
for (int i : input) {
if (i == older + 1) {
last = i;
older++;
} else if (i > older + 1) {
out += last > first ? first + " through " + last + ", " : first + ", ";
first = i;
older = i;
}
if (i == input[input.length - 1]) {
out += last > first ? first + " through " + last : first;
}
}
System.out.println(out);
}
Example:
int[] in1 = { 1, 2, 3, 6, 7, 8, 9, 20, 22 };
int[] in2 = { 1, 2, 3, 6, 7, 8, 9, 20, 21, 22 };
display(in1);
display(in2);
Outputs:
Numbers 1 through 3, 6 through 9, 20, 22
Numbers 1 through 3, 6 through 9, 20 through 22
Try something like:
int[] numberArray = [1, 2, 3, 6, 7, 8, 9, 20, 22];
int rangeStart = -999;
int rangeEnd = -999;
for (int n : numberArray) {
if (n > rangeEnd + 1) {
if (rangeEnd = -999) {
System.out.print("Numbers ");
else if (rangeEnd > rangeStart) {
System.out.printf("%d through %d, ", rangeStart, rangeEnd);
} else {
System.out.printf("%d, ", rangeEnd);
}
rangeStart = rangeEnd = n;
} else {
rangeEnd = n;
}
}
if (rangeEnd > rangeStart) {
System.out.printf("%d through %d, ", rangeStart, rangeEnd);
} else {
System.out.printf("%d,", rangeEnd);
}
Might need some fine-tuning regarding the use of commas and newlines.
Sorry for my terrible formatting, just some psuedocode you can think about.
for(int i = 0; i < length; i++){
start = int[i]
compare int[i] to int[i+1] {
if true, store as end, compare to next in array
else, break out
}
if start != end, print start through end
else, print start
}
**edit: and increment i to be the last + 1

Java Interview Task: Complete the Java method for a sorted array [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Find a pair of elements from an array whose sum equals a given number
I was recently presented with the following Java interview question.
The target is to complete the method task with only a single pass over the input array.
I claimed it is not possible to complete this task on a single pass over the array but I was met with the usual silence, pause and then the interviewer proclaimed the interview was at an end without giving me the answer.
public class SortedArrayOps {
public SortedArrayOps() {
}
// Print at the system out the first two ints found in the sorted array: sortedInts[] whose sum is equal to Sum in a single pass over the array sortedInts[] with no 0 value allowed.
// i.e. sortedInts[i] + sortedInts[?] = Sum where ? is the target index to be found to complete the task.
static void PrintIntSumValues(int Sum, int sortedInts[]) {
// need to test to see if the Sum value is contained in the array sortedInts. And, if not do nothing.
for(int i=0; i<sortedInts.length; i++) {
// ... do some work: algebra and logic ...
// System.out.println sortedInts[i]+sortedInts[?] sums to Sum.
}
}
public static void main(String[] args) {
final int[] sortedArray = {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};
PrintIntSumValues(48, sortedArray);
}
}
I am not sure which values in the array you are looking for (what does "first two" ints mean? Minimum sum of their indices? One is smallest? Any two that happen to pop out first?), but this solution is O(n), takes one pass, uses no additional data structures, and only uses one extra int. It does not always find the two indices closest together, nor does it always find the "first", whatever that might mean. I believe that it will always find the two whose sum is smallest (until you guys find a counter example).
Let me know if you guys find any bugs with it:
class Test {
public static void main(String[] args) {
int[] sortedArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
PrintIntSumValues(6, sortedArray);
sortedArray = new int[] {1, 2,3, 12, 23423};
PrintIntSumValues(15, sortedArray);
sortedArray = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
PrintIntSumValues(100, sortedArray);
sortedArray = new int[] {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};
PrintIntSumValues(48, sortedArray);
}
// Print at the system out the first two ints found in the sorted array: sortedInts[] whose sum is equal to Sum in a single pass over the array sortedInts[] with no 0 value allowed.
// i.e. sortedInts[i] + sortedInts[?] = Sum where ? is the target index to be found to complete the task.
static void PrintIntSumValues(int Sum, int sortedInts[]) {
// need to test to see if the Sum value is contained in the array sortedInts. And, if not do nothing.
int offset = sortedInts.length-1;
for(int i=0; i<sortedInts.length; i++) {
// ... do some work: algebra and logic ...
if ((sortedInts[i] + sortedInts[offset]) == Sum){
System.out.println("sortedInts[" + i + "]+sortedInts[" + offset + "] sums to " + Sum + ".");
return;
} else {
int remaining = Sum - sortedInts[i];
if (remaining < sortedInts[i] ){
// We need something before i
if (remaining < sortedInts[offset]) {
// Even before offset
offset = 0 + (offset - 0)/2;
} else {
// Between offset and i
offset = offset + (i - offset)/2;
}
} else {
// We need something after i
if (remaining < sortedInts[offset]) {
// But before offset
offset = i + (offset - i)/2;
} else {
// Even after offset
offset = offset + (sortedInts.length - offset)/2;
}
}
}
}
System.out.println("There was no sum :(");
}
}
You can view the output here.
import java.util.HashMap;
public class SortedArrayOps {
public SortedArrayOps() {
}
// Print at the system out the first two ints found in the sorted array: sortedInts[] whose sum is equal to Sum in a single pass over the array sortedInts[] with no 0 value allowed.
// i.e. sortedInts[i] + sortedInts[?] = Sum where ? is the target index to be found to complete the task.
static void PrintIntSumValues(int Sum, int sortedInts[]) {
HashMap<Integer, Boolean> pool= new HashMap<Integer, Boolean> ();
for(int i=0; i<sortedInts.length; i++) {
int current = sortedInts[i];
int target = Sum - current;
if (pool.containsKey(target)) {
System.out.println(String.format("%d and %d sum to %d", current, target, Sum));
break;
}
else {
pool.put(current, Boolean.TRUE);
}
}
}
public static void main(String[] args) {
final int[] sortedArray = {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};
PrintIntSumValues(48, sortedArray);
}
}
Here is a complete solution using a HashMap:
import java.util.HashMap;
public class Test
{
public static void main(String[] args)
{
final int[] sortedArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = 6;
printSum(sum, sortedArray);
}
private static void printSum(int sum, int[] sortedArray)
{
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int index = 0; index < sortedArray.length; index++)
{
int currentNumber = sortedArray[index];
int remainder = sum - currentNumber;
if (map.containsKey(remainder))
{
System.out.println(String.format("%d + %d = %d", currentNumber, remainder, sum));
break;
}
else
{
map.put(currentNumber, index);
}
}
}
}
This should work. You have two pointers, and make only a single pass through the data.
j = sortedInts.length - 1;
for(int i=0; i<sortedInts.length && j>=i; i++) {
sx = sortedInts[i];
while (sx + sortedInts[j] > Sum)
j++;
if (sx + sortedInts[j] == Sum)
...
}
Because the array of values is specific, the solution can be simplified as this,
public class SortedArrayOps {
public SortedArrayOps() {
}
// Print at the system out the first two ints found in the sorted array:
// sortedInts[] whose sum is equal to Sum in a single pass over the array
// sortedInts[] with no 0 value allowed.
// i.e. sortedInts[i] + sortedInts[?] = Sum where ? is the target index to
// be found to complete the task.
static void PrintIntSumValues(int Sum, int sortedInts[]) {
// need to test to see if the Sum value is contained in the array
// sortedInts. And, if not do nothing.
for (int i = 0; i < sortedInts.length; i++) {
// ... do some work: algebra and logic ...
// System.out.println sortedInts[i]+sortedInts[?] sums to Sum.
int remainder = Sum - sortedInts[i];
if( remainder <= sortedInts.length && remainder>0 && remainder!=sortedInts[i]) {
System.out.print(String.format("%d + %d = %d", sortedInts[i], sortedInts[remainder-1], Sum));
break;
}
}
}
public static void main(String[] args) {
final int[] sortedArray = { 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 };
PrintIntSumValues(48, sortedArray);
}
}

Categories