Make an algorithm start again? - java

So I'm pretty new to coding with Java (started yesterday). What I am trying to do is to make an Input of an Integer, if the int c it is higher than 1 or lower than 0 (if it is not 1 or 0), I want it to start again. If int c equals either 1 or 0, I want the alogrithm to continue. I tried to insert some kind of loops after if(c > 1 || c < 0) but it does not seem to work and only spams my console with the result. Is there any easy way to make the algorithm start over again? I'm already trying to fix this for more than 2 hours, but I'm just confusing me over and over again.
// more code up here but it is unimportant
int c = sc.nextInt();
if(c > 1 || c < 0) {
result = result + wrong;
System.out.println(result);
} else if (c == 1) {
result = result + notImplemented;
System.out.println(result);
} else if (c == 0) { //more code follows here but is unimportant

So you want to ask for input again, i assume.
A simple way could be:
int c = sc.nextInt();
while (c > 1 || c < 0) {
c = sc.nextInt();
}
//code continues

You can use while in this case and use break to exit:
while (scanner.hasNext()) {
int c = sc.nextInt();
if(c > 1 || c < 0) {
result = result + wrong;
System.out.println(result);
} else if (c == 1) {
result = result + notImplemented;
System.out.println(result);
break;
} else if (c == 0) {
...
break;
}
}
scanner.close();

You need to use a loop so you have
while(true){
int c = sc.nextInt();
if(c > 1 || c < 0) {
result = result + wrong;
System.out.println(result);
break;
} else if (c == 1) {
result = result + notImplemented;
System.out.println(result);
} else if (c == 0) { //more code follows here but is unimportant
...
}
Since you say you are new, I'll do a little explanation:
A While loop repeats what is in it's code block (i.e within the { }) for as long as a certain condition is true. In the case of my answer I did while(true) meaning it will keep repeating until something causes it to stop. In this case I used a break which forces the loop to end/stop.

Use hasNextInt() and a while loop to iterate over the data:
while (sc.hasNextInt()) {
int aInt = sc.nextInt();
//logic here
}
Documentation for hasNextInt() method:
https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#hasNextInt()

You can put your code in a function (which I hope is already the case) and then when you don't have the expected result and want to call it again, just do so by calling your function inside itself.
It's called recursion.
You can learn more here .
For example :
// more code up here but it is unimportant
public void myFunction(){
int c = sc.nextInt();
if(c > 1 || c < 0) {
result = result + wrong;
System.out.println(result);
} else if (c == 1) {
result = result + notImplemented;
System.out.println(result);
} else if (c == 0) { //more code follows here but is unimportant
}
//You want to call your function again
myFunction();
}

Related

Beautiful Word:Hackerrank

Question
We consider a word,w , to be beautiful if the following two conditions are satisfied:
No two consecutive characters are the same.
No two consecutive characters are in the following vowel set: a, e, i, o, u, y. Note that we consider y to be a vowel in this challenge.
For example:
The string batman is beautiful because it satisfies the given criteria; however, apple has two consecutive occurrences of the same letter (pp) and beauty has three consecutive vowels (eau), so those words are not beautiful.
My problem is when i am giving an input string "yes" it prints Yes but it should print No.
When i debugged the code using Intellij i see that
It is executing the code which is past return statement but the return statement is used to transfer control to the main function.
Solution
public class Coding {
int count = 0;
public static void main(String[] args) {
Coding obj = new Coding();
Scanner in = new Scanner(System.in);
String w = in .next();
boolean b = true;
char[] c = w.toCharArray();
for (int i = 0; i < c.length - 2; i++) {
b = obj.check(i, c); //recursive function
if (c[i] == c[i + 1]) {
b = false;
break;
}
if (!b) {
System.out.println("No");
break;
}
}
if (c[c.length - 2] == c[c.length - 1]) //check.for.the.remaining.chars
System.out.println("No");
else if (b) {
System.out.println("Yes");
}
}
public boolean check(int i, char[] c) {
if (c[i] == 'a' || c[i] == 'e' || c[i] == 'i' || c[i] == 'o' || c[i] == 'u' || c[i] == 'y') {
count++;
if (count == 2) {
return false; // code following this statement are executing
}
check(i + 1, c);
}
count = 0;
return true;
}
}
You are making a recursive call, but you are ignoring the results of that call!
That doesn't make sense. Either that call is valid, then you should return whatever comes back. Or the recursion doesn't "belong" there, then you should rework the complete method!
Beyond that: although recursive solution often look elegant, those contests focus on optimal performance. Meaning: rather use a single loop to iterate that string once.
Hint: The problem appears to be with method count. It always returns true to main method. If any recursive call returns false, is it being propagated back to main method?

Why is this becoming an infinite loop?

All i need this method to do is take a string lets say "aaxbb" and it will return true because there is an 'aa' and a 'bb',
If the string given is length = 0 or length = 1 it should fail.
The issue i'm having is that which i do not know.. i know that in my terminal after hasAdjacentPair's first test case Pass's, i get a blinking curser meaning that somehwere in this method i'm not kicking out of one of my loops for it to continue to check the string for any more adjacent pairs
the first test case passes while its an empty string "" = because it returned false
the second test case passes while its "a" = because it returned false
We are also not allowed to use Arrays :(
public boolean hasAdjacentPair(String str)
{
boolean result = false;
if (str.length() == 0)
{
result = false;
}
if (str.length() == 1)
{
result = false;
}
while (str.length() != 0)
{
for (int i = 0; i < str.length() - 1; ++i)
{
char adjChar = str.charAt(i);
char nextAdjChar = str.charAt(i + 1);
if (adjChar == nextAdjChar)
{
result = true;
}
}
}
return result;
}
Changed my while loop while (str.length() != 0) to while (str.length() != 0 && str.length() != 1) this enabled test 2 to work
EDIT 2 : After i completely took out the while (str.length() != 0) All 5 of my test cases pass :) so i guess it was just that?
while (str.length() != 0)
is always true and loop never end. Instead of if..if..while structure use either switch on length of string or if-else.
You could try something like this
if (str.length() == 0)
{
result = false;
}
else if (str.length() == 1)
{
result = false;
}
else
{
for (int i = 0; i < str.length() - 1; ++i)
{
char adjChar = str.charAt(i);
char nextAdjChar = str.charAt(i + 1);
if (adjChar == nextAdjChar)
{
result = true;
break;
}
}
If you checking for atleast one pair make use of break statement as you already know that you got the result
try this alternative:
boolean c = false;
//Your other code
while (str.length() != 0 && c == false)
{
for (int i = 0; i < str.length() - 1; ++i)
{
char adjChar = str.charAt(i);
char nextAdjChar = str.charAt(i + 1);
if (adjChar == nextAdjChar)
{
result = true;
}
}
c = true;
}
//Your other code
Is there a reason you have a while loop checking for the str length? The str is not modified in the loop.
What you most likely want is an if, else if, else structure.
You can most likely return true within the adjChar == nextAdjChar if statement and return false at the end of your function.

Java - what is the best way to check if a STRING contains only certain characters?

I have this problem: I have a String, but I need to make sure that it only contains letters A-Z and numbers 0-9. Here is my current code:
boolean valid = true;
for (char c : string.toCharArray()) {
int type = Character.getType(c);
if (type == 2 || type == 1 || type == 9) {
// the character is either a letter or a digit
} else {
valid = false;
break;
}
}
But what is the best and the most efficient way to implement it?
Since no one else has worried about "fastest" yet, here is my contribution:
boolean valid = true;
char[] a = s.toCharArray();
for (char c: a)
{
valid = ((c >= 'a') && (c <= 'z')) ||
((c >= 'A') && (c <= 'Z')) ||
((c >= '0') && (c <= '9'));
if (!valid)
{
break;
}
}
return valid;
Full test code below:
public static void main(String[] args)
{
String[] testStrings = {"abcdefghijklmnopqrstuvwxyz0123456789", "", "00000", "abcdefghijklmnopqrstuvwxyz0123456789&", "1", "q", "test123", "(#*$))&v", "ABC123", "hello", "supercalifragilisticexpialidocious"};
long startNanos = System.nanoTime();
for (String testString: testStrings)
{
isAlphaNumericOriginal(testString);
}
System.out.println("Time for isAlphaNumericOriginal: " + (System.nanoTime() - startNanos) + " ns");
startNanos = System.nanoTime();
for (String testString: testStrings)
{
isAlphaNumericFast(testString);
}
System.out.println("Time for isAlphaNumericFast: " + (System.nanoTime() - startNanos) + " ns");
startNanos = System.nanoTime();
for (String testString: testStrings)
{
isAlphaNumericRegEx(testString);
}
System.out.println("Time for isAlphaNumericRegEx: " + (System.nanoTime() - startNanos) + " ns");
startNanos = System.nanoTime();
for (String testString: testStrings)
{
isAlphaNumericIsLetterOrDigit(testString);
}
System.out.println("Time for isAlphaNumericIsLetterOrDigit: " + (System.nanoTime() - startNanos) + " ns");
}
private static boolean isAlphaNumericOriginal(String s)
{
boolean valid = true;
for (char c : s.toCharArray())
{
int type = Character.getType(c);
if (type == 2 || type == 1 || type == 9)
{
// the character is either a letter or a digit
}
else
{
valid = false;
break;
}
}
return valid;
}
private static boolean isAlphaNumericFast(String s)
{
boolean valid = true;
char[] a = s.toCharArray();
for (char c: a)
{
valid = ((c >= 'a') && (c <= 'z')) ||
((c >= 'A') && (c <= 'Z')) ||
((c >= '0') && (c <= '9'));
if (!valid)
{
break;
}
}
return valid;
}
private static boolean isAlphaNumericRegEx(String s)
{
return Pattern.matches("[\\dA-Za-z]+", s);
}
private static boolean isAlphaNumericIsLetterOrDigit(String s)
{
boolean valid = true;
for (char c : s.toCharArray()) {
if(!Character.isLetterOrDigit(c))
{
valid = false;
break;
}
}
return valid;
}
Produces this output for me:
Time for isAlphaNumericOriginal: 164960 ns
Time for isAlphaNumericFast: 18472 ns
Time for isAlphaNumericRegEx: 1978230 ns
Time for isAlphaNumericIsLetterOrDigit: 110315 ns
If you want to avoid regex, then the Character class can help:
boolean valid = true;
for (char c : string.toCharArray()) {
if(!Character.isLetterOrDigit(c))
{
valid = false;
break;
}
}
If you care about being upper case, then do below if statement instead:
if(!((Character.isLetter(c) && Character.isUpperCase(c)) || Character.isDigit(c)))
You could use Apache Commons Lang:
StringUtils.isAlphanumeric(String)
Additionally to all the other answers, here's a Guava approach:
boolean valid = CharMatcher.JAVA_LETTER_OR_DIGIT.matchesAllOf(string);
More on CharMatcher: https://code.google.com/p/guava-libraries/wiki/StringsExplained#CharMatcher
StringUtils in Apache Commons Lang 3 has a containsOnly method, https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html
The implementation should be fast enough.
Use a regular expression:
Pattern.matches("[\\dA-Z]+", string)
[\\dA-Z]+: At least one occurrence (+) of digits or uppercase letters.
If you want to include lowercase letter, replace [\\dA-Z]+ with [\\dA-Za-z]+.
The following way is not as fast as Regular expression to implement but is one of the most efficient solution (I think) because it use bitwise operations which are really fast.
My solution is more complex and harder to read and maintain but I think it is another simple way to do what you want.
A good way to test that a string only contains numbers or capital letters is with a simple 128 bits bitmask (2 Longs) representing the ASCII table.
So, For the standard ASCII table, there's a 1 on every character we want to keep (bit 48 to 57 and bit 65 to 90)
Thus, you can test that a char is a:
Number with this mask: 0x3FF000000000000L (if the character code < 65)
Uppercase letter with this mask: 0x3FFFFFFL (if the character code >=65)
So the following method should work:
public boolean validate(String aString) {
for (int i = 0; i < aString.length(); i++) {
char c = aString.charAt(i);
if ((c <= 64) & ((0x3FF000000000000L & (1L << c)) == 0)
| (c > 64) & ((0x3FFFFFFL & (1L << (c - 65))) == 0)) {
return false;
}
}
return true;
}
The best way in sense of maintainability and simplicity is the already posted regular expression. Once familiar the this technic you know what to expect and it is very easy to widen the criteria if needed. Downside of this is the performance.
The fastest way to go is the Array approach. Checking if a character's numerical value falls in the wanted range ASCII A-Z and 0-9 is nearly speed of light. But the maintainability is bad. Simplicity gone.
You could use and java 7 switch case with char approach but that's just as bad as the second.
In the end, since we are talking about java, I would strongly suggest to use regular expressions.

Java StringTokenizer considering parentheses

I am creating a program that tokenizes boolean logic expressions and returns the String array of tokens. The following is my code:
public static String[] tokenize(String s)
{
String delims = "+";
StringTokenizer st = new StringTokenizer(s, delims);
String[] tokens = new String[st.countTokens()];
int i=0;
while (st.hasMoreElements()) {
tokens[i++] = st.nextElement().toString();
}
return tokens;
}
For example, I have the following string as an input:
A+B+(C+D+(A+B))+(B+C)
Using the code I have, it will only generate the following tokens:
A
B
(C
D
(A
B))
(B
C)
Is it possible (using the same structure of code) to come up with these tokens? If not, how is it code-able?
A
B
(C+D+(A+B))
(B+C)
ArrayList<String> tokens = new ArrayList<String>();
String current = "";
int counter = 0;
for(int i = 0 ; i < input.length(); i++)
{
char c = input.charAt(i);
if(counter==0 && c=='+')
{
tokens.add(current);
current = "";
continue;
}
else if(c=='(')
{
counter++;
}
else if(c==')')
{
counter--;
}
current += c;
}
tokens.add(current);
This is the solution for my comment:
You could just loop through 1 character at a time, when you reach a +
while not in a parenthesis, save the characters read up to there, and
start a new set. The way to track if you're in a a set of parentheses
is with a counter. When you hit a open parenthesis, you increment a
counter by 1, when you hit a close parenthesis you decrement the
counter by 1. If the counter > 0 then you're in parentheses. Oh, and
if counter ever goes negative, the string is invalid, and if counter
is not 0 at the end, then the string is also invalid.
You can do the checks on counter and return false or something, to show that it is an invalid string. If you know the string is valid then this works as is. You can get an array from the ArrayList, with tokens.toArray()
If you can find a simple solution go with it otherwise try mine
String s = "A+B+(C+D+(A+B))+(B+C)";
List<String> l = new ArrayList<>();
StringBuilder sb = new StringBuilder();
int p = 0;
for (char c : s.toCharArray()) {
if (c == '(') {
p++;
sb.append(c);
} else if (c == ')') {
p--;
sb.append(c);
} else if (p == 0 && c == '+') {
l.add(sb.toString());
sb.setLength(0);
} else {
sb.append(c);
}
}
if (sb.length() > 0) {
l.add(sb.toString());
}
System.out.println(l);
output
[A, B, (C+D+(A+B))]

Checking string for large amount of different, incremental values

Currently I am checking a string for the following:
if(parseCommand.contains("vlan1")
|| parseCommand.contains("Fa0/1i") || parseCommand.contains("Fa0/1o")
|| parseCommand.contains("Fa1/0") || parseCommand.contains("Fa1/1")
|| parseCommand.contains("Fa1/2") || parseCommand.contains("Fa1/3")
|| parseCommand.contains("Fa1/4") || parseCommand.contains("Fa1/5")
|| parseCommand.contains("Fa1/6") || parseCommand.contains("Fa1/7")
|| parseCommand.contains("Fa1/8") || parseCommand.contains("Fa1/9")
|| parseCommand.contains("Fa1/11") || parseCommand.contains("Gi0"))
{
//do things here
}
However it may contain vlan1 up to vlan4094 and i have to check for these. What is the simplest way to do this, do I have to stick it all in a for loop incrementing to 4094 I guess?
for (int i = 1; i <= 4094; i++)
{
if(parseCommand.contains("vlan"[i]))
{
//do stuff here
}
}
if(other conditions from above)
{
//do same stuff again here
}
Or else I could stick all the conditions in the for loop and do everything inside there. This all seems messy, is there a non-messy way of doing it?
I think this regex should do it:
String parseCommand = "vlan4094";
if (parseCommand.matches(".*?vlan([1-3][0-9]{3}|" +
"[1-9][0-9]{0,2}|" +
"40(9[0-4]|[0-8][0-9])).*"))
System.out.println("matches");
[1-3][0-9]{3} - 1000-3999
[1-9][0-9]{0,2} - 1-999
9[0-4] - 90-94
[0-8][0-9] - 00-89
40(9[0-4]|[0-8][0-9]) - 4000-4094
Something like this is probably simpler:
String parseCommand = "vlan4094";
if (parseCommand.startsWith("vlan"))
{
int v = Integer.parseInt(parseCommand.substring(4));
if (v >= 1 && v <= 4094)
/* do stuff */
}
Suggested change:
Replace:
parseCommand.contains("Fa1/0") || parseCommand.contains("Fa1/1")
|| parseCommand.contains("Fa1/2") || parseCommand.contains("Fa1/3")
|| parseCommand.contains("Fa1/4") || parseCommand.contains("Fa1/5")
|| parseCommand.contains("Fa1/6") || parseCommand.contains("Fa1/7")
|| parseCommand.contains("Fa1/8") || parseCommand.contains("Fa1/9")
with
parseCommand.matches(".*?Fa1/[0-9].*")
You can combie them into one boolean
boolean b = false;
for(int i = 1 ; i < 4094 ; i ++){
b = b || parseCommand.contains("vlan" + i);
}
Then check your boolean value
If the only problem is with "vlanXXX" you can remove the "vlan" part of the string:
parseCommand = parseCommand.replaceFirst("vlan", "");
and then cast it to int
int value = Integer.parseInt(parseCommand);
and then comparing this result with that whaat you want
if((value >= 1) && (value <= 4094)){....}
This will only work for the given case and you have to handle the case where parseCommand cannot be cast to int. And it is much more understandable than using whatever regular expresion

Categories

Resources