How to reduce time complexity of the code? - java

I have given a queue initial positions increment by 1 from 1 at the front of the line to n at the back.
Any person in the queue can bribe the person directly in front of them to swap positions. If two people swap positions, they still wear the same sticker denoting their original places in line. One person can bribe at most two others. For example, if n = 8 and Person 5 bribes Person 4, the queue will look like this:1,2,3,5,4,6,7,8.
minimumbribes must print an integer representing the minimum number of bribes necessary to create the original queue, or Too chaotic if the line configuration is not possible. If no of bribes for a person exceeds to 2 then the line configuration is not possible.
minimumBribes has the following parameter(s):
q: an array of integers.
1 <= n <= 100000.
Sample Input
2
5
2 1 5 3 4
5
2 5 1 3 4
Output
3
Too chaotic
Using the sorting logic I have just counted the person that comes early and are greater than following person. And it also prints the total no of bribes if the line configuration is possible else it prints Too chaotic message.
static void minimumBribes(int[] q) {
int count = 0; // Counts the no of bribes by an individual.
int j;
int total = 0; // Total no of bribes.
loop1 : for(int i = 0; i < q.length; i++) {
loop2 : for(j = i; j < q.length; j++) {
if(q[i] > q[j]) {
count++;
if(count > 2) {
System.out.println("Too chaotic");
break loop1;
}
}
else if (q[i] <= q[j]) {
total += count;
count = 0;
}
}
}
if(count <= 2)
System.out.println(total);
}
The upper mentioned code runs perfectly for a small queue but if an array has a large size, It exceeds the fixed time limit for processing.

I just solved this in python to get a better understanding of the problem.
I decided to start with the last person in the queue because there are a number of things we can immediately say about this person:
They can only bribe forward (i.e. they have no one behind them to bribe them)
They cannot bribe to be more than two positions away from the "EOQ" [, where EOQ means end of queue or initial position of this person].
We can apply this rule to everyone starting from person N to person 1.
Pseudocode:
FOR PERSON in [N to 1]:
P = PERSON
IF (P MORE THAN 2 POSITIONS FROM INITIAL POS; OR P IS FURTHER BACK IN QUEUE):
PRINT 'Too chaotic'
RETURN
FOR POS in [CURR_POS[P] to INIT_POS[P]]:
SWAP POSITION OF P AND PERSON_TO_THE_RIGHT_OF_P
INCREMENT COUNT OF BRIBES BY 1
PRINT COUNT_OF_BRIBES
Notes
INIT_POS[P] refers to the initial position of the person before any bribes took place, so INIT_POS[PERSON_5] = 5
CURR_POS[P] refers to the current position of P at the start of the algorithm or after any swaps.
At the end of this algorithm, (assuming the bribes were not chaotic) the following invariant should hold: CURR_POS[i] == i. The reason is because all we are doing is moving all the people back to their original positions before any bribes took place.

static void minimumBribes(int[] q) {
int count = 0; // Counts the no of bribes by an individual.
int total = 0; // Total no of bribes.
loop1 : for(int i = 0; i < q.length; i++) {
if((q[i]-(i+1))>2){//original position i should be person i+1
System.out.println("Too chaotic");
break loop1;
}
else if((q[i]-(i+1))>0){
count=q[i]-(i+1);
total += count;
count = 0;
}
}
if(count <= 2) //not sure what dose this sentence do?
System.out.println(total);
}
Is this what you ask? Not sure I understand you correctlly

Related

Reduce time complexity of game program

