How Improve Run-time when sorting arrays - java

I have managed to create a working solution for "Mixing Milk" for USACO, but the judge says my program takes too long.
I think this has to do with the way I sort the list of Farmers by asking price in lines 29 - 44. Is there any way I can improve the run time?
/*
ID:
LANG: JAVA
TASK: milk
*/
import java.util.*;
import java.io.*;
public class milk {
public static void main(String[] args) throws IOException {
double startTime = System.currentTimeMillis();
BufferedReader s = new BufferedReader(new InputStreamReader(new FileInputStream(new File("test.in"))));
PrintWriter w = new PrintWriter(new File("test.out"));
// BufferedReader s = new BufferedReader(new InputStreamReader(new FileInputStream(new File("milk.in"))));
// PrintWriter w = new PrintWriter(new File("milk.out"));
String[] st = s.readLine().split(" ");
int N = Integer.parseInt(st[0]);
int M = Integer.parseInt(st[1]);
int[] P = new int[M];
int[] A = new int[M];
String[] sets = new String[M];
for (int i = 0; i < M; i++) {
sets[i] = s.readLine();
st = sets[i].split(" ");
P[i] = Integer.parseInt(st[0]);
}
int maxp = ("" + maxVal(P)).length();
for (int i = 0; i < M; i++) {
st = sets[i].split(" ");
while (st[0].length() < maxp) {
st[0] = "0" + st[0];
}
sets[i] = st[0] + " " + st[1];
}
Arrays.sort(sets);
int cap = 0;
for (int i = 0; i < M && cap <= N; i++) {
st = sets[i].split(" ");
P[i] = Integer.parseInt(st[0]);
A[i] = Integer.parseInt(st[1]);
cap += A[i];
}
int sum = 0;
int units = 0;
int a;
for (int i = 0; units < N; i++) {
if (A[i] <= N - units) {
sum = sum + P[i] * A[i];
units += A[i];
} else {
a = N - units;
if (a > A[i]) {
a = A[i];
}
sum = sum + P[i] * a;
units += a;
}
}
System.out.println(units);
System.out.println(sum);
w.println(sum);
w.close();
double endTime = System.currentTimeMillis();
System.out.println("Took " + ((endTime - startTime) / 1000) + " seconds.");
}
public static int maxVal(int[] x) {
int max = 0;
for (int i : x) {
if (i > max) {
max = i;
}
}
return max;
}
}
EDIT: Thanks Andreas!
Changed code and made the time limit:
/*
ID:
LANG: JAVA
TASK: milk
*/
import java.util.*;
import java.io.*;
public class milk {
public static void main(String[] args) throws IOException {
double startTime = System.currentTimeMillis();
// BufferedReader s = new BufferedReader(new InputStreamReader(new FileInputStream(new File("test.in"))));
// PrintWriter w = new PrintWriter(new File("test.out"));
BufferedReader s = new BufferedReader(new InputStreamReader(new FileInputStream(new File("milk.in"))));
PrintWriter w = new PrintWriter(new File("milk.out"));
String temp = s.readLine();
int spc = temp.indexOf(" ");
int N = Integer.parseInt(temp.substring(0, spc));
int M = Integer.parseInt(temp.substring(spc + 1));
System.out.println(N + " " + M);
int[] P = new int[M];
int[] A = new int[M];
Farmer[] f = new Farmer[M];
for (int i = 0; i < M; i++) {
temp = s.readLine();
spc = temp.indexOf(" ");
f[i] = new Farmer(Integer.parseInt(temp.substring(0, spc)), Integer.parseInt(temp.substring(spc + 1)));
}
Arrays.sort(f);
for (int i = 0; i < M; i++) {
P[i] = f[i].getPrice();
A[i] = f[i].getInventory();
}
int sum = 0;
int units = 0;
int a;
for (int i = 0; units < N; i++) {
if (A[i] <= N - units) {
sum = sum + P[i] * A[i];
units += A[i];
} else {
a = N - units;
if (a > A[i]) {
a = A[i];
}
sum = sum + P[i] * a;
units += a;
}
}
System.out.println(units);
System.out.println(sum);
w.println(sum);
w.close();
double endTime = System.currentTimeMillis();
System.out.println("Took " + ((endTime - startTime) / 1000) + " seconds.");
}
}
class Farmer implements Comparable<Farmer> {
private int price;
private int inventory;
public Farmer(int price, int inventory) {
this.price = price;
this.inventory = inventory;
}
public int getPrice() {
return price;
}
public int getInventory() {
return inventory;
}
#Override
public int compareTo(Farmer f1) {
if (f1.price != this.price) {
return this.price - f1.price;
} else if (f1.inventory != this.inventory) {
return f1.inventory - this.inventory;
} else {
return 0;
}
}
}

