I'm currently stuck on a problem from CodeAbbey. I don't want an answer to the entire thing.
This is the meat of the question:
Input data will have:
initial integer number in the first line;
one or more lines describing operations, in form sign value where sign is either + or * and value is an integer;
last line in the same form, but with sign % instead and number by which the result should be divided to get the remainder.
Answer should give remainder of the result of all operations applied sequentially (starting with initial number) divided by the last number.
My problem is with the logic. So far I realize there is an operator, a space and then a number. To get the number I thought of using
char c = src.charAt(2);
and to get the operator I'd use the same thing. Then I'd just use a bunch of if-else statements to figure out the rest. But how do I do this in the large scale? How do I read all of those numbers in and do it for every one of them? A nudge on the right direction would help.
import java.util.Scanner;
public class Challenge14 {
static Scanner in = new Scanner(System.in);
public static void main(String[] args) {
System.out.println("Enter Your first number: ");
int x = in.nextInt();
for (int i = 0; i < 7; i++) {
String[] s = new String[i];
s = in.nextLine();
}
}
}
One of the more helpful classes for this problem is the Scanner.
The Scanner documentation is located at:
https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
The Scanner can be set to read from a String, File, or Input Stream.
The Scanner has several useful methods, including:
hasNext(), which lets you know if there are any other operators or numbers to pick up
next(), which will read the next token as a String
nextInt(), which will read the next token as an int
You can use the scanner to pick up the first number, then use some sort of loop to perform operations on that number until there are no more operations to perform.
Assuming that the input is from a file, what you want to do is this:
Read the first line in as a number
Split the input on each other line on whitespace, so you're left with something that can be interpreted as an operator, and something that can be interpreted as a number
Perform the operations and accumulate your result
The file portion is likely what you're struggling with. The answer below addresses that. I leave the rest as an exercise for the reader.
public class Accumulator {
private int result;
public void readFile(String filename) {
try(Scanner scan = new Scanner(new File(filename)) {
// Unconditionally read the first line as a number
result += Integer.parseInt(scan.nextLine());
//Now, we need to read in each other line remaining.
while(scan.hasNextLine()) {
String[] contents = scan.nextLine().split();
int number = Integer.parseInt(contents[1]);
// The operator is in contents[0]
performArithmeticWith(contents[0], number);
}
} catch(IOException e) {
e.printStackTrace();
}
}
public void performArithmeticWith(String operator, int number) {
switch(operator) {
case "+":
break;
// etc
}
}
}
My problem is with the logic. So far I realize there is an operator, a space and then a number.
There are several options in Java to separate the operator and the operand.
You can use the String.split() method:
String[] token input.split(" ");
//token[0] will be your operator
//token[1] will be your number
You can also use the indexOf() method:
int idx = input.indexOf(" ");
String opr = input.substring(0, idx); //your operator
String num = input.substring(idx+1); //your number
This is my approach.
Assumption is that you will get all the values as String array (Which
I believe is much easy compare to making a scalable solution).
Here's my code. You can support additional operators easily and the sequence of operator does not matter.
package com.stack.overflow.test;
import java.math.BigDecimal;
public class Calculator {
public static void main(String[] args) {
String[] values = {"5", "+", "3", "*", "7", "+", "10", "*", "2", "*", "3", "+", "1", "%", "11"};
new Calculator().calculate(values);
}
public void calculate(String[] inputs) {
BigDecimal result = null;
for(int i = 0; i < inputs.length-2;) {
String left = inputs[i];
String operator = inputs[++i];
String right = inputs[++i];
System.out.println("left : "+ left);
System.out.println("operator : "+ operator);
System.out.println("right : "+ right);
result = Operator.instanceOf(operator).apply(new BigDecimal(left), new BigDecimal(right));
inputs[i] = result.toString();
System.out.println("Result :: "+ result);
}
}
}
enum Operator {
ADD("+") {
BigDecimal apply(BigDecimal left, BigDecimal right) {
return left.add(right);
}
},
MULTIPLY("*"){
BigDecimal apply(BigDecimal left, BigDecimal right) {
return left.multiply(right);
}
},
REMAINDER("%"){
BigDecimal apply(BigDecimal left, BigDecimal right) {
return left.remainder(right);
}
};
private String symbol;
Operator(String symbol) {
this.symbol = symbol;
}
public static Operator instanceOf(String givenSymbol) {
for(Operator operator : Operator.values()) {
if(operator.symbol.equals(givenSymbol)) {
return operator;
}
} throw new RuntimeException("Operator not supported : "+givenSymbol);
}
abstract BigDecimal apply(BigDecimal left, BigDecimal right);
}
Result
left : 5
operator : +
right : 3
Result :: 8
left : 8
operator : *
right : 7
Result :: 56
left : 56
operator : +
right : 10
Result :: 66
left : 66
operator : *
right : 2
Result :: 132
left : 132
operator : *
right : 3
Result :: 396
left : 396
operator : +
right : 1
Result :: 397
left : 397
operator : %
right : 11
Result :: 1
The input data contains a number at the first line. Then an operation and a number delimited by a space on each consecutive line. Here is one approach to read in the data.
First, read the data line by line, until there are no more lines. Since there is only one element on the first line, read it and convert it to an integer (it looks like all data is integers). A Scanner can be used to read the data line by line. The two useful methods here are:
public boolean hasNextLine() - Returns true if there is another line in the input of this scanner.
public String nextLine() - Advances this scanner past the current line and returns the input that was skipped.
For each line after that, read it, and split it based on the white space using String[] splited = str.split("\\s+");. Then process the string, and read the next line. Note that split, splits based on white space by default and "\\s+" is there just for explicitness.
Related
I am working on an exercise with the following criteria:
"The input consists of pairs of tokens where each pair begins with the type of ticket that the person bought ("coach", "firstclass", or "discount", case-sensitively) and is followed by the number of miles of the flight."
The list can be paired -- coach 1500 firstclass 2000 discount 900 coach 3500 -- and this currently works great. However, when the String and int value are split like so:
firstclass 5000 coach 1500 coach
100 firstclass
2000 discount 300
it breaks entirely. I am almost certain that it has something to do with me using this format (not full)
while(fileScanner.hasNextLine())
{
StringTokenizer token = new StringTokenizer(fileScanner.nextLine(), " ")
while(token.hasMoreTokens())
{
String ticketClass = token.nextToken().toLowerCase();
int count = Integer.parseInt(token.nextToken());
...
}
}
because it will always read the first value as a String and the second value as an integer. I am very lost on how to keep track of one or the other while going to read the next line. Any help is truly appreciated.
Similar (I think) problems:
Efficient reading/writing of key/value pairs to file in Java
Java-Read pairs of large numbers from file and represent them with linked list, get the sum and product of each pair
Reading multiple values in multiple lines from file (Java)
If you can afford to read the text file in all at once as a very long String, simply use the built-in String.split() with the regex \\s+, like so
String[] tokens = fileAsString.split("\\s+");
This will split the input file into tokens, assuming the tokens are separated by one or more whitespace characters (a whitespace character covers newline, space, tab, and carriage return). Even and odd tokens are ticket types and mile counts, respectively.
If you absolutely have to read in line-by-line and use StringTokenizer, a solution is to count number of tokens in the last line. If this number is odd, the first token in the current line would be of a different type of the first token in the last line. Once knowing the starting type of the current line, simply alternating types from there.
int tokenCount = 0;
boolean startingType = true; // true for String, false for integer
boolean currentType;
while(fileScanner.hasNextLine())
{
StringTokenizer token = new StringTokenizer(fileScanner.nextLine(), " ");
startingType = startingType ^ (tokenCount % 2 == 1); // if tokenCount is odd, the XOR ^ operator will flip the starting type of this line
tokenCount = 0;
while(token.hasMoreTokens())
{
tokenCount++;
currentType = startingType ^ (tokenCount % 2 == 0); // alternating between types in current line
if (currentType) {
String ticketClass = token.nextToken().toLowerCase();
// do something with ticketClass here
} else {
int mileCount = Integer.parseInt(token.nextToken());
// do something with mileCount here
}
...
}
}
I found another way to do this problem without using either the StringTokenizer or the regex...admittedly I had trouble with the regular expressions haha.
I declare these outside of the try-catch block because I want to use them in both my finally statement and return the points:
int points = 0;
ArrayList<String> classNames = new ArrayList<>();
ArrayList<Integer> classTickets = new ArrayList<>();
Then inside my try-statement, I declare the index variable because I won't need that outside of this block. That variable increases each time a new element is read. Odd elements are read as ticket classes and even elements are read as ticket prices:
try
{
int index = 0;
// read till the file is empty
while(fileScanner.hasNext())
{
// first entry is the ticket type
if(index % 2 == 0)
classNames.add(fileScanner.next());
// second entry is the number of points
else
classTickets.add(Integer.parseInt(fileScanner.next()));
index++;
}
}
You can either catch it here like this or use throws NoSuchElementException in your method declaration -- As long as you catch it on your method call
catch(NoSuchElementException noElement)
{
System.out.println("<###-NoSuchElementException-###>");
}
Then down here, loop through the number of elements. See which flight class it is and multiply the ticket count respectively and return the points outside of the block:
finally
{
for(int i = 0; i < classNames.size(); i++)
{
switch(classNames.get(i).toLowerCase())
{
case "firstclass": // 2 points for first
points += 2 * classTickets.get(i);
break;
case "coach": // 1 point for coach
points += classTickets.get(i);
break;
default:
// budget gets nothing
}
}
}
return points;
The regex seems like the most convenient way, but this was more intuitive to me for some reason. Either way, I hope the variety will help out.
simply use the built-in String.split() - #bui
I was finally able to wrap my head around regular expressions, but \s+ was not being recognized for some reason. It kept giving me this error message:
Invalid escape sequence (valid ones are \b \t \n \f \r " ' \ )Java(1610612990)
So when I went through with those characters instead, I was able to write this:
int points = 0, multiplier = 0, tracker = 0;
while(fileScanner.hasNext())
{
String read = fileScanner.next().split(
"[\b \t \n \f \r \" \' \\ ]")[0];
if(tracker % 2 == 0)
{
if(read.toLowerCase().equals("firstclass"))
multiplier = 2;
else if(read.toLowerCase().equals("coach"))
multiplier = 1;
else
multiplier = 0;
}else
{
points += multiplier * Integer.parseInt(read);
}
tracker++;
}
This code goes one entry at a time instead of reading a whole array void of whitespace as a work-around for that error message I was getting. If you could show me what the code would look like with String[] tokens = fileAsString.split("\s+"); instead I would really appreciate it :)
you need to add another "\" before "\s" to escape the slash before "s" itself – #bui
i get termination due to timeout error when i compile. Please help me
Given two strings, determine if they share a common substring. A substring may be as small as one character.
For example, the words "a", "and", "art" share the common substring "a" . The words "be" and "cat" do not share a substring.
Input Format
The first line contains a single integer , the number of test cases.
The following pairs of lines are as follows:
The first line contains string s1 .
The second line contains string s2 .
Output Format
For each pair of strings, return YES or NO.
my code in java
public static void main(String args[])
{
String s1,s2;
int n;
Scanner s= new Scanner(System.in);
n=s.nextInt();
while(n>0)
{
int flag = 0;
s1=s.next();
s2=s.next();
for(int i=0;i<s1.length();i++)
{
for(int j=i;j<s2.length();j++)
{
if(s1.charAt(i)==s2.charAt(j))
{
flag=1;
}
}
}
if(flag==1)
{
System.out.println("YES");
}
else
{
System.out.println("NO");
}
n--;
}
}
}
any tips?
Below is my approach to get through the same HackerRank challenge described above
static String twoStrings(String s1, String s2) {
String result="NO";
Set<Character> set1 = new HashSet<Character>();
for (char s : s1.toCharArray()){
set1.add(s);
}
for(int i=0;i<s2.length();i++){
if(set1.contains(s2.charAt(i))){
result = "YES";
break;
}
}
return result;
}
It passed all the Test cases without a time out issue.
The reason for the timeout is probably: to compare two strings that each are 1.000.000 characters long, your code needs 1.000.000 * 1.000.000 comparisons, always.
There is a faster algorithm that only needs 2 * 1.000.000 comparisons. You should use the faster algorithm instead. Its basic idea is:
for each character in s1: add the character to a set (this is the first million)
for each character in s2: test whether the set from step 1 contains the character, and if so, return "yes" immediately (this is the second million)
Java already provides a BitSet data type that does all you need. It is used like this:
BitSet seenInS1 = new BitSet();
seenInS1.set('x');
seenInS1.get('x');
Since you're worried about execution time, if they give you an expected range of characters (for example 'a' to 'z'), you can solve it very efficiently like this:
import java.util.Arrays;
import java.util.Scanner;
public class Whatever {
final static char HIGHEST_CHAR = 'z'; // Use Character.MAX_VALUE if unsure.
public static void main(final String[] args) {
final Scanner scanner = new Scanner(System.in);
final boolean[] characterSeen = new boolean[HIGHEST_CHAR + 1];
mainloop:
for (int word = Integer.parseInt(scanner.nextLine()); word > 0; word--) {
Arrays.fill(characterSeen, false);
final String word1 = scanner.nextLine();
for (int i = 0; i < word1.length(); i++) {
characterSeen[word1.charAt(i)] = true;
}
final String word2 = scanner.nextLine();
for (int i = 0; i < word2.length(); i++) {
if (characterSeen[word2.charAt(i)]) {
System.out.println("YES");
continue mainloop;
}
}
System.out.println("NO");
}
}
}
The code was tested to work with a few inputs.
This uses a fast array rather than slower sets, and it only creates one non-String object (other than the Scanner) for the entire run of the program. It also runs in O(n) time rather than O(n²) time.
The only thing faster than an array might be the BitSet Roland Illig mentioned.
If you wanted to go completely overboard, you could also potentially speed it up by:
skipping the creation of a Scanner and all those String objects by using System.in.read(buffer) directly with a reusable byte[] buffer
skipping the standard process of having to spend time checking for and properly handling negative numbers and invalid inputs on the first line by making your own very fast int parser that just assumes it's getting the digits of a valid nonnegative int followed by a newline
There are different approaches to solve this problem but solving this problem in linear time is a bit tricky.
Still, this problem can be solved in linear time. Just apply KMP algorithm in a trickier way.
Let's say you have 2 strings. Find the length of both strings first. Say length of string 1 is bigger than string 2. Make string 1 as your text and string 2 as your pattern. If the length of the string is n and length of the pattern is m then time complexity of the above problem would be O(m+n) which is way faster than O(n^2).
In this problem, you need to modify the KMP algorithm to get the desired result.
Just need to modify the KMP
public static void KMPsearch(char[] text,char[] pattern)
{
int[] cache = buildPrefix(pattern);
int i=0,j=0;
while(i<text.length && j<pattern.length)
{
if(text[i]==pattern[j])
{System.out.println("Yes");
return;}
else{
if(j>0)
j = cache[j-1];
else
i++;
}
}
System.out.println("No");
return;
}
Understanding Knuth-Morris-Pratt Algorithm
There are two concepts involved in solving this question.
-Understanding that a single character is a valid substring.
-Deducing that we only need to know that the two strings have a common substring — we don’t need to know what that substring is.
Thus, the key to solving this question is determining whether or not the two strings share a common character.
To do this, we create two sets, a and b, where each set contains the unique characters that appear in the string it’s named after.
Because sets 26 don’t store duplicate values, we know that the size of our sets will never exceed the letters of the English alphabet.
In addition, the small size of these sets makes finding the intersection very quick.
If the intersection of the two sets is empty, we print NO on a new line; if the intersection of the two sets is not empty, then we know that strings and share one or more common characters and we print YES on a new line.
In code, it may look something like this
import java.util.*;
public class Solution {
static Set<Character> a;
static Set<Character> b;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
for(int i = 0; i < n; i++) {
a = new HashSet<Character>();
b = new HashSet<Character>();
for(char c : scan.next().toCharArray()) {
a.add(c);
}
for(char c : scan.next().toCharArray()) {
b.add(c);
}
// store the set intersection in set 'a'
a.retainAll(b);
System.out.println( (a.isEmpty()) ? "NO" : "YES" );
}
scan.close();
}
}
public String twoStrings(String sOne, String sTwo) {
if (sOne.equals(sTwo)) {
return "YES";
}
Set<Character> charSetOne = new HashSet<Character>();
for (Character c : sOne.toCharArray())
charSetOne.add(c);
Set<Character> charSetTwo = new HashSet<Character>();
for (Character c : sTwo.toCharArray())
charSetTwo.add(c);
charSetOne.retainAll(charSetTwo);
if (charSetOne.size() > 0) {
return "YES";
}
return "NO";
}
This must work. Tested with some large inputs.
Python3
def twoStrings(s1, s2):
flag = False
for x in s1:
if x in s2:
flag = True
if flag == True:
return "YES"
else:
return "NO"
if __name__ == '__main__':
q = 2
text = [("hello","world"), ("hi","world")]
for q_itr in range(q):
s1 = text[q_itr][0]
s2 = text[q_itr][1]
result = twoStrings(s1, s2)
print(result)
static String twoStrings(String s1, String s2) {
for (Character ch : s1.toCharArray()) {
if (s2.indexOf(ch) > -1)
return "YES";
}
return "NO";
}
I have to resolve the next exercise:
Create a keyboard scanner in which the tokens are unsigned integers, and write the code to determine the sum of the integers.
Note: -5 will be scanned as the unsigned integer 5, and the minus sign will be skipped over as a delimiter
this is my solution (not working) :
import java.util.*;
public class testing{
public static void main( String[] argv ){
testing p = new testing();
}
public testing(){
Scanner myScanner = new Scanner(System.in);
String regex = "\\s+|-";
myScanner.useDelimiter(regex);
int sum = 0;
while(myScanner.hasNextInt()){
int partial = myScanner.nextInt();
sum += partial;
}
System.out.println(sum);
}
}
The problem with my solution is that it is working only for positive integers or negative integer (only first input) added to positive integers.
for example:
-2
3
4
f (used to stop the program)
will retrieve 9.
but
3
-2
will stop the program and retrieve 3
I am trying to understand the reason of this behavior but not luck so far.
You are using an OR in the regex, which means it just consumes the line break and then stops at the '-', because it's not consumed as a delimiter any more.
The input your scanner sees is:
-2\n3\n4\nf
'f' is the first thing after an integer that does not match your pattern of whitespaces OR one minus.
The second pattern though requires both to be matched vs your delimiter:
3\n-2
So the line break (white space) is matched versus your delimiter pattern and the minus remains unmatched. Since it's not an Integer .hasNextInt() returns false.
A repeatable group of whitespaces and minus works as you intend:
final String regex = "[\\s-]+";
This might end up accepting more than your exercise requires, like multiple minus signs in front of a number. If that is not acceptable, you can of course limit the minus to one occurance after an indeterminate amount of whitespaces:
final String regex = "[\\s]*-?";
The '?' means "once or not at all" and limits the occurances of minuses.
Edit:
As #maraca pointed out in a comment, my previously proposed solution only works for single digit numbers, as the pattern accepts the empty string as well. The solution that works for numbers >9 as well is:
final String regex = "\\s+|\\s*-";
What it does is consume either one or more whitespaces OR zero or more whitespaces followed by a minus sign.
Turns out even small things like these can be rather difficult to do right. -.-
You can solve by catching InputMismatchException like this:
public Testing(){
Scanner myScanner = new Scanner(System.in);
String regex = "\\s+|-";
myScanner.useDelimiter(regex);
int sum = 0;
while(myScanner.hasNext()){
int partial = 0;
try{
partial = myScanner.nextInt();
} catch(InputMismatchException e){
continue;
}
sum += partial;
}
System.out.println(sum);
}
The issue is you are trying to parse a int but you receive a "-".
This Java program does a simple computation and it is suppose to output the numerical value of 123+1
(The output should be 124.) (Ignore the last "+" string.)
I got an error inside the if statement:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
I did a printout for arrayz[i-1] and arrayz[i+1] and it seems to printout 123 and 1 receptively, which is correct. So, I'm not sure what's wrong.
String math = "123+1+";
String arrayz[]={"123","+","1","+"};
double total =0.0;
int i=0;
while(i<=(math.length()-1)) //don't bother with the last char
{ i++;
if(arrayz[i].equals("+"))
{
total = Double.parseDouble((String)arrayz[i-1]) + Double.parseDouble((String)arrayz[i+1]);
}
}
System.out.println(total);
while(i<=(math.length()-1))
math length is 6 and and in side loop your array length is 4
You might want to write
while(i<=(arrayz.length-1))
Since you are using the index i with the array arrayz, you must use arrayz.length instead of math.length()
Edit
This should work:
public static void main(String[] args)
{
String math = "123+1+";
String arrayz[] = { "123", "+", "1", "+" };
double total = 0.0;
int i = 0;
// arrayz.length - 2 -> because you are accessing "arrayz[i + 1]",
// arrayz.length - 1 would be OK if the maximum index you were using were "arrayz[i] "
while (i <= (arrayz.length - 2)) //don't bother with the last char
{
if (arrayz[i].equals("+")) {
total = Double.parseDouble((String) arrayz[i - 1]) + Double.parseDouble((String) arrayz[i + 1]);
}
i++; // Increment at the end of the loop
}
System.out.println(total);
}
You are looping over the string math, at the same time accessing elements of arrayz inside your loop, and thinking that they have the same elements and the same length.
What I suggest you, is to use instead of math String (you can omit it in this case but I assume you can't in general for some criteria), you can use an array of type String, so that 123 in your example would be the first element arrayz[0].
I'm trying to find out if the input of the user is decimal or fraction or mixed fraction and when there is a decimal with fraction I would like to replace the decimal to a whole number so that it would be a proper mixed fraction
for example:
input: 2.23 1/2
expected output: 2 1/2
public class DecimalOrFraction {
public static void main(String args[]){
String partOfString;
String[] s = { "0000.2","2","2.222 1/2","1 2/2", "0"};
for (int x = 0 ;x<s.length;x++) {
if(s[x].matches("[1-9]{1}\\d{0,3}([.]\\d{1,3}\\s{0,1})?")){
System.out.println(x+") "+Float.valueOf(s[x])+" ---- Decimal");
}
else if(s[x].matches("[1-9]{1,5}([.]\\d{1,3})?\\s[1-9]{1}\\d{0,2}([/]\\d{0,3})?")){
partOfString = s[x].substring( s[x].lastIndexOf("."), s[x].lastIndexOf(" ")); //HAVING AN ERROR
s[x] = s[x].replace(partOfString," ");
System.out.println(x+") "+s[x]+" ---- Fraction");
}
else if(s[x].matches("[1-9]\\d{0,4}[/]\\d{0,3}")){
System.out.println(x+") "+s[x]+" ---- also Fraction");
}
else{
System.out.println(x+") "+s[x]+" ---- ERROR/Zero");
}
}
}
}
Is there another way to make this work without any error??
The error occurs because there is no dot in "1 2/2" to take the index of.
Since the matching uses RegEx, why not use RegEx for the replacement as well?
Here's a pass at refactoring the whole thing.
private static final Pattern DECIMAL = Pattern.compile("\\d*\\.?\\d+");
private static final Pattern FRACTION = Pattern.compile("\\.\\d+(\\s+\\d+/\\d+)");
public static void main(String args[]) {
String[] samples = {"0000.2", "2", "2.222 1/2", "1 2/2", "0"};
for (String sample : samples) {
if (DECIMAL.matcher(sample).matches()) {
float decimal = Float.parseFloat(sample);
System.out.println(decimal + (decimal == 0 ? "\tERROR/Zero" : "\tDecimal"));
}
else {
String fraction = FRACTION.matcher(sample).replaceFirst("$1");
System.out.println(fraction + "\tFraction");
}
}
}
if you can ONLY have at most two separate parts then you can use String.split() and split on a " " white space. Then if you have two parts it's easier to work with. If you have one, again, simple conditionals. I don't think there's a need for this much messy regex.
Alterantively, if you have more than one whitespace, simply call each resulting split string against a regex for either of your two cases and handle that way.