Adam wants to watch a football game from the top of the building that is arranged in a straight line.
Adam can watch the football match from the top of ith building if
there exists a maximum of K[i] buildings in front of Adam with a
height less than or equal to the height of ith building.
If there is any building in front of Adam with a height more than
the height of ith position building then he cannot see the match
from this ith building.
Count the positions of buildings where Adam can see the match from the top of the buildings.
Example:
Both arrays have the same length.
B (Buildings) = [2,1,3] represents the height of buildings
K = [1,2,1]
Answer:
1
Explanation:
For B[0] = 2 we have K[0] = 1. The number of buildings in front of it that have a height smaller than or equal to 2 is 0. This is <= K[0] So Adam can see the match.
For B[1] = 1, we have K[1] = 2. The number of buildings in front of it that have a height smaller than or equal to 1 is 0. But B[0] = 2 so Adam cannot see the match.
For B[2] = 3, we have K[2] = 1. The number of buildings in front of it that have a height smaller than or equal to 3 is 2. But this value is >= K[2] i.e 1 so Adam cannot see the match
The total positions where Adam can see the match is 1.
Constraints:
Array size is 1 to 10^5
Each element in Arrays is 1 to 10^5
This is the code I tried with the time complexity of O(n^2):
public static int process(int[] buildings, int[] K) {
int n = buildings.length;
int answer = 0;
for(int i=0; i<n; i++) {
int count = 0;
boolean valid = true;
for(int j=i-1; j>=0; j--) {
if(buildings[j] <= buildings[i]) count++;
if (buildings[j] > buildings[i]) {
valid = false;
break;
}
}
if(valid && count <= K[i]) answer++;
}
return answer;
}
This program works for arrays of small size but fails for large arrays as the time complexity of my program is O(n^2).
What is the better approach to solve this and how can we reduce the time complexity?
you have 2 conditions which we look on one by one but we'll start from the second:
The second condition can be interpreted as if ith building is the highest building from any other building in front of it. this can be achieved by checking the max hight to the ith position and update it as you go.
if the second condition is true that's means you have i-1 buildings in front of the ith building that are equal or smaller than it (i instead of i-1 if you start to count from 0 like in array). so the first condition would be true only if k[i] is bigger than (i-1) you just need to compare between them.
here is the code in java:
import java.util.*;
class HelloWorld {
public static void main(String[] args) {
List<Integer> buildings = Arrays.asList(2, 1, 3);
List<Integer> K = Arrays.asList(1, 2, 1);
System.out.println(process(K, buildings));
}
public static Integer process(List<Integer> K, List<Integer> buildings){
Integer maxHightBuilding = buildings.get(0);
Integer sum = 0;
for(Integer i = 0; i < buildings.size(); i++){
if(buildings.get(i) >= maxHightBuilding ){
maxHightBuilding = buildings.get(i);
if(i <= K.get(i)){
sum++;
}
}
}
return sum;
}
}
I think if you retain the biggest value in front of the actual index, you can just check with the value and when your index passes the biggest value you can update it.
So find the biggest value from the end of the array.
HF!

Minimum number of swaps needed to getting the queue to final state not exceeding 2 swaps per element