Java is an Object-Oriented language. Use it.
Your code keeps processing String lines, splitting and concatenating. That is slow.
Read your lines into objects containing the two integer values. Make the class implement Comparable, to sort by the two values, so you can call sort().
The processing is faster because you only parse the numbers once. The sorting is faster because you don't have to zero-pad the numbers, and you sort by integers, not string.
Since your lines consist of two integers separated by a single space, don't use split(). Use indexOf(' ') and call substring() twice. It's faster and less memory intensive.

Related

UVa 10461 Difference Java Solution got Runtime Error

I'm trying to solve UVa 10461 Difference problem using Java and I am pretty sure of the logic of my code because I actually submitted this logic in C++ and got accepted but when I was trying to submit it using Java, I got Runtime error.
The problem asks to calculate the maximum possible difference among all possible completion times of a particular job.
Any ideas
import java.io.*;
import java.util.*;
class Main {
public static void main(String[] args) throws IOException {
BufferedReader bufferReader = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(System.out);
StringTokenizer st = new StringTokenizer(bufferReader.readLine());
int v = Integer.parseInt(st.nextToken());
int e = Integer.parseInt(st.nextToken());
int count = 1;
while (v != 0 || e != 0) {
int[] jobs = new int[v];
List<List<Integer>> parents = new ArrayList<>(v);
List<List<Integer>> children = new ArrayList<>(v);
int sum = 0;
st = new StringTokenizer(bufferReader.readLine());
for (int i = 0; i < v; i++) {
jobs[i] = Integer.parseInt(st.nextToken());
parents.add(new ArrayList<>());
children.add(new ArrayList<>());
sum += jobs[i];
}
for (int i = 0; i < e; i++) {
st = new StringTokenizer(bufferReader.readLine());
int from = Integer.parseInt(st.nextToken()) - 1;
int to = Integer.parseInt(st.nextToken()) - 1;
children.get(from).add(to);
parents.get(to).add(from);
}
st = new StringTokenizer(bufferReader.readLine());
int q = Integer.parseInt(st.nextToken());
st = new StringTokenizer(bufferReader.readLine());
out.println("Case #" + count++ + ":");
while (q-- > 0) {
int cur = Integer.parseInt(st.nextToken()) - 1;
int max = sum - getJobTime(cur, parents, jobs) - jobs[cur];
int min = getJobTime(cur, children, jobs);
out.println(max - min);
}
out.println();
out.flush();
bufferReader.readLine();
st = new StringTokenizer(bufferReader.readLine());
v = Integer.parseInt(st.nextToken());
e = Integer.parseInt(st.nextToken());
}
bufferReader.close();
out.close();
}
public static int getJobTime(int job, List<List<Integer>> dependencies, int[] jobs) {
Queue<Integer> q = new LinkedList<>();
Set<Integer> set = new HashSet<>();
List<Integer> curDependencies = dependencies.get(job);
for (Integer item : curDependencies) {
q.offer(item);
set.add(item);
}
int count = 0;
while (!q.isEmpty()) {
int cur = q.poll();
count += jobs[cur];
curDependencies = dependencies.get(cur);
for (Integer item : curDependencies) {
if (!set.contains(item)) {
q.offer(item);
set.add(item);
}
}
}
return count;
}
}

