splitting a text into words using bufferReader - java

I have an issue solving a problem. I have to add ONLY words into a treeset (and output the size of treeset) using bufferedReader but the problem is I cannot pass the compilator speed test limit. The text contains only letters and whitespaces (it can be an empty line). I have to find out a new solution but seems not this :
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
Set<String> text = new TreeSet<String>();
String words[], line;
while ((line = read.readLine()) != null) {
words = line.split("\\s+");
for (int i = 0; i < words.length && words[0].length() > 0; i++) {
text.add(words[i]);
}
}
System.out.println(text.size());
Is there any other "split" method to use so the compiler use less "time-thinking"?

In line
words = line.split("\\s+");
you split by regex, which is much slower, than splitting by one char (5 times on my machine).
Java split String performances
If the words are exactly separated by only one space, then the solution is simple
words = line.split(" ");
just replace with this line and your code will run faster.
If words can be separated by several spaces, then add such a line after the loop
text.remove("");
and still replace your regex split with 1 char split.
public class Test {
public static void main(String[] args) throws IOException {
// string contains 1, 2 and two spaces between 1 and 2. text size should be 2
String txt = "1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n" +
"1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n" +
"1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n" +
"1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n" +
"1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1\n" +
"1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1";
InputStream inpstr = new ByteArrayInputStream(txt.getBytes());
BufferedReader read = new BufferedReader(new InputStreamReader(inpstr));
Set<String> text = new TreeSet<>();
String[] words;
String line;
long startTime = System.nanoTime();
while ((line = read.readLine()) != null) {
//words = line.split("\\s+"); -- runs 5 times slower
words = line.split(" ");
for (int i = 0; i < words.length; i++) {
text.add(words[i]);
}
}
text.remove(""); // add only if words can be separated with multiple spaces
long endTime = System.nanoTime();
System.out.println((endTime - startTime) + " " + text.size());
}
}
Also you can replace your for loop with
text.addAll(Arrays.asList(words));

based on the assumption you provided, I would simply add everything to the set and at the end delete unwanted values from it. This hopefully reduces the time to check for the condition (which is not much really)
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
Set<String> text = new TreeSet<String>();
String words[], line;
while ((line = read.readLine()) != null) {
words = line.split("\\s+");
for(String value: words) {
text.add(value);
}
}
text.remove(" ");
text.remove("");
text.remove(null);
System.out.println(text.size());

You can of course stream your BufferedReader into your TreeSet:
Collection<String> c = read.lines().flatMap(line -> Stream.of(line.split("\\s+")).filter(word -> word.length() > 0)).collect(Collectors.toCollection(TreeSet::new));

Related

list combinations