Scenario or Problem statement:
It's New Year's Day and everyone's in line for the Wonderland rollercoaster ride! There are a number of people queued up, and each person wears a sticker indicating their initial position in the queue. Initial positions increment by 1 from 1 at the front of the line to n at the back.
Any person in the queue can bribe the person directly in front of them to swap positions. If two people swap positions, they still wear the same sticker denoting their original places in line. One person can bribe at most two others. For example, if n = 8 and Person 5 bribes Person 4, the queue will look like this: 1,2,3,5,4,6,7,8.
Fascinated by this chaotic queue, you decide you must know the minimum number of bribes that took place to get the queue into its current state!
Function Description
Complete the function minimumBribes in the editor below. It must print an integer representing the minimum number of bribes necessary, or Too chaotic if the line configuration is not possible.
minimumBribes has the following parameter(s):
q: an array of integers
Input Format
The first line contains an integer , the number of test cases.
Each of the next pairs of lines are as follows:
- The first line contains an integer , the number of people in the queue
- The second line has space-separated integers describing the final state of the queue.
Output Format
Print an integer denoting the minimum number of bribes needed to get the queue into its final state. Print Too chaotic if the state is invalid, i.e. it requires a person to have bribed more than people.
Sample Input
2
8
5 1 2 3 7 8 6 4
8
1 2 5 3 7 8 6 4
Sample Output
Too chaotic
7
I'm basically trying to create a method that accepts the values of the queue in this(final) state and returns the number of bribes needed to get to the final state starting from 1,2,3,4,5,... state, in case the number of bribes per person in the queue is not more than 2 else "Too chaotic".
The code which fails for a few cases using java streams is as below, I want to know why I'm not able to achieve the output with Java Streams?
static void minimumBribes(int[] q) {
AtomicInteger bribeCount = new AtomicInteger(0);
AtomicReference<String> chaoticString = new AtomicReference<String>();
IntStream.rangeClosed(1, q.length).forEach(i -> {
if (q[i - 1] > i) {
if (q[i - 1] - i > 2) {
chaoticString.set("Too chaotic");
} else {
bribeCount.addAndGet(q[i - 1] - i);
}
}
});
if (chaoticString.get() == "Too chaotic")
System.out.print(chaoticString.get());
else
System.out.print(bribeCount.get());
}
The code that passes without using java streams is given below:
static void minimumBribes(int[] q) {
for (int i = 0; i < q.length; i++) {
if (q[i] - (i + 1) > 2) {
System.out.println("Too chaotic");
return;
}
}
int bribe = 0;
for (int i = 0; i < q.length; i++) {
for (int j = i + 1; j < q.length; j++) {
if(q[i] > q[j]) {
q[j] = q[i] + q[j];
q[i] = q[j] - q[i];
q[j] = q[j] - q[i];
bribe++;
}
}
}
System.out.println(bribe);
}
public class MaximumTwoBribesAllowedForMovingForwardInQueue {
//Method that needs to be filled in
static void minimumBribes(int[] q) {
}
private static final Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
int t = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int tItr = 0; tItr < t; tItr++) {
int n = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
int[] q = new int[n];
String[] qItems = scanner.nextLine().split(" ");
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int i = 0; i < n; i++) {
int qItem = Integer.parseInt(qItems[i]);
q[i] = qItem;
}
minimumBribes(q);
}
scanner.close();
}
}
Can you please help recommend changes if any to achieve this with java streams?
Sample Input:
2
8
5 1 2 3 7 8 6 4
8
1 2 5 3 7 8 6 4
Expected Correct Output:
Too chaotic
7
Actual Wrong Output
Too chaotic
6

How to initialize a large number of variables in Java quickly and easily?