What is wrong with this swapping program in Java, why and what should I do?

I am making a multiple string input random swap without using a temp variable.
But when I input, this happens a few times:
This happens more frequently... (note that the first output is always null and some outputs occasionally repeat)
My code:
import java.util.Arrays;
import java.util.Scanner;
public class myFile {
public static boolean contains(int[] array, int key) {
Arrays.sort(array);
return Arrays.binarySearch(array, key) >= 0;
}
public static void println(Object line) {
System.out.println(line);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String finalText = "";
String[] input = new String[5];
String[] swappedInput = new String[input.length];
int[] usedIndex = new int[input.length];
int swapCounter = input.length, useCounter;
for (int inputCounter = 0; inputCounter < input.length; inputCounter++) { //input
println("Enter input 1 " + (inputCounter + 1) + ": ");
input[inputCounter] = in.nextLine();
}
while (--swapCounter > 0) {
do{
useCounter = (int) Math.floor(Math.random() * input.length);
}
while (contains(usedIndex, useCounter));
swappedInput[swapCounter] = input[swapCounter].concat("#" + input[useCounter]);
swappedInput[useCounter] = swappedInput[swapCounter].split("#")[0];
swappedInput[swapCounter] = swappedInput[swapCounter].split("#")[1];
usedIndex[useCounter] = useCounter;
}
for (int outputCounter = 0; outputCounter < input.length; outputCounter++) {
finalText = finalText + swappedInput[outputCounter] + " ";
}
println("The swapped inputs are: " + finalText + ".");
}
}
Because of randomality some times useCounter is the same as swapCounter and now look at those lines (assume useCounter and swapCounter are the same)
swappedInput[swapCounter] = input[swapCounter].concat("#" + input[useCounter]);
swappedInput[useCounter] = swappedInput[swapCounter].split("#")[0];
swappedInput[swapCounter] = swappedInput[swapCounter].split("#")[1];
In the second line you are changing the value of xxx#www to be www so in the third line when doing split you dont get an array with two values you get an empty result thats why exception is thrown in addition you should not use swappedInput because it beats the pourpuse (if i understand correctly yoush shoud not use temp values while you are using addition array which is worse) the correct sollution is to only use input array here is the solution
public class myFile {
public static boolean contains(int[] array, int key) {
Arrays.sort(array);
return Arrays.binarySearch(array, key) >= 0;
}
public static void println(Object line) {
System.out.println(line);
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String finalText = "";
String[] input = new String[5];
int[] usedIndex = new int[input.length];
int swapCounter = input.length, useCounter;
for (int inputCounter = 0; inputCounter < input.length; inputCounter++) { //input
println("Enter input 1 " + (inputCounter + 1) + ": ");
input[inputCounter] = in.nextLine();
}
while (--swapCounter >= 0) {
do {
useCounter = (int) Math.floor(Math.random() * input.length);
}
while (contains(usedIndex, useCounter));
// Skip if results are the same
if (useCounter == swapCounter) {
swapCounter++;
continue;
}
input[swapCounter] = input[swapCounter].concat("#" + input[useCounter]);
input[useCounter] = input[swapCounter].split("#")[0];
input[swapCounter] = input[swapCounter].split("#")[1];
usedIndex[useCounter] = useCounter;
}
for (int outputCounter = 0; outputCounter < input.length; outputCounter++) {
finalText = finalText + input[outputCounter] + " ";
}
println("The swapped inputs are: " + finalText + ".");
}
}

Training data algorithm not working. (Perceptron)

