Related
How can I write a for loop that goes through an array and splits it into groups of 6. From there it should add the first group in the arrNumbers, then add the second group but reversed so { 6, 5, 4, 3, 2, 1 } to first group which is { 1, 2, 3, 4, 5, 6 } and then third group should be not reversed, but then if there is another group of 6, the set should be reversed to add. I don't know how to go about this. Any help will be appreciated. Below is my attempt
import java.util.Arrays;
public class arrayAdding{
public static void main(String []args){
int[] arrNumbers = new int[] { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6 };
int[] newArrNumbers = new int[6];
for(int i = 0; i < arrNumbers.length ; i++){
newArrNumbers[i < 6 ? i : (6 - (i % 6) - 1)] += arrNumbers[i];
}
System.out.println(Arrays.toString(newArrNumbers));
}
}
Actual Result from my code:
newArrNumbers = [13, 12, 11, 10, 9, 8]
The required result should be:
newArrNumbers = [8, 9, 10, 11, 12, 13]
You can think like group of 12 elements and not reversed for the first 6 and reversed for the next 6.
(i % 12) < 6 - First half - i % 6
(i % 12) >= 6 - Second half(reversed) - (6 - (i % 6) - 1)
Code:
newArrNumbers[(i % 12) < 6 ? i % 6 : (6 - (i % 6) - 1)] += arrNumbers[i];
You can refer below code:
import java.util.*;
public class ArrayAdding {
public static void main(String []args){
Integer[] arrNumbers = new Integer[] { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6 };
int[] newArrNumbers = new int[6];
List<List<Integer>> partitions = ArrayAdding.splitArray(arrNumbers);
Iterator<List<Integer>> itr = partitions.iterator();
while (itr.hasNext()) {
List<Integer> next = itr.next();
if (next.size() < 6 )
itr.remove();
}
for(int i = 0; i < partitions.size() ; i++){
if (i % 2 != 0) {
Collections.reverse(partitions.get(i));
}
}
for (List<Integer> partition : partitions) {
for (int j = 0; j < 6; j++) {
newArrNumbers[j] = partition.get(j) + newArrNumbers[j];
}
}
System.out.println(Arrays.toString(newArrNumbers));
}
private static List<List<Integer>> splitArray(Integer[] arrNumbers) {
int partitionSize = 6;
List<List<Integer>> partitions = new LinkedList<>();
List<Integer> originalList = Arrays.asList(arrNumbers);
for (int i = 0; i < originalList.size(); i += partitionSize) {
partitions.add(originalList.subList(i,
Math.min(i + partitionSize, originalList.size())));
}
return partitions;
}}
Given two arrays which represents a path and each element in the array represent the time it takes the driver to travel, write a method that chooses the fastest path he can take. The driver can switch paths only once between arrays.
For example the following arrays:
int[] road1 = new int[] { 5, 4, 5, 8, 12, 9, 9, 3 };
int[] road2 = new int[] { 7, 3, 3, 12, 10, 2, 10, 7 };
the output should be 49 since the driver will start at road2 and switch at index 6 to the second Array.
Edit:
My question is how do I make the recursion stop after switching to the other array? I tried to put a counter marker but it didn't work and I reverted back to my original output. Am I missing something about how recursion works?
My code prints 53 where it should print 49.
My code:
public class MyClass {
public static int shortestRoad(int[] road1, int[] road2) {
return shortestRoadNumbers(road1, road2, 0);
}
private static int shortestRoadNumbers(int[] road1, int[] road2, int index) {
if (index == road1.length || index == road2.length) {
return 0;
}
if (road1[index] >= road2[index] && road1[index + 2] >= road2[index + 2]) {
return (road2[index] + shortestRoadNumbers(road1, road2, index + 1));
} else {
return (road1[index] + shortestRoadNumbers(road1, road2, index + 1));
}
}
public static void main(String args[]) {
int[] road1 = new int[] { 5, 4, 5, 8, 12, 9, 9, 3 };
int[] road2 = new int[] { 7, 3, 3, 12, 10, 2, 10, 7 };
MyClass.shortestRoad(road1, road2);
int result = MyClass.shortestRoad(road1, road2);
System.out.println(result);
}
}
Let the following schema to illustrate your problem
We have two paths, and each path contain many nodes (values) , we can switch from one path to another just one time. Find the best combination of nodes (values) that minimise the score.
We can distinguish 4 cases:
1- the sum of the values of the first path without switching.
2-the sum of the values of the second path without switching.
3-the sum of the values from the first path until a node i, then switch to path second path from node i+1 (sum from node+1 til the end)
4-the inverse of the point 3.
static int shortestRoad(int road1[], int road2[])
{
// case 1
int bestValue = sumValues(road1,0);
// case 2
int sumValuesRoad2 = sumValues(road2,0);
if ( sumValuesRoad2 < bestValue)
bestValue = sumValuesRoad2;
// case 3: best values of all combination from road 1 to road 2
int bestValuesSwitchFromRoad1ToRoad2 = shortestRoad_Switch_RoadFrom_RoadTo(road1, road2);
if ( bestValuesSwitchFromRoad1ToRoad2 < bestValue)
bestValue = bestValuesSwitchFromRoad1ToRoad2;
// case 4: best values of all combination from road 2 to road 1
int bestValuesSwitchFromRoad2ToRoad1 = shortestRoad_Switch_RoadFrom_RoadTo(road2, road1);
if ( bestValuesSwitchFromRoad2ToRoad1 < bestValue)
bestValue = bestValuesSwitchFromRoad2ToRoad1;
return bestValue;
}
sum the values of a given array from idx til the end:
static int sumValues(int array[], int idx_from)
{
int sum = 0;
for (int i = idx_from; i<array.length; ++i)
sum += array[i];
return sum;
}
case 3 and 4:
static int shortestRoad_Switch_RoadFrom_RoadTo(int[] road_from, int[] road_to)
{
int sumValues_RoadFrom_til_idx = 0;
int sumValues_RoadFrom_idx_switch_RoadTo = 0;
int bestValue = Integer.MAX_VALUE;
for (int i = 0; i<road_from.length-1; ++i)
{
sumValues_RoadFrom_til_idx += road_from[i];
sumValues_RoadFrom_idx_switch_RoadTo = sumValues_RoadFrom_til_idx+sumValues(road_to,i+1);
if(sumValues_RoadFrom_idx_switch_RoadTo < bestValue )
bestValue = sumValues_RoadFrom_idx_switch_RoadTo;
}
return bestValue;
}
Driver code:
public static void main(String[] args)
{
int road1[] = { 5, 4, 5, 8, 12, 9, 9, 3 };
int road2[] = { 7, 3, 3, 12, 10, 2, 10, 7 };
int road_a[] = { 1, 1, 1, 1, 1, 9, 9, 9,9,9 };
int road_b[] = { 9, 9, 9, 9, 9, 1, 1, 1,1,1 };
int road_c[] = { 1, 1, 1, 1, 1, 2 };
int road_d[] = { 9, 9, 9, 9, 9, 1, 1, 1,1,1 };
System.out.println("best road1, road2 = "+shortestRoad(road1,road2));
System.out.println("best road_a, road_b = "+shortestRoad(road_a,road_b));
System.out.println("best road_c, road_d = "+shortestRoad(road_c,road_d));
return 0;
}
Results:
best road1, road2 = 49
best road_a, road_b = 10
best road_c, road_d = 7
ps:
the best path in your example is begin from road2 and then switch to road 1 at i=5 (i begin from 0)
{ 5, 4, 5, 8, 12, 9, -->9, 3 }
{ -->7, 3, 3, 12, 10, 2 /, 10, 7 }
public static int shortestRoad(int[]road1, int[]road2)
{
int sumRoad1Only = 0;
int sumRoad2Only = 0;
for(int i=0; i<road1.length; i++)
{
sumRoad1Only += road1[i];
sumRoad2Only += road2[i];
}
Those sums are for the option that the driver chooses one lane, and doesn't change it until the end. Now, we can find the switch index, for options like starting at one road, and switching to the other. In this specific question I realized that the best point of switch between the arrays - is where the difference between the two collected sums until a certain index is the largest. In your example, it is index 6. That doesn't say that switching a lane is always giving a smaller sum.
int roadIndex1 = road1.length-1;
int roadIndex2 = road2.length-1;
int totalSumRoad1 = sumRoad1Only;
int totalSumRoad2 = sumRoad2Only;
int max = 0;
int indexOfSwitch = 0;
int diff = 0;
while(roadIndex1 >=0 && roadIndex2 >=0)
{
diff = Math.abs(totalSumRoad2 - totalSumRoad1);
if(diff > max)
{
max = diff;
indexOfSwitch = roadIndex1;
}
totalSumRoad1 -= road1[roadIndex1];
totalSumRoad2 -= road2[roadIndex2];
roadIndex1--;
roadIndex2--;
}
If the index of switch is at last index, we shall move it one left, so there be a transition between the arrays.
if(indexOfSwitch == road1.length-1)
{
indexOfSwitch--;
}
now we found the indexOfSwitch, we can calculate the options of starting at road1, and switching exactly once to road2, and vice versa:
int begin1 = 0;
int begin2 = 0;
for(int k = 0; k<=indexOfSwitch; k++)
{
begin1 += road1[k];
begin2 += road2[k];
}
int end1 = sumRoad1Only - begin1;
int end2 = sumRoad2Only - begin2;
int begin1End2 = begin1 + end2;
int begin2End1 = begin2 + end1;
and when we find all the options, we can return the minimum.
return Math.min(Math.min(sumRoad1Only, sumRoad2Only), Math.min(begin1End2, begin2End1));
So I came across this problem in Java that wants to remove a list of number that has occurred more than twice but keeping the order, and the first two occurrences.
For example, if the list is 2, 3, 5, 4, 5, 2, 4, 3, 5, 2, 4, 4, 2, 10
the expected output would be 2, 3, 5, 4, 5, 2, 4, 3, 10
I've tried several methods, including using a counter int to keep track of the occurrences and filter it out, but I am not sure how I can go about it
class DeDup {
// function to find the element occurring more than 3 times
static void get2Occurrences(int arr[]) {
int i;
int count = 0;
for (i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length; j++) {
if (arr[i] == arr[j])
count++;
}
if (count < 3 && count > 0) {
//return arr[i];
System.out.print(arr[i] + ", ");
} else {
for (int k = 2; k > 0; k--) {
System.out.print(arr[i] + ", ");
}
}
}
}
// driver code
public static void main(String[]args) {
int arr[] = new int[]{ 2, 3, 5, 4, 5, 2, 4, 3, 5, 2, 4, 4, 2, 10 };
//expected output: 2, 3, 5, 4, 5, 2, 4, 3, 10
//int n = arr.length;
get2Occurrences(arr);
}
}
the expected output would be 2, 3, 5, 4, 5, 2, 4, 3, 10
but i got 2, 2, 3, 3, 5, 5, 4, 4, 5, 5, 2, 2, 4, 4, 3, 3, 5, 5, 2, 2, 4, 4, 4, 4, 2, 2, 10, 10,
I would do it using a pair of Sets: Set.add returns a boolean indicating whether the element was added. Hence:
boolean b = set1.add(num) || set2.add(num);
will be true if it was added into either set - and it will only try to add it to set2 if it was already in set1 - and false otherwise, meaning it was present in both sets already.
Set<Integer> set1 = new HashSet<>();
Set<Integer> set2 = new HashSet<>();
for (Integer a : arr) {
if (set1.add(a) || set2.add(a)) {
System.out.print(a + ", ");
}
}
Ideone demo
Keep track of the number of occurrences found for each element.
Something like this:
static void get2Occurrences(int arr[])
{
// Initialize occurrences found
Hashtable<Integer, Integer> found_elms = new Hashtable<Integer, Integer>();
// Loop over all elements
int counter;
int number;
Integer found;
for (counter = 0; counter < arr.length; counter++)
{
number = arr[counter];
found = found_elms.get(number);
if (found == null)
found = 1;
else
found = found + 1;
found_elms.put(number, found);
if (found < 3)
System.out.print(number + ", ");
}
System.out.println();
} // get2Occurrences
In this solution, you can change the number of repetitions from three to another.
int[] arr = new int[]{2, 3, 5, 4, 5, 2, 4, 3, 5, 2, 4, 4, 2, 10};
Map<Integer, Integer> counting = new HashMap<>();
for (Integer current : arr) {
int count = counting.compute(current, (x, n) -> n == null ? 1 : n + 1);
if (count < 3) {
System.out.print(current + ", ");
}
}
I would propose an insert filter : go through each element with a for loop and insert it into a response array if the response arrays doesnt contain it 2 times yet
import java.util.ArrayList;
import java.util.List;
...
List<Integer> lst = new ArrayList<>();
for (int i : arr) {
if (lst.lastIndexOf(i) == lst.indexOf(i)) {
lst.add(i);
}
}
return lst.stream().mapToInt(i -> i).toArray();
So this is what I came up with in the end
import java.util.ArrayList;
import java.util.Arrays;
class DeDup {
// function to find the element occurring more than 3 times
static void get2Occurrences(ArrayList<Integer> arr)
{
for(int i=0; i<arr.size(); i++){
int count=0;
for(int j=0; j<i; j++){
if(arr.get(j)==arr.get(i)){
count++;
}
}
if (count>=2){
arr.remove(i);
i--;
}
}
System.out.println("Output: "+arr);;
}
// driver code
public static void main(String[] args)
{
ArrayList<Integer> arr = new ArrayList<Integer>(Arrays.asList( 2, 3, 5, 4, 5, 2, 4, 3, 5, 2, 4, 4, 2, 10));
//expected output: 2, 3, 5, 4, 5, 2, 4, 3, 10
//int n = arr.length;
System.out.println("Input: "+arr);
get2Occurrences(arr);
}
}
Solution using Iteartor:
List<Integer> array = Lists.newArrayList(2, 3, 5, 4, 5, 2, 4, 3, 5, 2, 4, 4, 2, 10);
Map<Integer, Integer> control = new HashMap<>();
Iterator<Integer> iterator = array.iterator();
while(iterator.hasNext()) {
Integer element = iterator.next();
Integer occurrences = control.getOrDefault(element, 0);
if (occurrences >= 2) {
iterator.remove();
} else {
control.put(element, occurrences + 1);
}
}
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();
}
This question already has answers here:
Find the Smallest Integer Not in a List
(28 answers)
Closed 8 years ago.
This is an interview question, but I couldn't solve it in time, so posting it here:
Given a sorted array of n integers where each integer is in the range from 0 to m-1 and m > n. Find the smallest number that is missing from the array.
Examples
Input: {0, 1, 2, 6, 9}, n = 5,m = 10
Output: 3
Input: {4, 5, 10, 11}, n = 4, m = 12
Output: 0
The code for this is as follows:
int findFirstMissing(int array[], int start, int end) {
if(start > end)
return end + 1;
if (start != array[start])
return start;
int mid = (start + end) / 2;
if (array[mid] > mid)
return findFirstMissing(array, start, mid);
else
return findFirstMissing(array, mid + 1, end);
}
Now, the question is that input array can have duplicates also:
input = [0, 1, 1, 2, 3, 3, 4, 5, 5, 7]
output = 6
How do I solve it efficiently? What kind of optimizations can be applied?
It can be easily proved that you have to this in O(n) time, as you can't distinguish without checking every single value two tables:
1,2,_3_,4,5,7
and
1,2,_2_,4,5,7
This solution works in O(N) time and uses O(1) additional memory:
public class Test {
public static void main(String[] args) {
int m = 5;
int[] data = new int[] {0, 1, 1, 2, 3, 3, 4, 5};
int current = 0;
for (int i = 0; i < data.length; ++i) {
if (current == data[i]) {
current++;
}
}
if (current >= m) {
System.out.println("All is here");
} else {
System.out.println(current);
}
}
}
Note: n is actually ignored, I used data.length instead.
Solution
public static void main(String[] args) {
Collection<Integer> input = new LinkedList<Integer>(Arrays.asList(10, 9, 7, 6, 5, 4, 3, 2, 1));
NavigableSet<Integer> sortedOriginal = new TreeSet<Integer>(input);
NavigableSet<Integer> numbers = new TreeSet<Integer>();
for(int i=sortedOriginal.first();i<=sortedOriginal.last();i++){
numbers.add(i);
}
for(Integer x : numbers){
if(!sortedOriginal.contains(x)){
System.out.println(x);
break;
}
}
}