So I have a really basic coding question, I just started learning this year, and I have an assignment for a code that is supposed to
flip a fair coin n times and count how many heads it gets. The program will do m experiments and then
print out the results as a (vertical) histogram. The program will first ask the user to input the number of
experiments to perform (m) and the number of coin flips in each experiment (n). n can be at most 79. The
output will be a histogram made up of spaces and asterisks (*), with n+1 columns (for the number of heads
which can go from 0 to n)
I have the code for the histogram all done, but the problem I have is how to store the number of heads as it's own variable. For example, if it flipped the coin 80 times and 40 of them were heads, I would want it to create an int for 40 flips, then add one to it. I just don't know how to go about initializing 80 variables without writing out int one = 0; int two = 0, int three = 0; until the end of time, then writing 80 if statements until it finds the right integer to add one to. Is there an easy way to do this or should there be a different approach I should be taking? Here is the code, please be gentle, literally only a month or so into an extremely basic java class
for(m=m; m>0; m--) { //runs m number of experiments of n coinflips, keeping track of total heads
n = o; // when N gets set to 0 through the while loop, o resets it back to it's original so it can loop again
while(n>0) {
n--;
if(random.nextBoolean()) {
heads++;
total++;
/** here is where I want the number of heads saved to a
variable, so that way later I can run a loop to put as many *'s as I need in the histogram later */
Just use an array for the 80 (or n) experiments:
I don't understand, this would just count how many heads/tails there are right? This doesn't save them (ie it flipped 5 heads 6 times, 4 heads 3 times, 3 heads twice, ect) unless I'm misunderstanding
If you are storing the number of head m times (where m is < 80), you can:
1) print the histogram as you generate the results (no array needed) OR
2) store the 80 results in an array
Example for 1 (no array):
for(int x=0; x<experiments; x++){
int heads = 0;
for(int y=0; y<flips; y++){
if(rnd.nextInt(2) == 0) //assume 0 is head
heads ++;
}
//print histogram
for(int y=0; y<heads; y++)
System.out.print("*");
System.out.println();
}
Example for 2 (with array):
int[] expr = new int[80]; //store results for 80 experiments
for(int x=0; x<expriments; x++)
for(int y=0; y<flips; y++)
if(rnd.nextInt(2) == 0)
expr[x] ++;
Use an array:
int n = 80;
// space for n integers, with indexes 0..n
int[] histogram = new int[n + 1];
for (int i = 0; i < experiments; i++) {
// flip coin n times, counting heads
int heads = ...;
histogram[heads] = histogram[heads] + 1;
}
for (int i = 0; i < histogram.length; i++) {
printStars(histogram[i]);
}
If you're unfamiliar with arrays, the Java Tutorial has a good explanation.

Finding all the number combos in array that add up to input number

Hey I'm working on figuring out an algorithm that takes a user-entered number and then goes through an array of size 50 filled with random numbers between 1 and 100 and finds all the combinations of numbers that add up to the input number.
For example, given an array of integers [3,6,1,9,2,5,12] and being passed the integer value 9, you would return [[3,6],[6,1,2],[9],[3,1,5]]. Order of returning the results in the array does not matter, though you should return unique sets (ie. [6,3] and [3,6] are the same and only one should be returned). Also, the individual results should be in the order they are found (ie [6,1,2] should be returned, not [1,2,6]).
As I've started writing code, the first solution that I came to seems extremely in-efficient. I'm currently trying to separate each combo into it's own array, and every time a number gets added to the array, a check is done to see if the numbers equal the input, are still less than, or go over it. It's not working properly, and I feel like this might be an inefficient way to do it:
for (int i = 0; i < list.length; i++) {
List<Integer> combo = new ArrayList<Integer>();
int counter = 0;
int current = list[i];
if (current == input){
System.out.println(i);
}
else if (current > input) {
continue;
}
else if (current < input) {
combo.add(current);
if (combo.size() >= 2) {
for (int j = 0; j < combo.size(); j++) {
counter += combo.get(j);
if (counter == input) {
System.out.println("Success");
break;
}
else if (counter < input) {
continue;
}
else if (counter > input) {
break;
}
}
}
}
}
This is an idea, I don't have a working code. Try to use recursion, test all combinations with the biggest possible number plus all the rest without it. Function like: Sums(Number, maxN), (maxN is maximum number which we can take - in first call it's 9)
For your example would be:
1. As suggested, sort them and cut bigger than input.
2. Check if the maxN is greater than the minimum required to make a sum, in your example it is 5 (can't make 9 from numbers smaller than 5 in your set); if it's not return (base case).
3. Is maxN equal tu input? (9 in first call)
a) Yes - first solution subset [9] + Sums(Number, dec(maxN)) (dec(maxN) will be 6 in first call)
b) No - recursively check if 'Number - maxN' could be built from numbers from your set, Sums(Number - maxN, dec(K) or max number of 'Number - maxN' (depends what is smaller)) + Sums(Number, dec(maxN)) - add the rest.
Here is code to count only, ways to write a number as sum of squares, it passed HackerRank tests:
import math
def minArgument(x):
s = 0
i = 1
while s < x:
s = s + i * i
i = i + 1
return i - 1
def maxPower(a):
return math.floor(math.sqrt(a))
def sumOfSquares(M, K, cnt):
if M < 1:
return cnt
lowerLimit = minArgument(M)
if K < lowerLimit:
return cnt
else:
if K * K == M:
return sumOfSquares(M, K - 1, cnt + 1)
else:
return sumOfSquares(M, K - 1,sumOfSquares(M - K * K,
min(maxPower(M - K * K), K - 1), cnt))
After easy change, this gives you number of solutions. I don't see how to build a list with combinations as a return value now...