How to list combinations in java with methods that stack upon each other.
To print the combinations, you need to print when amount == 0.
To do that, you need to accumulate what has been done to get to that value, i.e. which coins has been applied to the amount value.
One way would be to build a string, appending a space and the coin value as part of the recursive call. The resultant string will start with a space, so it has to be skipped when printing.
public static int combo(int amount, int currentCoin, String combo) {
// Added: ^^^^^^^^^^^^^^
if (amount == 0) {
System.out.println(combo.substring(1)); // <<<<< Added
return 1;
}
if (amount < 0) {
return 0;
}
int nCombos = 0;
for (int coin = currentCoin; coin < coins.length; coin++) {
nCombos += combo(amount - coins[coin], coin, combo + " " + coins[coin]);
// Added: ^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
return nCombos;
}
Test
System.out.println("combo = " + combo(20, 0, ""));
// Added: ^^^^
Output
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 5
1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2
1 1 1 1 1 1 1 1 1 1 1 1 1 2 5
1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2
1 1 1 1 1 1 1 1 1 1 1 2 2 5
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2
1 1 1 1 1 1 1 1 1 1 5 5
1 1 1 1 1 1 1 1 1 2 2 2 5
1 1 1 1 1 1 1 1 2 2 2 2 2 2
1 1 1 1 1 1 1 1 2 5 5
1 1 1 1 1 1 1 2 2 2 2 5
1 1 1 1 1 1 2 2 2 2 2 2 2
1 1 1 1 1 1 2 2 5 5
1 1 1 1 1 2 2 2 2 2 5
1 1 1 1 1 5 5 5
1 1 1 1 2 2 2 2 2 2 2 2
1 1 1 1 2 2 2 5 5
1 1 1 2 2 2 2 2 2 5
1 1 1 2 5 5 5
1 1 2 2 2 2 2 2 2 2 2
1 1 2 2 2 2 5 5
1 2 2 2 2 2 2 2 5
1 2 2 5 5 5
2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 5 5
5 5 5 5
combo = 29

I need help on a code with average rating on 2D array in JAVA

I need help with my code which that my input ratings isĀ 
-1 2 3 5 -1 5 3 3 1 4 2 2 5 -1 1 3 3 5 4 3
-1 1 1 4 1 3 3 1 2 3 4 -1 4 1 2 4 5 4 2 3
3 -1 2 3 -1 2 5 -1 3 3 5 2 2 1 2 3 5 3 4 2
-1 1 -1 4 1 3 5 2 1 5 3 -1 5 2 1 3 4 5 3 2
-1 -1 3 2 -1 5 5 2 2 4 4 2 3 2 -1 3 4 4 3 1
2 1 1 5 2 2 4 2 3 4 3 -1 5 2 2 5 3 5 2 1
3 -1 3 4 -1 2 5 -1 -1 4 3 -1 3 -1 2 5 5 5 4 2
4 -1 4 2 3 -1 1 3 4 -1 1 4 4 4 -1 2 -1 1 4 4
4 3 3 3 -1 2 2 4 3 -1 2 4 3 4 2 -1 -1 2 2 3
3 -1 3 -1 3 4 -1 5 5 -1 -1 -1 1 -1 -1 1 1 2 -1 5
3 -1 3 4 3 4 -1 5 5 2 3 3 4 1 1 -1 -1 -1 -1 4
4 -1 4 4 1 3 -1 5 4 -1 1 3 4 1 -1 1 -1 1 -1 5
5 -1 3 1 4 3 -1 5 4 1 3 2 1 -1 4 2 1 -1 2 4
3 -1 5 1 4 4 2 5 5 1 2 3 1 1 -1 1 -1 1 -1 5
4 1 5 4 3 -1 1 3 4 -1 -1 3 3 -1 1 1 2 -1 3 5
-1 1 1 3 -1 3 1 3 -1 -1 3 -1 5 2 2 1 4 -1 5 -1
3 -1 2 3 1 5 4 3 3 -1 5 -1 5 2 -1 4 4 3 3 3
1 1 1 3 2 4 1 -1 -1 -1 5 -1 3 -1 -1 1 -1 2 5 2
-1 2 3 5 -1 4 3 1 1 3 3 -1 4 -1 -1 4 3 2 5 1
-1 1 3 3 -1 3 3 1 -1 -1 3 -1 5 -1 -1 3 1 2 4 -1
3 -1 2 4 1 4 3 -1 2 3 4 1 3 -1 2 -1 4 3 5 -1
-1 1 3 5 -1 4 2 1 -1 3 3 2 3 2 -1 3 1 -1 3 -1
3 2 2 3 -1 5 -1 -1 2 3 4 -1 4 1 -1 -1 -1 -1 4 2
-1 3 -1 -1 4 -1 2 -1 2 2 2 5 -1 3 4 -1 -1 2 -1 2
1 4 3 -1 3 2 1 -1 -1 -1 1 3 1 3 3 1 -1 -1 -1 3
4 3 3 -1 4 2 -1 4 -1 -1 2 4 -1 3 4 2 -1 -1 -1 4
-1 5 1 -1 4 1 -1 3 2 2 -1 4 1 3 3 1 -1 -1 -1 3
-1 4 2 1 5 -1 -1 2 1 1 -1 5 -1 5 4 1 2 2 -1 1
2 5 2 -1 3 -1 -1 1 -1 2 -1 4 2 4 3 -1 2 1 -1 -1
2 5 1 1 4 -1 2 1 -1 -1 2 4 -1 3 4 2 -1 -1 -1 4
which I am taking the first role of the rate by vertically which my average[] has 20 values.
I am confused about where is wrong with my code such that if number = -1, then it set to 0 and then doesn't count.
This is a code to count the average rating of a book, my average[] value comes out different then my calculation on a calculator.
public static double [] recommandratings(double[][]ratings) {
double [] average = new double[20];
int [] count = new int[20];
double[] sum = new double[30];
Arrays.fill(count,0);
Arrays.fill(sum, 0);
for(int i= 0;i<20;i++) {
for(int j=0; j<30; j++) {
if(ratings[j][i] == -1) {
ratings[j][i] = 0;
sum[i] += ratings[j][i];
count[i]--;
} else {
sum[i] += ratings[j][i];
count[i]++;
}
}
}
for(int a =0; a<20;a++) {
average[a] = sum[a]/count[a];
}
return average;
}
I think the way of iteration of the 2D array is wrong in your case. I made the following changes to make it simple and dynamic. I hope the following code will give you desired result.
public static double [] recommandratings (double[][]ratings) {
int rowSize = ratings.length;
int colSize = ratings[0].length;
double [] average = new double[colSize];
int[] count = new int[colSize];
for (int row= 0;row < rowSize;row++) {
for (int col=0; col < colSize; col++) {
if (ratings[row][col] != -1) {
average[col] += ratings[row][col];
count[col]++;
}
}
}
for (int a =0; a < colSize;a++) {
int sum = (int) average[a];
average[a] = average[a] / count[a];
System.out.println("count[" + a + "]=" + count[a] + "; sum[" + a + "]=" + sum + "; average[" + a + "]=" + average[a]);
}
return average;
}
P.S. I removed the sum[] and reused the average[] to optimize memory.
Update
This update is based on the comments where you state that the count[a] is always returning 30, where it should be less than 30. I performed a test with both your exact dataset and a smaller dataset. I found my solution is returning less than 30 which is expected. Therefore, I think you made some mistake in integrating my solution. So, I have made a gist with complete source code and input/output as well which will help you integrate it correctly.
Since you don't want to count number with value -1, there is no use of count[i]-- because you are increasing count only when there is a number not equal to -1.

How can i split the following string based upon double spaces, single spaces, ^, :and |? [duplicate]

This question already has answers here:
How do I split a string in Java?
(39 answers)
Closed 5 years ago.
How can i split the following string based upon double spaces, single spaces, ^, : and |
0 0 0 0 0 : 0 0 0 0 0 | 0 0 0 0 0 : 0 0 0 0 0 | 0 0 ^ 0 0 0 : 0 0 0 0 0 | 0 0 0 0 0 : 0 0 6 4 5 | 1 1 8 7 1 : 9 1 6 5 16 | 0 0 0 0 0 : 1 4 25 0
You can try splitting the string like below
String abc = "0 0 : 25 ^ 2 : 1 | 0";
String[] stringarr = abc.split("[ ]+|\\:+|\\^+|\\|");

How to make InputStream skip over a line if it starts with '#'?

I am writing a program that has to decode QR Codes. The codes are internally represented as a 2D Boolean List. The codes will usually be read as text files containing 1s and 0s, where 1 means a dark module (true) in the matrix, and 0 a light module (false).
I have to implement a method, which will take an InputStream and then has to return a QR Code back. I'll have to read .txt which contains 1s, 0s and comment lines beginning with '#'. I need to make the method ignore those comment lines, but I am not sure how to do it.
Here are some relevant parts of the code:
First the QR Code constructor (All of the methods used in the constructor work and do their job):
public class QRCode {
private List<List<Boolean>> data; //A 2D Boolean matrix, true means black, false means white.
public QRCode(List<List<Boolean>> data)
{
if (data == null)
throw new NullPointerException();
if (QRCode.isQuadratic(data) == false)
throw new InvalidQRCodeException("Matrix must be quadratic!");
if (QRCode.versionCheck(data) < 1 || QRCode.versionCheck(data) > 40)
throw new InvalidQRCodeException("Invalid Dimensions (Version).");
if (QRCode.correctlyAlligned(data) != true)
throw new InvalidQRCodeException("Improper Allignment!");
if (QRCode.correctTimers(data) != true)
throw new InvalidQRCodeException("Incorrect Timing Pattern!");
if (QRCode.correctFormatting(data) != true)
throw new InvalidQRCodeException("Incorrect Formatting!");
this.data = data;
}
}
This is the method I'm referring to. What I wrote sofar at least. Also, if the .txt file contains anything other than 1s, 0s and comment, it should throw an exception.
PS: I've never used InputStreams before, I tried googling this but all answers I found were for specific types of Streams, and they use a .readLine() method, which my IS here is not letting me use.
public static QRCode fromFile(InputStream is) throws IOException
{
int i;
List<List<Boolean>> data = new ArrayList<>(); //a 2D Boolean Matrix
int y = -1, x = -1;
if (is == null)
throw new NullPointerException();
while((i = is.read())!=-1) //Reading begin
{
if (i == (byte) '\n') //If a line in .txt file ends.
{
y++;
data.add(new ArrayList<Boolean>());
x = 0;
}
if ((char) i == '1') //|| (char) i == '0')
{
data.get(y).add(true);
x++;
}
if ((char) i == '0') //||
{
data.get(y).add(false);
x++;
}
}
return new QRCode(data);
}
An example of text files that I'd be handling:
# name: small
# type: bool matrix
# rows: 25
# columns: 25
1 1 1 1 1 1 1 0 1 1 1 1 0 1 1 0 1 0 1 1 1 1 1 1 1
1 0 0 0 0 0 1 0 0 0 0 1 1 1 1 0 0 0 1 0 0 0 0 0 1
1 0 1 1 1 0 1 0 0 1 0 1 0 1 0 1 0 0 1 0 1 1 1 0 1
1 0 1 1 1 0 1 0 0 0 1 1 0 1 0 0 0 0 1 0 1 1 1 0 1
1 0 1 1 1 0 1 0 0 0 1 1 1 0 0 0 1 0 1 0 1 1 1 0 1
1 0 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 0 1 0 0 0 0 0 1
1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0 1 1 0 0 1 1 1 1 0 0 0 0 0 0 0 0 0
1 1 0 1 1 0 1 0 0 1 0 0 1 0 1 1 0 0 1 0 0 0 0 0 1
1 1 1 1 0 0 0 0 1 0 1 0 0 1 1 1 0 0 0 1 1 1 0 0 0
1 0 0 1 1 1 1 0 1 1 0 0 1 1 0 1 1 0 1 1 1 0 1 0 1
0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 1 0 1 1 1 1 0
0 1 1 0 0 1 1 1 0 1 1 0 0 0 0 0 1 0 1 1 0 1 0 1 1
1 1 0 0 0 1 0 0 0 0 1 0 1 0 1 1 1 1 0 0 1 1 0 1 0
1 1 1 0 0 0 1 1 0 1 0 0 0 1 1 1 1 0 1 0 0 0 0 1 1
1 0 1 1 0 1 0 0 0 0 1 0 1 0 1 0 1 0 0 1 0 1 1 0 1
1 0 1 1 0 1 1 1 1 0 0 1 1 1 0 1 1 1 1 1 1 0 1 1 1
0 0 0 0 0 0 0 0 1 0 1 1 0 1 0 0 1 0 0 0 1 0 1 0 1
1 1 1 1 1 1 1 0 0 1 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1
1 0 0 0 0 0 1 0 0 0 1 1 0 1 1 0 1 0 0 0 1 1 0 0 0
1 0 1 1 1 0 1 0 1 0 0 1 0 1 0 1 1 1 1 1 1 1 0 1 1
1 0 1 1 1 0 1 0 1 0 0 0 1 1 1 0 0 1 1 0 0 0 1 1 1
1 0 1 1 1 0 1 0 0 0 1 1 0 1 0 0 1 1 0 1 1 0 0 1 1
1 0 0 0 0 0 1 0 1 0 1 1 1 1 0 0 0 0 1 1 0 1 1 1 1
1 1 1 1 1 1 1 0 1 0 1 1 1 1 0 0 1 0 1 0 0 1 0 0 1
First, I suggest you use a Reader to read text. Then you can use a BufferedReader with its readLine() method to work with lines of text, rather than a stream of bytes.
Regardless, given your current code: once your read a \n, set a boolean flag to indicate that you've just saw a new line character. Then, as you begin reading the next line, switch on that flag such that if it's true, and you see a # as the next character, you should read until you see another \n. If it the flag is not true, then read the rest of the line as you are doing.
You may want to consider whitespace when finding the #, depending how lax you want this to be.
Why not use Files.lines instead of InputStream?
Files.lines(Paths.get("path_to_File.txt")).filter(s -> !s.contains("#"));// let's
//read all lines form the file and skip the lines with `#` symbol
Than we can convert each line to a list of Boolean:
s -> Stream.of(s.split(" ")).map("1"::equals).collect(Collectors.toList())// split
string by ` ` (space) symbol and convert to Boolean "1" - true, "0" - false
Now let's put everything together:
List<List<Boolean>> qr = Files.lines(Paths.get("data/fromFile.txt"))
.filter(s -> !s.contains("#")).map(
s -> Stream.of(s.split(" ")).map("1"::equals)
.collect(Collectors.toList())
).collect(Collectors.toList());
For the file:
# name: small
# type: bool matrix
# rows: 1
# columns: 3
1 1 1
1 0 1
Output will be
[true, true, true]
[true, false, true]
If you decide to use Reader then you may use regex to eleminate the lines which includes any character except '0' and '1'. You can find detail about regex usage below link.
How to check if a string contains only digits in Java
You can modify regex expression for only 1 and 0 like String regex = "[0-1]+";
After you can use below sample code to get each character.
String s1="hello";
char[] ch=s1.toCharArray();

Dynamic programming: Find largest diamond (rhombus)

I have a small program to do in Java. I have a 2D array filled with 0 and 1, and I must find the largest rhombus (as in square rotated by 45 degrees) and their numbers.
Example:
0 1 0 0 0 1
1 0 1 1 1 0
1 0 1 1 1 1
0 1 1 1 1 1
0 0 1 1 1 1
1 1 1 1 1 1
Result:
1
1 1 1
1 1 1 1 1
1 1 1
1
The problem is similar to this SO question.
If you have any idea, post it here.
This too long for a comment. I'll post my solution later on if you can't solve it but here's how I've done it (in less than 15 lines of code): I first created a second array (a little big bigger [n+2][n+2]) and did n/2 pass:
0 0 0 0 0 0 0 0
0 0 1 0 0 0 1 0
0 1 0 1 1 1 0 0
0 1 0 1 2 2 1 0
0 0 1 2 2 2 1 0
0 0 0 1 2 2 1 0
0 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 1 0 0 0 1 0
0 1 0 1 1 1 0 0
0 1 0 1 2 2 1 0
0 0 1 2 3 2 1 0
0 0 0 1 2 2 1 0
0 1 1 1 1 1 1 0
0 0 0 0 0 0 0 0
Where a non-zero number x means "I'm the center of a rhombus of size x" (I'm expressing the size in relation with the length of the diagonals [which are both equal in your case] of the rhombus). You can find if you have the center of a rhombus of size (k+1) by checking if {top,right,down,left} are all the centers of rhombus of size k.
The advantage of first creating a bigger array is that it really simplifies your logic but I could do it in place, with a more convoluted logic, by modifying the original array or by using a second array of the same size as the input (once again, it's way easier to simply put a safe "fence" of all-zeroes around your input).
If you don't "surround" your array with a fence, you have a lot of additional if/else checks: this would be prone to errors, lead to bigger code and lead to uglier code.
Short tutorial:
How would you solve the problem if it was a 1x1-field?
How could you formulate the problem recursively?
How could you remember intermediate results and use them?
Do it.
void rhombus()
{
maxr=0;
for (int i=n-1;i>=0;i--)
{
for (int j=n-1;j>=0;j--)
{
if (b[i][j]>0)
{
if ((i==n-1) || (j==n-1) || (i==0) || (j==0)) b[i][j]=1;
else {
b[i][j]=min4(b[i][j+1],b[i][j-1],b[i+1][j],b[i-1][j])+1;
if (b[i][j]==maxr) nrr++;
else if (b[i][j]>maxr) {
nrr=1;
maxr=b[i][j];
}
}
}
}
}
}
Did it,it works,this is my function,where maxr is the max size of the rhombus,and nrr is the number of max sized rhombus.Not sure how it works on huge arrays.(i loop this function n/2 times)

Categories

Resources