I am trying to write an algorithm to train perceptron but there seems to be values exceeding max value for double. I have been trying to figure out since yesterday but cannot.
The value of weights seems to be exceeding as well as the value of variable output.
The text file that is read in is of the form:
Input variables and the output
/**
* Created by yafael on 12/3/16.
*/
import java.io.*;
import java.util.*;
public class Perceptron {
static double[] weights;
static ArrayList<Integer> inputValues;
static ArrayList<Integer> outputValues;
static int[] inpArray;
static int[] outArray;
public static int numberOfInputValues(String filePath)throws IOException
{
Scanner valueScanner = new Scanner(new File(filePath));
int num = valueScanner.nextInt();
return num;
}
public static void inputs(String filePath)throws IOException
{
inputValues = new ArrayList<Integer>();
outputValues = new ArrayList<Integer>();
Scanner valueScanner = new Scanner(new File(filePath));
int num = valueScanner.nextInt();
while (valueScanner.hasNext())
{
String temp = valueScanner.next();
String[] values = temp.split(",");
for(int i = 0; i < values.length; i++)
{
if(i+1 != values.length)
{
inputValues.add(Integer.parseInt(values[i]));
}else
{
outputValues.add(Integer.parseInt(values[i]));
}
}
}
valueScanner.close();
}
public static void trainData(int[] inp, int[] out, int num,int epoch)
{
weights = new double[num];
Random r = new Random();
int i,ep;
int error = 0;
/*
* Initialize weights
*/
for(i = 0; i < num; i++)
{
weights[i] = r.nextDouble();
}
for(ep = 1; ep<= epoch; ep++)
{
double totalError = 0;
for(i = 0; i < inp.length/(num); i++)
{
double output = calculateOutput(inp, i, weights);
System.out.println("Output " + (i + 1) + ": " + output);
//System.out.println("Output: " + output);
if(output > 0)
{
error = out[i] - 1;
}else
{
error = out[i] - 0;
}
for(int temp = 0; temp < num; temp++)
{
double epCalc = (1000/(double)(1000+ep));
weights[temp] += epCalc*error*inp[((i*weights.length)+temp)];
//System.out.println("Epoch calculation: " + epCalc);
//System.out.println("Output: " + output);
//System.out.println("error: " + error);
//System.out.println("input " + ((i*weights.length)+temp) + ": " + inp[(i*weights.length)+temp]);
}
totalError += (error*error);
}
//System.out.println("Total Error: " + totalError);
if(totalError == 0)
{
System.out.println("In total error");
for(int temp = 0; temp < num; temp++)
{
System.out.println("Weight " +(temp)+ ": " + weights[temp]);
}
double x = 0.0;
for(i = 0; i < inp.length/(num); i++)
{
for(int j = 0; j < weights.length; j++)
{
x = inp[((i*num) + j)] * weights[j];
}
System.out.println("Output " + (i+1) + ": " + x);
}
break;
}
}
if(ep >= 10000)
{
System.out.println("Solution not found");
}
}
public static double calculateOutput(int[] input, int start, double[] weights)
{
start = start * weights.length;
double sum = 0.0;
for(int i = 0; i < weights.length; i++)
{
//System.out.println("input[" + (start + i) + "]: " + input[(start+i)]);
//System.out.println("weights[i]" + weights[i]);
sum += (double)input[(start + i)] * weights[i];
}
return sum - 1.0 ;
}
public static void main(String args[])throws IOException
{
BufferedReader obj = new BufferedReader(new InputStreamReader(System.in));
//Read the file path from the user
String fileName;
System.out.println("Please enter file path for Execution: ");
fileName = obj.readLine();
int numInputValues = numberOfInputValues(fileName);
//Call the function to store values in the ArrayList<>
inputs(fileName);
inpArray = inputValues.stream().mapToInt(i->i).toArray();
outArray = outputValues.stream().mapToInt(i->i).toArray();
trainData(inpArray, outArray, numInputValues, 10000);
}
}
I believe your code is problematic, so i am giving you a simple example but i am sure you will get help from this code to resolve your problem.
import java.util.Random;
public class Perceptron {
double[] weights;
double threshold;
public void Train(double[][] inputs, int[] outputs, double threshold, double lrate, int epoch) {
this.threshold = threshold;
int n = inputs[0].length;
int p = outputs.length;
weights = new double[n];
Random r = new Random();
//initialize weights
for(int i=0;i<n;i++) {
weights[i] = r.nextDouble();
}
for(int i=0;i<epoch;i++) {
int totalError = 0;
for(int j =0;j<p;j++) {
int output = Output(inputs[j]);
int error = outputs[j] - output;
totalError +=error;
for(int k=0;k<n;k++) {
double delta = lrate * inputs[j][k] * error;
weights[k] += delta;
}
}
if(totalError == 0)
break;
}
}
public int Output(double[] input) {
double sum = 0.0;
for(int i=0;i<input.length;i++) {
sum += weights[i]*input[i];
}
if(sum>threshold)
return 1;
else
return 0;
}
public static void main(String[] args) {
Perceptron p = new Perceptron();
double inputs[][] = {{0,0},{0,1},{1,0},{1,1}};
int outputs[] = {0,0,0,1};
p.Train(inputs, outputs, 0.2, 0.1, 200);
System.out.println(p.Output(new double[]{0,0})); // prints 0
System.out.println(p.Output(new double[]{1,0})); // prints 0
System.out.println(p.Output(new double[]{0,1})); // prints 0
System.out.println(p.Output(new double[]{1,1})); // prints 1
}
}

