Even if I think that I solved a competitive programming problem from HackerEarth with the best approach, all tests exceed the time limit. I really do not know how to optimize it further because it is just an easy exercise.
My approach: iterate over all array members than add them to a HashMap which stores their occurrences. After that simply read the query numbers and get their occurence from the HashMap.
This is my solution:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
class TestClass {
public static void main(String args[]) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(br.readLine());
//go through all test cases
for (int i = 0; i < t; i++) {
Map<Integer, Integer> map = new HashMap<>();
String[] inputs = br.readLine().split(" ");
int N = Integer.parseInt(inputs[0]);
int Q = Integer.parseInt(inputs[1]);
inputs = br.readLine().split(" ");
//read array
for (int j = 0; j < N; j++) {
int x = Integer.parseInt(inputs[j]);
Integer value = map.get(x);
//if number is already in hashmap then increment its count
//else put it into the map with a count of 1
if (value == null) {
map.put(x, 1);
} else map.put(x, value + 1);
}
//iterate through the queries and get their occurences from the map
for (int j = 0; j < Q; j++) {
int x = Integer.parseInt(br.readLine());
Integer value = map.get(x);
if (value == null) {
System.out.println(0);
} else System.out.println(value);
}
}
}
}
My question is: what can be the problem with my approach? Why does it run out of time?
Ok, so the problem is not so obvious. I took a look at the input files and they are huge so you have to use some really fast method for writing to the console(many test cases -->> many answers). You can use PrinteWriter for that.
Working solution:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
class TestClass {
public static void main(String args[]) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
PrintWriter pr = new PrintWriter(System.out);
int t = Integer.parseInt(br.readLine());
//go through all test cases
for (int i = 0; i < t; i++) {
Map<Integer, Integer> map = new HashMap<>();
String[] inputs = br.readLine().split(" ");
int N = Integer.parseInt(inputs[0]);
int Q = Integer.parseInt(inputs[1]);
inputs = br.readLine().split(" ");
//read array
for (int j = 0; j < N; j++) {
int x = Integer.parseInt(inputs[j]);
Integer value = map.get(x);
//if number is already in hashmap then increment its count
//else put it into the map with a count of 1
if (value == null) {
map.put(x, 1);
} else map.put(x, value + 1);
}
//iterate through the queries and get their occurences from the map
for (int j = 0; j < Q; j++) {
int x = Integer.parseInt(br.readLine());
Integer value = map.get(x);
if (value == null) {
pr.println(0);
} else pr.println(value);
}
}
pr.close();
}
}
Yes, I know that it is strange that the exercise itself is not so hard, but reading the input and writing the result is the big part of it.
The problem with your approach is primarily it's use of BufferedReader, and the consequential information parsing you're preforming. Try an approach with scanner.
import java.util.*;
class TestClass {
public static void main(String args[] ) throws Exception {
Scanner s = new Scanner(System.in);
int T = s.nextInt();
Map<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int i=0;i<T;i++)
{
StringBuilder sb=new StringBuilder();
int N=s.nextInt();
int Q=s.nextInt();
int[] arr=new int[N];
for(int j=0;j<N;j++)
{
arr[j]=s.nextInt();
if(map.containsKey(arr[j]))
{
map.put(arr[j],map.get(arr[j])+1);
}
else
map.put(arr[j],1);
}
for(int k=0;k<Q;k++)
{
int X=s.nextInt();
if(map.containsKey(X)){
sb.append(map.get(X)+"\n");
}
else{
sb.append(0+"\n");
}
}
System.out.println(sb.toString());
map.clear();
}
}
}
This will remove a lot of the unnecessary parsing you are doing with:
String[] inputs = br.readLine().split(" ");
int N = Integer.parseInt(inputs[0]);
int Q = Integer.parseInt(inputs[1]);
inputs = br.readLine().split(" ");
Please look at Scanner vs. BufferedReader to understand why Scanner is situationally faster here. Essentially BufferedReader is faster in it's ability to simply read the lines, but when you use BufferedReader here, you are then forced to use Integer.parseInt(...) and br.readlines().split(" ") to parse the information you need from the input; however, scanner has built in parsing mechanisms that can read and parse the data asynchronously. As you will see, this approach passes the test in 4-8 seconds. Additionally you could benefit from using StringBuilder, and not using:
Integer value = map.get(x);
if (value == null) {
pr.println(0);
} else pr.println(value);
With the built in method map.containsKey(x).
Scanner is used for parsing tokens from the contents of the stream while BufferedReader just reads the stream and does not do any special
parsing.
In fact you can pass a BufferedReader to a scanner as the source of
characters to parse.
Furthermore:
A scanner on the other hand has a lot more cheese built into it; it
can do all that a BufferedReader can do and at around the same level of
efficiency as well. However, in addition a Scanner can parse the
underlying stream for primitive types and strings using regular
expressions. It can also tokenize the underlying stream with the
delimiter of your choice. It can also do forward scanning of the
underlying stream disregarding the delimiter!
There is a large difference in runtime when you have to call
inputs = br.readLine().split(" "); and Integer.parseInt(..) multiple times, versus simply calling s.nextInt(). You are already reading the data with br.readLine(), when you call Integer.parseInt(...) the data is read again by the parseInt() function.
Related
import java.io.*;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
try {
File file = new File("C:\\Users\\HIM\\IdeaProjects\\File Tutorial\\src\\quad.txt");
Scanner scanner = new Scanner(file);
double a , b, c;
double[] arr = new double[3];
for(int i = 0; i < arr.length; i++) {
while (scanner.hasNextLine()) {
arr[i] = scanner.nextInt();
System.out.println(arr[i]);
}
}
a = arr[0];
System.out.println(a);
b = arr[1];
System.out.println(b);
c = arr[2];
System.out.println(c);
} catch (Exception e){
System.out.println("Not Found");
}
}
}
i used this code, but from the loop that transferred the values 2, 3, 4, into the array it was read successful but i tried initializing those array values into a,b,c, but it only reads the last value and assign it to a.
You don't say what your input file looks like, so it's hard to tell you exactly what's wrong, but I suspect the issue is you are using hasNextLine in your loop, but nextInt when you read. This won't behave in the way you expect for input like this, for example:
1 2 3
Notice that there is one line, so hasNextLine will return false because, while there are multiple ints, there is only one line.
What you probably want instead is Scanner#hasNextInt
In addition, this logic is probably not correct:
for(int i = 0; i < arr.length; i++) {
while (scanner.hasNextLine()) {
arr[i] = scanner.nextInt();
System.out.println(arr[i]);
}
When a Scanner moves to the next token, you cannot go back. So you can only read from it once without creating a new scanner.
What you likely want is the following:
int i = 0;
while (scanner.hasNextInt()) {
arr[i] = scanner.nextInt();
System.out.println(arr[i]);
i++;
}
This will go through the scanner once and correctly populate your values.
for(int i = 0; i < arr.length; i++) {
while (scanner.hasNextLine()) {
arr[i] = scanner.nextInt();
System.out.println(arr[i]);
}
}
Look at the inner loop. You're running while(scanner.hasNextLiine() however i is never getting iterated while you read the file. As a result, you read the entire file, but always put it into arr[i=0].
A better solution may be
int i = 0;
while(scanner.hasNextLine() && i < arr.length){
arr[i++] = scanner.nextInt();
}
Which will combine the functionality of your while and for loop. Another alternative:
for(int i = 0; i < arr.length && scanner.hasNextLine(); i++){
arr[i] = scanner.nextInt();
}
Chris's answer is also valid. nextInt and hasNextLine aren't the same thing. But in this case I'm assuming your file has ints on every line.
I'm working on a problem that requires me to store a very large amount of integers into an integer array. The input is formatted so that one line displays the amount of integers and the next displays all of the values meant to be stored. Ex:
3
12 45 67
In the problem there is closer to 100,000 integers to be stored. Currently I am using this method of storing the integers:
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int[] iVau = new int[n];
String[] temp = scanner.nextLine().split(" ");
for(int i = 0; i < n; i++) {
iVau[i] = Integer.parseInt(temp[i]);
}
This works fine, however the problem I am solving has a strict time limit and my current solution is exceeding it. I know that there is a more efficient way to store this input using buffered readers and input streams, but I don't know how to do it, can someone please show me.
The way you are using Scanner makes your program save a String containing the whole numbers at once, in memory. With 100000 numbers in the 2nd line of your input, it is not so efficient, you could read numbers one after the other without keeping the previous one in memory. So, this way, avoiding using Scanner.readLine() should make your program run faster. You will not have to read the whole line one time, and read a 2nd time this String to parse the integers from it: you will do both of these operations only once.
Here is an example. The method testing() does not use any Scanner. The method testing2() is the one you provided. The file tst.txt contains 100000 numbers. The output from this program, on my Mac Mini (Intel Core i5#2.6GHz) is:
duration without reading one line at a time, without using a Scanner instance: 140 ms
duration when reading one line at a time with a Scanner instance: 198 ms
As you can see, not using Scanner makes your program 41% faster (integer part of (198-140)/140*100 equals 41).
package test1;
import java.io.*;
import java.util.*;
public class Test {
// Read and parse an Int from the stream: 2 operations at once
private static int readInt(InputStreamReader ir) throws IOException {
StringBuffer str = new StringBuffer();
int c;
do { c = ir.read(); } while (c < '0' || c > '9');
do {
str.append(Character.toString((char) c));
c = ir.read();
} while (!(c < '0' || c > '9'));
return Integer.parseInt(str.toString());
}
// Parsing the input step by step
private static void testing(File f) throws IOException {
InputStreamReader ir = new InputStreamReader(new BufferedInputStream(new FileInputStream(f)));
int n = readInt(ir);
int [] iVau = new int[n];
for (int i = 0; i < n; i++) iVau[i] = readInt(ir);
ir.close();
}
// Your code
private static void testing2(File f) throws IOException {
Scanner scanner = new Scanner(f);
int n = scanner.nextInt();
int[] iVau = new int[n];
scanner.nextLine();
String[] temp = scanner.nextLine().split(" ");
for(int i = 0; i < n; i++)
iVau[i] = Integer.parseInt(temp[i]);
scanner.close();
}
// Compare durations
public static void main(String[] args) throws IOException {
File f = new File("/tmp/tst.txt");
// My proposal
long t = System.currentTimeMillis();
testing(f);
System.out.println("duration without reading one line at a time, without using a Scanner instance: " + (System.currentTimeMillis() - t) + " ms");
// Your code
t = System.currentTimeMillis();
testing2(f);
System.out.println("duration when reading one line at a time with a Scanner instance: " + (System.currentTimeMillis() - t) + " ms");
}
}
NOTE: creating the input file is done this way, with bash or zsh:
echo 100000 > /tmp/tst.txt
for i in {1..100000}
do
echo -n $i" " >> /tmp/tst.txt
done
I believe this is what you're looking for. A BufferedReader can only read a line at a time, so it is necessary to split the line and cast Strings to ints.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
int n = Integer.parseInt(br.readLine());
int[] arr = new int[n];
String[] line = br.readLine().split(" ");
for (int i = 0; i < n; i++) {
arr[i] = Integer.parseInt(line[i]);
}
} catch (IOException e) {
e.getStackTrace();
}
Just a thought, String.split returns an array of Strings. You say the input can be around 100,000 values. So in order to split the array in this way, String.split must be iterating through each element. Now in parsing the new array of strings to Integers you have iterated through the collection twice. You could do this in one iteration with a few small tweaks.
Scanner scanner = new Scanner(System.in);
String tmp = scanner.nextLine();
scanner = new Scanner(tmp);
for(int i = 0; scanner.hasNextInt(); i++) {
arr[i] = scanner.nextInt();
}
The reason for linking the scanner to a String instead of leaving it on System.in is so that it ends properly. It doesn't open System.in for user input on the last token. I believe in big O notation this is the difference between O(n) and O(2n) where the original snippet is O(2n)
I am not quite sure why OP has to use Integer.parseInt(s) here since Scanner can just do the parsing directly by new Scanner(File source).
Here is a demo/test for this idea:
public class NextInt {
public static void main(String... args) {
prepareInputFile(1000, 500); // create 1_000 arrays which each contains 500 numbers;
Timer.timer(() -> readFromFile(), 20, "NextInt"); // read from the file 20 times using Scanner.nextInt();
Timer.timer(() -> readTest(), 20, "Split"); // read from the file 20 times using split() and Integer.parseInt();
}
private static void readTest() {
Path inputPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/main/java/io/input.txt"));
try (Scanner scanner = new Scanner(new File(inputPath.toString()))) {
int n = Integer.valueOf(scanner.nextLine());
int[] iVau = new int[n];
String[] temp = scanner.nextLine().split(" ");
for (int i = 0; i < n; i++) {
iVau[i] = Integer.parseInt(temp[i]);
}
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
private static void readFromFile() {
Path inputPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/main/java/io/input.txt"));
try (Scanner scanner = new Scanner(new File(inputPath.toString()))) {
while (scanner.hasNextInt()) {
int arrSize = scanner.nextInt();
int[] arr = new int[arrSize];
for (int i = 0; i < arrSize; ++i) {
arr[i] = scanner.nextInt();
}
// System.out.println(Arrays.toString(arr));
}
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
private static void prepareInputFile(int arrCount, int arrSize) {
Path outputPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/main/java/io/input.txt"));
List<String> lines = new ArrayList<>();
for (int i = 0; i < arrCount; ++i) {
int[] arr = new int[arrSize];
for (int j = 0; j < arrSize; ++j) {
arr[j] = new Random().nextInt();
}
lines.add(String.valueOf(arrSize));
lines.add(Arrays.stream(arr).mapToObj(String::valueOf).collect(Collectors.joining(" ")));
}
try {
Files.write(outputPath, lines);
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
}
Locally tested it with 1_000 arrays while each array has 500 numbers, reading all the elements cost about: 340ms using Scanner.nextInt() while OP's method about 1.5ms.
NextInt: LongSummaryStatistics{count=20, sum=6793762162, min=315793916, average=339688108.100000, max=618922475}
Split: LongSummaryStatistics{count=20, sum=26073528, min=740860, average=1303676.400000, max=5724370}
So I really have doubt the issue lies in the input reading.
Since in your case you are aware of the total count of elements all that you have to do is to read X integers from the second line. Here is an example:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int count = in.nextInt();
int array[] = new int[count];
for (int i = 0; i < count; i++) {
array[i] = in.nextInt();
}
}
If this is not fast enough, which I doubt, then you could switch to the use of a BufferedReader as follows:
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
int count = Integer.parseInt(in.readLine());
int array[] = new int[count];
for (int i = 0; i < count; i++) {
int nextInteger = 0;
int nextChar = in.read();
do {
nextInteger = nextInteger * 10 + (nextChar - '0');
nextChar = in.read();
} while (nextChar != -1 && nextChar != (int)' ');
array[i] = nextInteger;
}
}
In your case the input will be aways valid so this means that each of the integers will be separated by a single whitespace and the input will end up with EoF character.
If both are still slow enough for you then you could keep looking for more articles about Reading Integers in Java, Competative programming like this one: https://www.geeksforgeeks.org/fast-io-in-java-in-competitive-programming/
Still my favorite language when it comes to competitions will always be C :) Good luck and enjoy!
I want to read and save the content of the file in a 2d array, but I don't know the size of the file, because the program should read different files. So there is the first problem after "new char". I searched for the problem and found that "matrix[x][y]=zeile.charAt(x);"
should be right, but that throws the error "NullPointerException" when I write any number into the first brackets of new char.
Could somebody explain and give some ideas oder solutions? Thank you :)
import java.io.*;
class Unbenannt
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("Level4.txt");
BufferedReader br = new BufferedReader(fr);
String zeile = br.readLine();
char [][] matrix = new char [][];
while(zeile != null )
{
int y = 0;
for(int x = 0; x < zeile.length(); x++) {
matrix[x][y] = zeile.charAt(x);
}
y++;
} System.out.print(matrix);
br.close();
}
}
Arrays are stored as blocks in memory in order to achieve O(1) operations, which is why you need to define their size during definition. If you insist on arrays (rather than a dynamic ADT such as List), you'll need to know the dimensions in advance.
What you could do is store the file lines temporarily in a list and find out the maximum line length, i.e.:
List<String> lines = new ArrayList<String>();
String zeile = null;
int max = 0;
while ((zeile = br.readLine()) != null) {
lines.add(zeile);
if (zeile.length() > max)
max = zeile.length();
}
char[][] matrix = new char[lines.length()][max];
// populate the matrix:
for (int i = 0; i < lines.length(); i++) {
String line = lines.get(i);
for (int j = 0; j < line.length(); j++) {
matrix[i][j] = line.charAt(j);
}
}
Note that since char is a primitive, you'll be initialized with the default value 0 (the integer, not the character!) in every cell of the inner array, so for lines which are shorter than the others, you'll have trailing zero characters.
you initialize the matrix (char [][]) but you never initialize any of the inbound arrays. This leads to the NullPointerException.
In addition your 'while' condition looks invalid, seems you only are reading the first line of your file here > your code will never complete and read the first line over and over again
Thank you all! It works! But there is still one problem. I changed lines.length() into lines.size(), because it doesn't work with length. The problem is the output. It shows for example: xxxx xxxx instead of "xxx" and "x x" and "xxx" among each other.
How can I build in a line break?
my programcode is:
import java.io.*;
import java.util.ArrayList;
class Unbenannt
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("Level4.txt");
BufferedReader br = new BufferedReader(fr);
ArrayList<String> lines = new ArrayList<String>();
String zeile = null;
int max = 0;
while ((zeile = br.readLine()) != null) {
lines.add(zeile);
if (zeile.length() > max)
max = zeile.length();
}
char [][] matrix = new char[lines.size()][max];
for(int i = 0; i < lines.size(); i++) {
String line = lines.get(i);
for(int j = 0; j < line.length(); j++) {
matrix[i][j] = line.charAt(j);
System.out.print(matrix[i][j]);
}
}
br.close();
}
}
I have been testing my code for the overlapping rectangles challenge on codeeval. I feel my code is close to the solution as I have tested it on my machine and it appears correct. Codeeval is picky however and won't execute the code, claiming it is hanging.No further information is given. It has done this in the past but that was due to me not closing my scanner at the end. Am I violating a similar principle here?
Any recommendations on finding the solution simpler or better coding practices is appreciated.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws FileNotFoundException {
File file = new File("C:/Users/minda_000/Desktop/text.txt");
FileReader fr = new FileReader(file);
Scanner scan = new Scanner(fr);
scan.useDelimiter(",");
boolean flag = true;
while (scan.hasNextLine()) {
String line = scan.nextLine();
Scanner scanline = new Scanner(line);
scanline.useDelimiter(",");
int lxa = scanline.nextInt();
int lya = scanline.nextInt();
int rxa = scanline.nextInt();
int rya = scanline.nextInt();
int lxb = scanline.nextInt();
int lyb = scanline.nextInt();
int rxb = scanline.nextInt();
int ryb = scanline.nextInt();
int[] contentsofx = contentsOfX(lxa, rxa);
int[] contentsofy = contentsOfY(lya, rya);
int[] contentsofx2 = contentsOfX(lxb, rxb);
int[] contentsofy2 = contentsOfY(lyb, ryb);
scanline.close();
for (int i = 0; i < contentsofx.length; i++) {
for (int j = 0; j < contentsofx2.length; j++) {
if (contentsofx[i] == contentsofx2[j]) {
if(i<contentsofy.length && i<contentsofy2.length && contentsofy[i]==contentsofy2[j]){
System.out.println(true);
flag=false;
}
}
}
}
if(flag) {
System.out.println(false);
}
flag=true;
}
scan.close();
}
public static int[] contentsOfX(int lx, int rx) {
int[] line = new int[(rx - lx)];
for (int i = 0; i < line.length; i++) {
line[i] = lx + i;
}
return line;
}
public static int[] contentsOfY(int ly, int ry) {
int[] line = new int[(ly - ry)];
for (int i = 0; i < line.length; i++) {
line[i] = ry + i;
}
return line;
}
}
Just to make sure, you are changing "C:/Users/minda_000/Desktop/text.txt" to args[0] before uploading your solution to CodeEval, right?
Some of the other issues:
You're outputting True and False in lowercase when they're supposed to be capitalized.
In this line --
if(i<contentsofy.length && i<contentsofy2.length && contentsofy[i]==contentsofy2[j]){
-- you've got a problem when i and/or j are larger than the lengths of contentsofy and contentsofy2.
And comments would make your code easier to read. :-)
I scrapped this code and started over more or less with a much cleaner solution just using boolean logic. The problems with this code is the contentsOfX and contentsOfY methods should be 1 size greater for one point overlap. Additionally, at this time I implied one rectangle would always be to the left of the other. The nested for loop does not work as intended because of this. Still the arrays are sorted for each value from minimum value of x,y to maximum value of x,y so if you check for the reverse polarity index within the array as well the logic should be the work.
This was my online interview question, and I already submitted the answer. However, the compilation was terminated due to time so I just submitted. Could I get feedback from you? Thanks in advance.
Problem:
Given N numbers , [N<=10^5] we need to count the total pairs of numbers that have a difference of K
Input Format:
1st line contains N & K (integers).
2nd line contains N numbers of the set. All the N numbers are assured to be distinct.
Output Format:
One integer saying the no of pairs of numbers that have a diff K.
Sample Input #00:
5 2
1 5 3 4 2
Sample Output #00:
3
My code:
import java.io.*
import java.util.*;
public class DiffNumbers {
public static void main(String[] args) throws Exception {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line1 = in.readLine();
String line2 = in.readLine();
int n = Integer.parseInt(line1.split(" ")[0]);
int diff = Integer.parseInt(line1.split(" ")[1]);
Hashtable table = new Hashtable();
int[] arr = new int[n];
for(in i=0; i<n; i++) {
arr[i] = Integer.parseInt(line2.split(" ")[i]);
table.put(Integer.parseInt(line2.split(" ")[i]));
}
int count = 0;
for(in i=0; i<n; i++) {
if(table.containsKey(arr[i]+diff) {
count++;
}
}
system.out.println(count);
}
}
Using HashMap/Table needs extra space. If you want to avoid it you can do it this way
1) Sort the array
2) initialize outputCount as 0
3) Let there be two pointers. "first" start with 0 and "Other" pointer start with 1.
4)
while(arr[other]-arr[first] <requiredDifference)
other ++;
if(arr[other]-arr[first] == requiredDifference)
outputCount++;
else // no match for arr[first]
first++;
5)
return outputCount;
explanation :-
When difference is more than requiredDifference you stop moving ahead "other" poiner. So there is no match for arr[first]. So move ahead first counter. Now do the same logic for new arr[first]. This time you will continue checking from current position of "other" as array is sorted; lower number will not have required match.
public static void main(String[] args) throws Exception{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line1 = in.readLine();
String line2 = in.readLine();
int diff = Integer.parseInt(line1.split(" ")[1]);
Map<Integer, Object> nMap = new HashMap<Integer, Object>();
Map<Integer, Boolean> uMap = new HashMap<Integer, Boolean>();
Map<Integer, Boolean> lMap = new HashMap<Integer, Boolean>();
String[] numbers = line2.split(" ");
//init maps
for(String number : numbers){
Integer intValue = Integer.valueOf(number);
nMap.put(intValue, new Object()); //original set, N
uMap.put(intValue + diff, false); //upper-bound map
lMap.put(intValue - diff, false); //lower-bound map
}
int count = 0;
for(Integer nKey : nMap.keySet()){
//Do if the lower-bound of n exists in N and if n hasn't used as an upper-bound?
if(nMap.get(nKey - diff) != null && !uMap.get(nKey)){
count++;
//Mark the lower-bound as used.
lMap.put(nKey - diff, true);
}
//Do if the upper-bound of n exists in N and if n hasn't used as an lower-bound?
if(nMap.get(nKey + diff) != null && !lMap.get(nKey)){
count++;
//Mark the upper-bound as used.
uMap.put(nKey + diff, true);
}
}
System.out.println(count);
}
There's not much reason to store the integers in both an array and a hashtable. We can modify your code to do the all of the work in a single for loop.
for(int i=0; i<n; i++) {
int j = Integer.parseInt(line2.split(" ")[i]) //probably not how I would go about this
table.put(j);
if(table.containsKey(j+diff)) {
count++;
}
if(table.containsKey(j-diff)) {
count++;
}
}