Why does this merge sort give incorrect results?

My assignment is to merge two arrays using int arrays that the user fills and we have to assume that there will be a maximum of 10000 inputs from the user, and the user inputs a negative number to stop. Then sort the array from least to greatest and print it out. Initially i thought that this would be quite easy but when i finished, i began getting outputs such as:
Enter the values for the first array, up to 10000 values, enter a negative number to quit: 1
3
5
-1
Enter the values for the second array, up to 10000 values, enter a negative number to quit
2
4
6
-1
First Array:
1
3
5
Second Array:
2
4
6
Merged Array:
6 1 2 3 4 5
as you can see, the six is out of place and i have no idea how to fix it. Here is the source code, i have included copious comments because I really want you guys to help me out to the best of your abilities. IF it's possible to use the same exact technique without implement new techniques and methods into the code please do so. I know there are methods in java that can do all of this in one line but it's for an assignment at a more basic level.
import java.util.Scanner;
public class Merge
{
public static void main(String [] args)
{
Scanner scan = new Scanner(System.in);
int [] first = new int[10000]; //first array, assume 10k inputs max
int [] second = new int[10000]; //first array, assume 10k inputs max
boolean legal = true; //WILL IMPLIMENT LATER
int end = 0; // set how many elements to put in my "both" array
int end2 = 0;// set how many elements to put in my "both" array
System.out.print("Enter the values for the first array, up to 10000 values, enter a negative number to quit");
//get values
for(int i = 0; i<first.length; i++)
{
first[i] = scan.nextInt(); //fill first with user input
if(first[i] <0) //if negative number, stop loop
{
end = i; //get position of end of user input
break;
}
}
System.out.println("Enter the values for the second array, up to 10000 values, enter a negative number to quit");
for(int i = 0; i<second.length; i++) //exact same as the first get values loop
{
second[i] = scan.nextInt();
if(second[i] <0)
{
end2 = i;
break;
}
}
System.out.print("First Array:\n");
for(int i = 0; i<first.length; i++) //print first array
{
if(i == end) //this prevents from printing thousands of zeros, only prints values that user inputed
break;
System.out.println(first[i] + " ");
}
System.out.print("Second Array:\n");
for(int i = 0; i<second.length; i++) //same as printing first array
{
if(i == end2)
break;
System.out.println(second[i] + " ");
}
int [] both = new int[(end)+(end2)]; //instanciate an int array to hold only inputted values from first[] and second[]
int [] bothF = new int[(end)+(end2)]; //this is for my simple sorter algotithm loop
for(int i = 0; i<both.length; i++) //fill both with the first array that was filled
{
both[i] = first[i];
}
int temp = end; // see below
for(int i = 0;i<both.length; i++) //fill array with the second array that was filled(starting from the end of the first array so that the first set is not overwritten
{
if(temp<both.length){ //this prevents an out of bounds
both[temp] = second[i];
temp++;}
}
//simple sorting algorithm
for(int d = both.length -1;d>=0;d--)
{
for(int i = 0; i<both.length; i++)
{
if(both[d]<both[i])
{
bothF[d] = both[d];
both[d] = both[i];
both[i] = bothF[d];
}
}
}
System.out.println("Merged Array:"); //print the results
for(int i = 0; i<both.length; i++)
{
System.out.print(both[i] + " ");
}
//System.out.println("ERROR: Array not in correct order");
}
Your sorting algorithm is faulty.
It's similar to selection sort, in that you take two elements and swap them if they're out of place. However, you don't stop the comparisons when you should: when the index d is less than the index i, the comparison-and-swap based on arr[d] > arr[i] is no longer valid.
The inner loop should terminate with i=d.
The logic of your sort goes something like this:
On the d-th loop, the elements at d+1 and to the right are correctly sorted (the larger numbers). This is true at the beginning, because there are 0 elements correctly sorted to the right of the right-most element.
On each of the outer loops (with the d counter), compare the d-th largest element slot with every unsorted element, and swap if the other element is larger.
This is sufficient to sort the array, but if you begin to compare the d-th largest element slot with already-sorted elements to its right, you'll end up with a larger number in the slot than should be. Therefore, the inner loop should terminate when it reaches d.
Sure, you can do it like this
for (int i = 0; i < end; i++) {
both[i] = first[i];
}
for (int i = 0; i < end2; i++) {
both[i + end] = second[i];
}
// simple sorting algorithm
for (int d = both.length - 1; d >= 0; d--) {
for (int i = 0; i < d; i++) {
if (both[i] > both[d]) {
int t = both[d];
both[d] = both[i];
both[i] = t;
}
}
}
Output(s) -
Enter the values for the first array, up to 10000 values, enter a negative number to quit3
5
-1
Enter the values for the second array, up to 10000 values, enter a negative number to quit
2
4
6
-1
First Array:
3
5
Second Array:
2
4
6
-1
Merged Array:
2 3 4 5 6
First I will start with some recommendations:
1.Give end1 and end2 the initial value as the array lengths.
The printing part - instead of breaking the loop - loop till i == end(if its not changed by the first part it will stay the array length).
One suggestion is to use a "while" statement on the user input to do the reading part (it seems cleaner then breaking the loop- but its OK to do it like you have done too).
Try to use more functions.
now to the main thing- why not to insert the numbers from both arrays to the join array keeping them sorted?
Guiding:
Keep a marker for each array.
Iterate over the new join array If arr1[marker1]> arr2[marker2]
insert arr2[marker2] to the joint array in the current position.
and add 1 to marker2. and the opposite.
(don't forget to choose what happens if the are equal).
This can be achieved because the arrays were sorted in the first place.
Have fun practicing!
I guess you have sort of a reverse "selection sort"-algorithm going on there. I made an class that run your code and printed out the output after every swap. Here is the code which is the same as you got in your application with the addition of print.
for(int d = both.length -1;d>=0;d--)
{
for(int i = 0; i<both.length; i++)
{
if(both[d]<both[i])
{
int temp = both[d];
both[d] = both[i];
both[i] = temp;
printArray(both);
}
}
}
and when we run this on an example array we get this output
[9, 8, 7, 6]=
-> 6879
-> 6789
-> 6798
-> 6978
-> 9678
The algorithm actually had the correct answer after two swaps but then it started shuffling them into wrong order. The issue is the inner for loops end parameter. When you have run the outer loop once, you can be certain that the biggest number is in the end. 'd' is here 3 and it will swap out a bigger number every time it encounters it. the if clause comparisions in the first loop is 6-9 (swap), 9-8, 9-7, 9-9. All good so far.
Potential problems comes in the second iteration with 'd' as 2. Array is now [6,8,7,9] and comparisons are 7-6, 7-8 (swap with result [6,7,8,9]), 8-8, 8-9 (swap!!) resulting in [6,7,9,8]. the last swap was the problematic one. We knew that the biggest number was already in the last spot, but we still compare against it. with every gotrough of the whole inner loop it will always find the biggest number (and all other bigger than both[d] that is already in place) and swap it to some wrong position.
As we know that the biggest number will be last after one iteration of the outer loop, we shouldn't compare against it in the second iteration. You sort of lock the 9 in the array and only try to sort the rest, being in this case [6,8,7] where d = 3, value 7. hence, your inner loop for(int i = 0; i<both.length; i++) becomes for(int i = 0; i<=d; i++). As an added bonus, you know that in the last iteration i==d, and thus the code inside it, if(both[d]<both[i]) will never be true, and you can further enhance the loop into for(int i = 0; i<d; i++).
In your algorithm you always do four comparisons in the inner loop over four iterations of the outer loop, which means there is a total of 16 comparisons. if we use the i<d we'll just do three comparisons in the inner loop on the first iteration of the outer loop, then two, then one. This brings it to a total of six comparisons.
Sorry if too rambling, just wanted to be thorough.

Categories

Resources