printing optimal binary search tree in preorder dynamic programming algorith

I have just finished up computing the average cost of an OBST and I know I computed it correctly. My next task is to print the tree in preorder. I have an attempt at this using recursion but can't seem to shake the null pointer error.
Here's my code:
public class OBST {
static String[] keysA;
static Integer[][] root;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int tot = sc.nextInt();
HashMap<String, Double> hm = new HashMap<String, Double>();
int uniqNum = 0;
String[] rawInput = new String[tot];
for(int i=0; i<tot; i++) {
String tmp1 = sc.next();
if(i==0) {
hm.put(tmp1, 1.0);
uniqNum += 1.0;
} else if( i != 0) {
if(!hm.containsKey(tmp1)) {
hm.put(tmp1, 1.0);
uniqNum += 1.0;
} else {
Double tmpfreq = 0.0;
tmpfreq = hm.get(tmp1);
hm.put(tmp1, (tmpfreq + 1.0));
}
}
}
Set<String> keys = hm.keySet();
keysA = keys.toArray(new String[uniqNum]);
Double[] freqsA = new Double[uniqNum];
Arrays.sort(keysA);
for(int i=0; i<uniqNum; i++) {
Double tmp = 0.0;
String tmpK = keysA[i];
tmp = hm.get(tmpK);
tmp = tmp/tot;
freqsA[i] = tmp;
}
Double[][] eee = new Double[uniqNum+2][uniqNum+1];
Double[][] www = new Double[uniqNum+2][uniqNum+1];
//matrix to store optimal structure
root = new Integer[uniqNum+1][uniqNum+1];
for(int i=1; i<uniqNum+2; i++) {
eee[i][i-1] = 0.0;
www[i][i-1] = 0.0;
}
for(int l=1; l<uniqNum+1; l++) {
for(int i=1; i<=uniqNum-l+1; i++) {
int j = i + l - 1;
eee[i][j] = Double.MAX_VALUE;
www[i][j] = www[i][j-1] + freqsA[j-1];
for(int r=i; r<=j; r++) {
Double t = eee[i][r-1] + eee[r+1][j] + www[i][j];
if(t<eee[i][j]) {
eee[i][j] = t;
root[i][j] = r-1;
}
}
}
}
//total cost
System.out.println(eee[1][uniqNum]);
printTree(1,uniqNum-1,-1, "");
}
public static void printTree(int min, int max, int parent, String s) {
int r = root[min][max];
if(parent == -1 ) {
System.out.println(keysA[r] + " is root");
} else if(min < parent) {
System.out.println(keysA[r] + " is the left child of " + s);
} else {
System.out.println(keysA[r] + " is the right child of " + s);
} if(min < max) {
printTree(min,r,r+1,keysA[r]);
printTree(r+1,max,r,keysA[r]);
}
}
}
My trouble is in the method print tree.
Looks like you aren't checking your bounds correctly. If there is no left or right child, you shouldn't be printing that side. so make sure you check that r+1 is within the array size, and also that a node exists there. do the same for both left and right sides.

