Big O Recursion with a Case Statement - java

I have this program which uses a case statement to switch from printing the array backward to printing it forwards mid recursion. If I were to write this iteratively, it would be one for loop with conditional logic (which can be ignored); thus, the Big O would be O(n). I would assume the same logic holds true for the recursive program as well, correct?
public static int recursion(int i, int j, String swap) {
int[] testList = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21};
if (j == 10) {
return testList[10];
}
if (i == 10 ) {
swap = "Yes";
}
switch (swap) {
case "No":
System.out.print(testList[i] + " ");
i -= 1;
break;
case "Yes":
System.out.print(testList[j] + " ");
j += 1;
break;
}
return recursion(i, j, swap);
}
public static void main(String[] args){
String swap = "No";
int i = 20;
int j = 0;
System.out.println(recursion(i, j, swap) + " ");
}
}

I simplified the code as follows to calculate its time complexity
public static void recursion(int[] testList, int i) { // O(n)
int len = testList.length; // O(1)
if(i >= len) return; // O(1)
int idx = i <= len / 2 ? len - 1 - i: i - len / 2; // O(1)
System.out.print(testList[idx] + " "); // O(1)
recursion(testList, i + 1); // O(n - 1)
}
public static void main(String[] args){
int[] testList = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21};
recursion(testList, 0);
}
If we create a recurrence relation than we can find its time complexity
T(n) = T(n - 1) + C (some constant time) (0 <= n < length)
T(n) = 1 (for n >= length)
We can simplify the equation
T(n) = T(n - 2) + 2C
= T(n - 3) + 3C
.
.
= T(n - (n - 1)) + (n - 1)C
= T(1) + (n - 1)C
= 1 + (n - 1)C
Which gives T(n) = O(n)

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

Small exercise for Java given two arrays which represents a path

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

Java program to find the number of combinations that four cards in a deck will equal 24

I have a program in Java that will take a deck of cards and calculate the number of combinations of four cards will equal 24. So far, I have this:
public class Assign5b {
public static void main(String[] args) {
int[] deck = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
int total;
total = calculate(deck);
output(total);
}
public static int calculate(int[] deck) {
int total = 0;
int stack1, stack2, stack3, stack4, accumulate;
for (stack1 = 0; stack1 < 52; stack1++) {
for (stack2 = (stack1 + 1); stack2 < 52; stack2++) {
for (stack3 = (stack2 + 1); stack3 < 52; stack3++) {
for (stack4 = (stack3 + 1); stack4 < 52; stack4++) {
accumulate = (deck[stack1] + deck[stack2] + deck[stack3] + deck[stack4]);
if (accumulate == 24)
total++;
}
}
}
}
return total;
}
public static void output(int total){
System.out.println ("The total number of card combinations of 4 that \n" + "equal 24 is: " + total);
}
}
So my problem is not that it doesn't run, or that it's not displaying the correct value, but it's those nested loops. I don't want them there. It's making it run really inefficiently and I know there's a better way to get it to run I just can't visualize it.
You could add checks at the beginning of each loop to see if the running total already be over 24. In this case, there would be no point in doing those loops anyway:
public static int calculate(int[] deck, int target) {
int total = 0;
int stack1, stack2, stack3, stack4, accumulate;
for (stack1 = 0; stack1 < 52; stack1++) {
if (deck[stack1] > target) break;
for (stack2 = (stack1 + 1); stack2 < 52; stack2++) {
if (deck[stack1] + deck[stack2] > target) break;
for (stack3 = (stack2 + 1); stack3 < 52; stack3++) {
if (deck[stack1] + deck[stack2] + deck[stack3] > target) break;
for (stack4 = (stack3 + 1); stack4 < 52; stack4++) {
if (deck[stack1] + deck[stack2] + deck[stack3] + deck[stack4] > target) break;
accumulate = (deck[stack1] + deck[stack2] + deck[stack3] + deck[stack4]);
if (accumulate == 24)
total++;
}
}
}
}
return total;
}
This assumes that your deck is sorted in ascending order, e.g.
int[] deck = {1, 1, 1, 1,
2, 2, 2, 2,
...
13, 13, 13, 13};

Find groups of continuous integers in a list in 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")
}

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

Categories