Small exercise for Java given two arrays which represents a path - java

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));

Related

A method which finds the smallest subarray that's greater than X returns wrong number

For example, {1, 4, 45, 6, 0, 19} and the number 51 should return 3, because the number of elements in the smallest subarray which together are greater than 51 are 3: {4,45,6}`.
{7, 2, 5, 10, 1} and the number 9 should return 1, because the number of the elements in the smallest subarray possible that is greater than 9 is {10}.
If array is null or empty, or the array has no subarray that is greater than the given number, the method has to return -1.
I'm not allowed to use array package from java.util.
My goal is to execute the method in O(n) time.
This is my code so far, if the array has no subarray greater than the given number, it returns an OutofBounds error.
Anyone has a clue?
public static int smallestSubSum(int arr[], int x) {
int left = 0, right = 1, smallest = 0;
int sum = arr[right];
for (int i = 1; i < arr.length; i++) {
if (sum > x)
smallest = left - right;
else
right++;
sum += arr[right];
if (sum > x && left - right < smallest) {
smallest = left - right;
left++;
} else
sum -= arr[left];
left++;
if (sum > x && left - right < smallest)
smallest = left - right;
}
return smallest;
}
Edit: Perhaps I should explain what I tried to do with my code, basically I wanted the sum to hold the first two elements in the code, and then compare with each 'if' iteration if the sum of the current elements are greater or less than X, if not I raise the right element to go further, if yes I erase the first element, the 'left' one.
The array of {1, 4, 45, 6, 0, 19} and the number 51 returns 2, even though the result should be 3. I don't know why, because my right reaches the index 3 which is 6 and the left one reaches index 1 which is 4, so the result should indeed be {4,45,6} but it doesn't get to it.
This is the best I could do.
Here are my test results.
[1, 4, 45, 6, 0, 19] -> 51
3
[7, 2, 5, 10, 1] -> 9
1
[1, 4, 45, 6, 0, 19] -> 200
-1
I just cycled through the array with a for loop. Whenever the total exceeded the X amount, I subtracted values until the total dropped below the X amount.
Here's the complete runnable code I tested with.
import java.util.Arrays;
public class SmallestSubarray {
public static void main(String[] args) {
int[] arr1 = new int[] { 1, 4, 45, 6, 0, 19 };
int x1 = 51;
System.out.println(Arrays.toString(arr1) + " -> " + x1);
System.out.println(smallestSubSum(arr1, x1));
int[] arr2 = new int[] { 7, 2, 5, 10, 1 };
int x2 = 9;
System.out.println(Arrays.toString(arr2) + " -> " + x2);
System.out.println(smallestSubSum(arr2, x2));
int[] arr3 = new int[] { 1, 4, 45, 6, 0, 19 };
int x3 = 200;
System.out.println(Arrays.toString(arr3) + " -> " + x3);
System.out.println(smallestSubSum(arr3, x3));
}
public static int smallestSubSum(int arr[], int x) {
if (arr == null || arr.length < 1) {
return -1;
}
int sum = 0;
int minCount = Integer.MAX_VALUE;
int index = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
while (sum > x) {
minCount = Math.min(i - index + 1, minCount);
sum -= arr[index];
index++;
}
}
return (minCount == Integer.MAX_VALUE) ? -1 : minCount;
}
}

Can someone please point out error for the code "Number of Subsequences That Satisfy the Given Sum Condition" which is giving stack overflow error

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

Array Processing (stretching) Method

I'm looking for a hint on how to solve this or where I am going wrong.
The question is as follows: Write a static method named stretch that accepts an array of integers as a parameter and returns a new array twice as large as the original, replacing every integer from the original array with a pair of integers, each half the original. If a number in the original array is odd, then the first number in the new pair should be one higher than the second so that the sum equals the original number. For example, if a variable named list refers to an array storing the values {18, 7, 4, 24, 11}, the call of stretch(list) should return a new array containing {9, 9, 4, 3, 2, 2, 12, 12, 6, 5}. (The number 18 is stretched into the pair 9, 9, the number 7 is stretched into 4, 3, the number 4 is stretched into 2, 2, the number 24 is stretched into 12, 12 and the number 11 is stretched into 6, 5.)
Test your code with the following class:
import java.util.*;
public class TestStretch {
public static void main(String[] args) {
int[] list = {18, 7, 4, 14, 11};
int[] list2 = stretch(list);
System.out.println(Arrays.toString(list)); // [18, 7, 4, 24, 11]
System.out.println(Arrays.toString(list2)); // [9, 9, 4, 3, 2, 2, 7, 7, 6, 5]
}
// your code goes here
}
This is currently what I have, but it is not quite working correctly... I have a feeling it is how i'm using int i and int j, but i'm not sure what to do to fix it so that it works as intended.
import java.util.*;
public class TestStretch {
public static void main(String[] args) {
int[] list = {18, 7, 4, 14, 11};
int[] list2 = stretch(list);
System.out.println(Arrays.toString(list)); // [18, 7, 4, 24, 11]
System.out.println(Arrays.toString(list2)); // [9, 9, 4, 3, 2, 2, 7, 7, 6, 5]
}
public static int[] stretch(int[] array){
int length = array.length;
int[] newArray = new int[array.length*2];
for(int i = 0; i< length; i=i+2){
int j = 0;
if(array[i] % 2 == 0){
newArray[i] = (array[j]/2);
newArray[i+1] = newArray[i];
j++;
} else{
newArray[i] = (array[j]/2);
newArray[i+1] = (newArray[i] + 1);
j++;
}
}
return newArray;
}
}
The output I get is:
[18, 7, 4, 14, 11]
[9, 9, 9, 9, 9, 10, 0, 0, 0, 0]
Instead of:
[18, 7, 4, 24, 11]
[9, 9, 4, 3, 2, 2, 7, 7, 6, 5]
There are a couple of mistakes:
The loop iterates only until half of the array, skipping elements by 2
The value of j is reset to 0 in each iteration
Also, the algorithm can be simplified:
For each index i in the input, you want to set in the destination at position 2 * i and 2 * i + 1.
The second value to set is simply the original value divided by 2, with integer truncation
The first value to set is the same as the second, +1 if the division by 2 leaves a remainder
With the above issues corrected, and the implementation simplified:
int[] newArray = new int[array.length * 2];
for (int i = 0; i < array.length; i++) {
newArray[2 * i] = array[i] / 2 + array[i] % 2;
newArray[2 * i + 1] = array[i] / 2;
}
return newArray;
First of all, if you are looping to the old array's length, don't increment i by 2.
If i increases by 1 each time, we need to figure out how to map the old array's index i to the new array's index. It is quite simple: the new array's indices are just i*2 and i*2+1.
Now j seems redundant because it always holds the same value as i, so you can remove that.
This is the full code:
int length = array.length;
int[] newArray = new int[array.length*2];
for(int i = 0; i< length; i++){
if(array[i] % 2 == 0){
newArray[i*2] = (array[i]/2);
newArray[i*2+1] = newArray[i*2];
} else{
newArray[i*2] = (array[i]/2);
newArray[i*2+1] = (newArray[i*2] + 1);
}
}
return newArray;
Three mistakes:
j should be initialized outside the for-loop
we should use j to record the new value into the new array
we should increment j upon every iteration in 2 - and we should increment i only by 1 (since we're using j to insert two item while we use i to iterate the original array):
int j = 0;
for(int i = 0; i< length; i++){
if(array[i] % 2 == 0){
newArray[j] = newArray[j+1] = array[i]/2;
} else{
newArray[j] = array[i]/2 + 1;
newArray[j+1] = array[i]/2;
}
j += 2;
}
Note: giving a variable that holds an array the name "list" might create confusion!
for(int i = 0; i< length; i=i+2){
length is the length of the original array, so you iterate only over half of the values because you increase i by 2 each step.
if(array[i] % 2 == 0){
This should be
if(array[j] % 2 == 0){
And because you define j within your for-loop, array[j] always returns 18. Oh and you set the second element of the tuple to be the higher one while your comment in the code says the contrary should take place.
So a fixed version of your method would look like this:
public static int[] stretch(int[] array){
int length = array.length;
int[] newArray = new int[array.length*2];
int j = 0;
for(int i = 0; i< newArray.length; i=i+2){
if(array[j] % 2 == 0){
newArray[i] = (array[j]/2);
newArray[i+1] = newArray[i];
} else{
newArray[i+1] = (array[j]/2);
newArray[i] = (newArray[i+1] + 1);
}
j++;
}
return newArray;
}
Avoiding duplicate code:
public static int[] stretch(int[] array){
int[] newArray = new int[array.length*2];
int j = 0;
for(int i = 0; i< newArray.length; i=i+2){
int val = array[j];
newArray[i] = (val/2);
newArray[i+1] = newArray[i];
if(val % 2 != 0){
newArray[i]++;
}
j++;
}
return newArray;
}
Or using fancy streams:
public static int[] stretch(int[] array){
return Arrays.stream(array)
.flatMap(elem -> {
int half = elem / 2;
int otherHalf = half;
if (elem % 2 != 0) {
half++;
}
return IntStream.of(half, otherHalf);
}).toArray();
}
}

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));
}
}
}
}

Find the smallest missing number with Duplicates [duplicate]

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;
}
}
}

Categories