How can I avoid repetition of the same number?

This is what I want :
Let the user enter as many numbers as they want until a non number is entered (you may
assume there will be less than 100 numbers). Find the most frequently entered number. (If
there are more than one, print all of them.)
Example output:
Input: 5
Input: 4
Input: 9
Input: 9
Input: 4
Input: 1
Input: a
Most common: 4, 9
I have got to the point in my code where I have managed to find out which are the most common numbers. However, I don't want to print out the same number over and over again; example from above: Most common: 4, 9, 9, 4
What needs to be done?
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String[] input = new String[100];
System.out.print("Input: ");
input[0] = in.readLine();
int size = 0;
for (int i = 1; i < 100 && isNumeric(input[i-1]); i++) {
System.out.print("Input: ");
input[i] = in.readLine();
size = size + 1;
}
/*for (int i = 0; i < size; i++) { //testing
System.out.println(input[i]);
}*/
int numOccur;
int[] occur = new int[size];
for(int i = 0; i < size; i++) {
numOccur = 0;
for (int j = 0; j < size; j++) {
if(input[i].equals(input[j])) {
numOccur = numOccur + 1;
}
}
occur[i] = numOccur;
//System.out.println(numOccur); //testing
}
int maxOccur = 0;
for(int i = 0; i < size; i++) {
if(occur[i] > maxOccur) {
maxOccur = occur[i];
}
}
//System.out.println(maxOccur); //testing
for (int i = 0; i < size && !numFound; i++) {
if(occur[i] == maxOccur) {
System.out.println(input[i]);
}
}
}
//checks if s is an in, true if it is an int
public static boolean isNumeric (String s) {
try {
Integer.parseInt(s);
return true; //parse was successful
} catch (NumberFormatException nfe) {
return false;
}
}
Found the solution!
String[] mostCommon = new String[size];
int numMostCommon = 0;
boolean numFound = false;
for (int i = 0; i < size; i++) {
int isDifferent = 0;
if (occur[i] == maxOccur) {
for (int j = 0; j < size; j++) {
if (!(input[i].equals(mostCommon[j]))) {
isDifferent = isDifferent + 1;
}
}
if (isDifferent == size) {
mostCommon[numMostCommon] = input[i];
numMostCommon = numMostCommon + 1;
}
}
}
for (int i = 0; i < numMostCommon - 1; i++) {
System.out.print("Most common: " + mostCommon[i] + ", ");
}
System.out.println(mostCommon[numMostCommon - 1]);
you could use the hash table for this to store the frequenceis as the limit is very less i.e. less than 100.
pseudo code would be like:
vector<int> hash(101)
cin>>input
if(isnumeric(input))
hash[input]++
else{
max=max_element(hash.begin(),hash.end());
for(int i=0;i<100;i++)
if(hash[i]==max)
print i
}
Set<Integer> uniqueMaxOccur = new HashSet<Integer>();
for (int i = 0; i < size ; i++) {
if(occur[i] == maxOccur) {
//System.out.println(input[i]);
uniqueMaxOccur.add(input[i]);
}
}
and display the values in the set
You can use a Set and store the values already printed.
What about something like this?
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
Map<string,int> numberLookup = new HashMap<string,int>();
Boolean doContinue = true;
while (doContinue)
{
System.out.print("Input: ");
String input = in.readLine();
if (isNumeric(input))
{
if (!numberLookup.containsKey(input))
numberLookup.put(input,1);
else
numberLookup.put(input, numberLookup.get(input) + 1);
}
else
doContinue = false;
}
maxOccur = numberLookup.values().max();
System.out.print("These numbers were all entered " + maxOccur + " times:");
Iterator it = numberLookup.entrySet().iterator();
while (it.hasNext())
{
(Map.Entry)it.next();
System.out.println(pairs.getKey());
}
}
Sorry, I'm a C# person and don't have a Java compiler on me, so this might need some tweaking.

Categories