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;
}
}
}
Related
This is leetCode problem. I solved it using the following method but its giving stack overflow error.
Given an array of integers nums and an integer target.
Return the number of non-empty subsequences of nums such that the sum of the minimum and maximum element on it is less or equal than the target.
Since the answer may be too large, return it modulo 10^9 + 7.
Input: nums = [3,5,6,7], target = 9
Output: 4
Explanation: There are 4 subsequences that satisfy the condition.
[3] : Min value + max value <= target (3 + 3 <= 9)
[3,5] : (3 + 5 <= 9)
[3,5,6] : (3 + 6 <= 9)
[3,6] : (3 + 6 <= 9)
enter code here:
import java.lang.Math;
class Solution {
static int maxIndex=0;
static long M=1000000007;
public int numSubseq(int[] nums, int target) {
Arrays.sort(nums);
maxIndex=nums.length-1;
return numSubseq(nums,target,0);
}
public int numSubseq(int[] nums,int target, int i){
if(target==0 || nums.length==0 || i==nums.length)
return 0;
int res=0;
if(2*nums[i]<=target){
res=1;
if(nums[i]<nums[maxIndex]){
int j=maxIndex;
while(j>i){
if(nums[i]+nums[maxIndex]<=target)
break;
j--;
}
maxIndex=j;
if(nums[i]+nums[maxIndex]<=target && i!=maxIndex)
{
int diffIndex=maxIndex-i;
res+=Math.pow(2,diffIndex)-1;
}
}
}
else{
return 0;
}
return (int)((res+numSubseq(nums,target,i++))%M);
}
}``
I guess there would be a problem here in this line:
return (int)((res+numSubseq(nums,target,i++))%M);
We can solve the problem a bit easier though, similarly using sort, then two pointers.
Test with a b.java:
import java.util.*;
class Solution {
private static final int MOD = (int)1e9 + 7;
public static final int numSubseq(
final int[] nums,
final int target
) {
Arrays.sort(nums);
int[] pows = new int[nums.length];
pows[0] = 1;
int subsequences = 0;
int left = 0;
int right = nums.length - 1;
for (int index = 1 ; index < nums.length ; ++index) {
pows[index] = pows[index - 1] * 2;
pows[index] %= MOD;
}
while (left <= right) {
if (nums[left] + nums[right] > target) {
--right;
} else {
subsequences += pows[right - left++];
subsequences %= MOD;
}
}
return subsequences;
}
}
class b {
public static void main(String[] args) {
System.out.println(new Solution().numSubseq(new int[] {3, 5, 6, 7}, 9));
System.out.println(new Solution().numSubseq(new int[] {3, 3, 6, 8}, 10));
System.out.println(new Solution().numSubseq(new int[] {2, 3, 3, 4, 6, 7}, 12));
System.out.println(new Solution().numSubseq(new int[] {5, 2, 4, 1, 7, 6, 8}, 16));
}
}
prints
4
6
61
127
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));
I'm struggling to run this java correctly with a for each loop. It is fine for every test but the last. Could anyone kindly assist in letting me know where I'm going wrong? I feel confident I could do it with a for loop but would like to do it with a for each loop (if suitable).
Drill Question:
Given an array of ints, return true if the sequence of numbers 1, 2, 3 appears in the array somewhere.
arrayOneTwoThree([1, 1, 2, 3, 1]) -> true.
arrayOneTwoThree([1, 1, 2, 4, 1]) -> false.
arrayOneTwoThree([1, 1, 2, 1, 2, 3]) -> true.
For example:
int[] array = {2, 1, 2, 3, 2, 3, 2, 4, 1};
System.out.println(arrayOneTwoThree(array));
Result: true
public static void main(String[] args) {
//int[] array = {2, 1, 2, 3, 2, 3, 2, 4, 1};
//int[] array = {1, 1, 2, 3, 1};
//int[] array = {1, 1, 2, 4, 1};
int[] array = {1, 1, 2, 1, 2, 3};
System.out.println(arrayOneTwoThree(array));
}
public static boolean arrayOneTwoThree(int[] nums) {
for (int num : nums) {
//System.out.print(num);
if (nums[num] == 3 && nums[num-1] == 2 && nums[num-2] == 1)
return true;
}
return false;
}
In the loop, num is NOT the index within the array, it is the value.
I think you are expecting num to be the index, which would be the case if you did a for loop of the form for (int num =0; num < nums.length; num++)
If you want to compare n adiacent elements of array you have to use a loop ending to length - n - 1 : in your case n = 3 so your method can be written like below:
private static boolean arrayOneTwoThree(int[] array) {
final int n = array.length;
if (n < 3) { return false; } //<-- for arrays with less than 3 elements
for (int i = 0; i < n - 2; ++i) {
if (array[i] == 1 && array[i + 1] == 2 && array[i + 2] == 3) {
return true;
}
}
return false;
}
First tree test cases accidentally shoved correct result!
Your code works ONLY for cases, when index of 1 is 1, index of 2 is 2, and index of 3 is 3:
[*, 1, 2, 3, ......... ]
You are probably confused with another programming language. (Maybe for in construction of JavaScript?).
In Java for each over array (or anything else) iterates over values and never over indexes. (As was already specified)
I can see commented out System.out.print(num); why you've ignored it prints values not indexes?
Another issue is ignoring array bounds... Try to examine your code with next array:
int[] array = {2, 3, 2, 1, 2, 3};
It'll end up with ArrayIndexOutOfBoundsException
And answer for your question, how to solve with for each.
Yes, you can introduce external counter, but what would be the sense then?
public static boolean arrayOneTwoThree(int[] nums) {
int i = 0;
for (int num : nums) {
//System.out.print(num);
if (i < 2) continue; // we do not want ArrayIndexOutOfBoundsException happened, right?
if (nums[i] == 3 && nums[num-1] == 2 && nums[num-2] == 1)
return true;
}
return false;
}
If you wish to use for each you should avoid of using indexes to be consistent.
There could be tons of different solutions. You can use some flags or save previous and beforePrevious:
public static boolean arrayOneTwoThree(int[] nums) {
int beforePrevious;
int previous = 0;
int current = 0;
for (int num : nums) {
//System.out.print(num);
beforePrevious = previous;
previous = current;
current = num;
if (current == 3 && previous == 2 && beforePrevious == 1)
return true;
}
return false;
}
Beware: It's just first thought, so this solution may be not optimal and far from perfect, probably you can do better.
I'm trying to solve a problem on CodeFights called firstDuplicate, that states -
Given an array a that contains only numbers in the range from 1 to
a.length, find the first duplicate number for which the second
occurrence has the minimal index. In other words, if there are more
than 1 duplicated numbers, return the number for which the second
occurrence has a smaller index than the second occurrence of the other
number does. If there are no such elements, return -1.
Example
For a = [2, 3, 3, 1, 5, 2], the output should be firstDuplicate(a) =
3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3
has a smaller index than than second occurrence of 2 does, so the
answer is 3.
For a = [2, 4, 3, 5, 1], the output should be firstDuplicate(a) = -1.
My solution -
public class FirstDuplicate {
private static HashMap<Integer, Integer> counts = new HashMap<>();
private static void findSecondIndexFrom(int[] num, int n, int i) {
// given an array, a starting index and a number, find second occurrence of that number beginning from next index
for(int x = i; x < num.length; x++) {
if(num[x] == n) {
// second occurrence found - place in map and terminate
counts.put(n, x);
return;
}
}
}
private static int firstDuplicate(int[] a) {
// for each element in loop, if it's not already in hashmap
// find it's second occurrence in array and place number and index in map
for(int i = 0; i < a.length; i++) {
if(!counts.containsKey(a[i])) {
findSecondIndexFrom(a, a[i], i+1);
}
}
System.out.println(counts);
// if map is empty - no duplicate elements, return -1
if(counts.size() == 0) {
return -1;
}
// else - get array of values from map, sort it, find lowest value and return corresponding key
ArrayList<Integer> values = new ArrayList<>(counts.values());
Collections.sort(values);
int lowest = values.get(0);
//System.out.println(lowest);
for(Map.Entry<Integer, Integer> entries: counts.entrySet()) {
if(entries.getValue() == lowest) {
return entries.getKey();
}
}
return -1;
}
public static void main(String[] args) {
// int[] a = new int[]{2, 3, 3, 1, 5, 2};
//int[] a = new int[]{2, 4, 3, 5, 1};
//int[] a = new int[]{8, 4, 6, 2, 6, 4, 7, 9, 5, 8};
//int[] a = new int[]{1, 1, 2, 2, 1};
int[] a = new int[]{10, 6, 8, 4, 9, 1, 7, 2, 5, 3};
System.out.println(firstDuplicate(a));
}
}
This solution passes only for about 4 of the 11 test cases on CodeFights. However, I manually executed each one of the test cases in my IDE, and each one produces the right result.
I can't figure out why this won't work in CodeFights. Does it have something to do with the use of the static HashMap?
Edited: Since adding and checking if element is present in Set can be done in one step, code can be simplified to:
public static int findDuplicateWithLowestIndex(int... a){
Set<Integer> set = new HashSet<>();
for(int num : a){
if(!set.add(num)){
return num;
}
}
return -1;
}
You're completly right Patrick.
Use this solution: here duplicateIndex should be very large number.
package sample;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Duplicate {
public static Integer secondIndex(Integer[] arr) {
List<Integer> arrlist = new ArrayList<>(Arrays.asList(arr));
int duplicateIndex = 999;
int ele = 0;
for (int i = 0; i < arrlist.size(); i++) {
int secondIndex = getSecondIndex(arrlist, arrlist.get(i));
if (secondIndex >= 0 && duplicateIndex > secondIndex) {
duplicateIndex = secondIndex;
ele = arrlist.get(i);
}
}
return duplicateIndex == 999 ? -1 : ele;
}
public static int getSecondIndex(List<Integer> arr, int ele) {
List<Integer> var0 = new ArrayList<>(arr);
var0.set(var0.indexOf(ele), -1);
return var0.indexOf(ele);
}
public static void main(String[] str) {
// Integer[] arr = new Integer[] { 2, 3, 3, 1, 5, 2 };
// Integer[] arr = new Integer[] { 2, 4, 3, 5, 1 };
// Integer[] arr = new Integer[] { 8, 4, 6, 2, 6, 4, 7, 9, 5, 8 };
// Integer[] arr = new Integer[]{1, 1, 2, 2, 1};
Integer[] arr = new Integer[] { 10, 6, 8, 4, 9, 1, 7, 2, 5, 3 };
System.out.println(secondIndex(arr));
}
}
Solution in Javascript
function solution(a) {
const duplicates = [];
for (const i of a) {
if (duplicates.includes(i))
return i;
else
duplicates.push(i);
}
return -1;
}
console.log(solution([2, 1, 3, 5, 3, 2])); // 3
console.log(solution([2, 2])); // 2
console.log(solution([2, 4, 3, 5, 1])); // -1
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));
}
}
}
}