I don't know how to make my code less time consuming. My task was to make brute force password break. I knew how long password is and which characters it contains. So far i have this method.
public boolean moznosti(char [] arr, String pr, int a, int b) {
if (b == 0) {
char [] heslo = pr.toCharArray();
if(tryOpen(heslo)) {
return false;
}
return true;
}
for (int i = 0; i < a; i++) {
String tmp = pr+arr[i];
if (moznosti(arr, tmp, a, b-1) == false) {
return false;
}
moznosti(arr, tmp, a, b-1);
}
return true;
}
}
where heslo is password. any ideas?
Have a look at your code structure.
You have a for loop which recursively calls your moznosti method, and each time it's called it doing the same thing.
I don't know what your variables mean but assuming a and b are 4. Your first cycle will call your moznosti method 4 times with the same b parameter.
Not that this is causing the time issue but where you have:
if (moznosti(arr, tmp, a, b-1) == false)
Because the moznosti method returns a Boolean value, you don't need to check if it's equal to false or true, the if statement brackets only pass when the condition is true. So in your case this might be more applicable:
if (!moznosti(arr, tmp, a, b-1))
I think the part which is taking most of the time is where you are checking your base case
if (moznosti(arr, tmp, a, b-1) == false)
Okay i did it!
public class BruteForceAttacker extends Thief {
private boolean konec;
#Override
public void breakPassword(int sizeOfPassword) {
moznosti(getCharacters(), "", getCharacters().length, sizeOfPassword);
}
public void moznosti(char [] arr, String pr, int a, int b) {
if (konec != true) {
if (b == 0) {
char [] heslo = pr.toCharArray();
if (tryOpen(heslo)) {
konec = true;
}
return;
}
for (int i = 0; i < a; i++) {
String tmp = pr+arr[i];
moznosti(arr, tmp, a, b-1);
}
}
}
}
Related
I want to write a function that return true if if and only if
String a is always followed by String b, and String b is always followed by string c, this is what I wrote but it doesn't work :
public static boolean follows2(String s, String a, String b, String c) {
boolean res = true;
for (int i = 0; i < s.length(); i++) {
if (charAtPos(s, i).equals(a)) {
if (!(charAtPos(s, i + 1).equals(b))) {
res = false;
if (!(charAtPos(s, i + 2).equals(c))) {
res = false;
}
}
}
}
return res;
}
public static void main(String[] args) {
System.out.println(follows2(" koali oliali ", "a", "l", "i"));
// RETURN TRUE OK since for each " a" is followed by "l" then "i"
System.out.println(follows2("ipoipa", "i", "p", "a"));
//RETURN TRUE BUT IT'S NOT !
// The first " i" is followed by " p" then "o" which is not good
}
Here is the function that I wrote for:
String a is always followed by String b ( It works )
public static boolean follows(String s, String a, String b) {
boolean res = true;
for (int i = 0; i < s.length(); i++) {
if (charAtPos(s, i).equals(a)) {
if (!(charAtPos(s, i + 1).equals(b))) {
res = false;
}
}
}
return res;
}
public static String charAtPos(String s, int i) {
return String.valueOf(s.charAt(i));
}
public static void main(String[] args) {
System.out.println(follows("Arnold Barney", "r", "n"));
// RETURN TRUE because each "r" are followed by the letter "n"
System.out.println(follows("Arnold Barney", "n", "o"));
// RETURN FALSE , because not every "n" is followed by "o"
}
What can be done in my first program to make it work ?
Thank you
With recursion:
public static boolean follows(String s, String a, String b, String c) {
int ai = s.indexOf(a);
if (ai == -1) {
return true; // No more 'a' string, we're all good
}
int bi = s.indexOf(a + b);
int ci = s.indexOf(a + b + c);
if (bi != ai || ci != ai) {
return false; // Strings 'b' and 'bc' don't follow 'a', so the check failed
}
return follows(s.substring(ai + a.length()), a, b, c);
}
In reality, bi could be removed.
The problem you have is that you are not actually entering the nested if statements due to a minor flaw in your logic.
I would change it to this which checks whether i + 1 is equal to String b || i + 2 is equal to String c
public static boolean follows2(String s, String a, String b, String c) {
boolean res = true;
for (int i = 0; i < s.length(); i++) {
if (charAtPos(s, i).equals(a)) {
if (!(charAtPos(s, i + 1).equals(b)) || !(charAtPos(s, i + 2).equals(c))) {
res = false;
}
}
}
return res;
}
Because the code doesn't do what you think it does.
if you'll add some prints to the code, you'll see you never set "res" to false.
Let's debug the case you're testing:
When meet the the first letter - "i" - it entered the first if.
the next letter is "p" so you're not entered the 2nd if, so you'll continue to the next letter in the "for".
Here's my attempt (haven't tested it)
boolean hasOnlyCompleteSequences(String source, char.. chars) {
for (int s = 0; s < source.length(); s++) {
int c = 0;
if (source.charAt(s) == chars[c]) {
if (!isCompleteSequence(source, s + 1, chars, c + 1)) {
return false;
}
}
}
return true;
}
boolean isCompleteSequence(String source, int s, char[] chars, int c) {
while (s < source.length() && c < chars.length) {
// note: the indices get increased AFTER comparison
if (source.charAt(s++) != chars[c++]) {
return false;
}
}
// cover the case that the source String ends with an incomplete sequence
if (s == source.length() && c < chars.length) {
return false;
}
return true;
}
This is a much cleaner answer (tested & working great):
public static boolean follows(String s, String...strings) {
int number = 0;
for(int i = 0; i<s.length(); i++){
if(strings[number].length()+i<s.length() && s.substring(i, strings[number].length()+i).equals(strings[number]) && number+1 != strings.length) number++;
else if(number!=0 && !s.substring(i, strings[number].length()+i).equals(strings[number])) return false;
else number = 0;
}
return true;
}
It fixes many problems with your code:
Working with strings but using "charAt"
Copying the function just to add a parameter
Consider 4 input fields A, B, C and D on a web surface. The user can fill any of these arbitrary. There are 16 combinations of how to fill these fields. The ones allowed are:
A B C D
-------
1 0 0 0
1 1 0 0
1 1 1 0
1 1 1 1
where 1 means not null and 0 means null.
I am using the MVC pattern with jsf. I don't want the logic to be in the view, but rather in the controller. What is the best way to check this in Java?
I implemented two solutions so far:
Solution 1:
#Override
public boolean isInputInvalid(Integer a, Integer b, Integer c, Integer d) {
if (isNotSet(a) && isNotSet(b) && isNotSet(c) && isNotSet(d) {
return true;
}
return (firstParameterDoesNotExistAndSecondDoesExist(a, b)) || (firstParameterDoesNotExistAndSecondDoesExist(b, c)) || (firstParameterDoesNotExistAndSecondDoesExist(c, d));
}
private boolean firstParameterDoesNotExistAndSecondDoesExist(Integer firstParameter, Integer secondParameter) {
return isNotSet(firstParameter) && !isNotSet(secondParameter);
}
private boolean isNotSet(Integer parameter) {
return parameter == null;
}
Solution 2:
public boolean isInputValid(Integer a, Integer b, Integer c, Integer d) {
if (exists(a) && !exists(b) && !exists(c) && !exists(d) || //
exists(a) && exists(b) && !exists(c) && !exists(d) || //
exists(a) && exists(b) && exists(c) && !exists(d) || //
exists(a) && exists(b) && exists(c) && exists(d)) {
return true;
}
return false;
}
private boolean exists(Integer level) {
return level != null;
}
Note:
The first methods checks if input is invalid, while the second checks if input is valid (note the names of the methods).
I wrote 16 unit test cases, which all run green with both versions.
Do you have any hints/tips/tricks on how to get the code even more readable?
Valid combinations are: 1000, 1100, 1110 and 1111
If you only care about readability:
public static List<String> validOptions = Arrays.asList("1000","1100","1110","1111");
public boolean isValid(Integer a, Integer b, Integer c, Integer d)
{
StringBuilder sb = new StringBuilder();
sb.append(a==null ? 0 : 1);
sb.append(b==null ? 0 : 1),
sb.append(c==null ? 0 : 1);
sb.append(d==null ? 0 : 1);
return validOptions.contains(sb.toString());
}
Note that this is not the fastest or cleanest solution (wastes some CPU and memory)
To solve this for an arbitrary number of parameters, pass in true or false (if not null / null) in this:
static boolean isValid(boolean... params) {
boolean set = true;
for (boolean param : params) {
if (!set && param) return false;
set = param;
}
return params[0];
}
Or much cooler (and IMHO readable), but less performant, use regex on the array's toString():
static boolean isValid(boolean... params) {
return Arrays.toString(params).matches("\\[true(, true)*(, false)*]");
}
which ever implementation you use, you would call it like:
if (isValid(a != null, b != null, c != null, d != null))
Not fancy but fast and simple:
static boolean isValid(boolean a, boolean b, boolean c, boolean d) {
return a && (b || !c) && (c || !d);
}
Call:
isValid(a != null, b != null, c != null, d != null);
I don't really understand why you need this. Rather than a method that tests if input is valid, it would be much better to only allow valid input in the first place.
// This method is private, so you can't call it with arbitrary arguments.
private void privateMethod(Integer a, Integer b, Integer c, Integer d) {
// do something();
}
public void method(int a) {
privateMethod(a, null, null, null);
}
public void method(int a, int b) {
privateMethod(a, b, null, null);
}
public void method(int a, int b, int c) {
privateMethod(a, b, c, null);
}
public void method(int a, int b, int c, int d) {
privateMethod(a, b, c, d);
}
The way to modify this to any number of arguments (not just 4) is to have a method with signature
public void method(int... a)
Then, if the length of the array passed is less than the required length, you can just use null for the remaining inputs.
If this does not address your problem, I think you should consider editing your question to give an example of your use case, because I suspect there is a better way to achieve what you require.
You could create a pattern with a two dimensional array.
The advantage is that it is easy to adjust, and add additional information to it.
Here is a tiny example with your conditions.
In the end all you have to read is the pattern that is initialized in the static block, which is quite easy to read.
// Every boolean array in a dimension represents a valid pattern
private static boolean[][] pattern;
static {
pattern = new boolean[4][4];
pattern[0] = new boolean[]{true, false, false, false};
pattern[1] = new boolean[]{true, true, false, false};
pattern[2] = new boolean[]{true, true, true, false};
pattern[3] = new boolean[]{true, true, true, true};
}
public static void main(String[] args) {
// Testing an invalid combination
System.out.println(test(new Integer[]{1,null,3,null}));
// Testing a valid combination
System.out.println(test(new Integer[]{1,2,3,null}));
}
private static boolean test(Integer[] input) {
// cast the input to a boolean array that can be compared to the pattern.
boolean[] arr = createArr(input);
for(int i = 0;i<pattern.length;++i) {
if(Arrays.equals(pattern[i], arr)) { // Check if the pattern exists in the list of valid pattern. If it exists, then this is a valid combination
return true;
}
}
// the loop never found a valid combination, hence it returns false.
return false;
}
// This is just a helping method to create a boolean array out of an int array. It casts null to true and !null to false.
private static boolean[] createArr(Integer[] input) {
boolean[] output = new boolean[input.length];
for(int i = 0;i<input.length; ++i) {
output[i] = input[i] != null;
}
return output;
}
Yet another solution. Involves more code but for me it's easier to understand:
boolean isInputInvalid(Object ... args) {
int notNullDataIndex = -1;
for (int i = args.length - 1; i >= 0; i--) {
if (args[i] != null) {
notNullDataIndex = i;
break;
}
}
if (notNullDataIndex < 0) return false;
for (int i = notNullDataIndex; i >= 0; i--) {
if (args[i] == null) return false;
}
return true;
}
I'm currently trying to make a password validator work with boolean method, since the teacher asked us to do so. This is driving me nuts. To be correct, the password need to have one uppercase, one lower case letter, at least 10 characters and one number. I'm aware that right now, my method returns entirely with the value false, but I'm wondering how I can break the code once I have one uppercase, or one lowercase.
Thanks a lot for your help!
public class AtLeast1UppercaseLowercaseNumber {
public static void main(String[] args){
String password = "H";
System.out.println(password);
if(isSecurePassword(password)){
System.out.println("Yay it works");}
else {
System.out.println("you suck");}
}
public static isSecurePassword(String password) {
int uppercase = 0, lowercase = 0, number = 0;
for(int i=0; i<password.length(); i++) {
for(char c ='A'; c <='Z'; c++) {
if(password.charAt(i) == c) {
uppercase++;
if( uppercase >= 1) {
for(char t = 'a'; t <='z'; t++) {
if(password.charAt(i) == t) {
lowercase++;
if(lowercase >= 1) {
}
}
}
for(int j = '0'; j <='9'; j++) {
if(password.charAt(i) == j) {
number++;
if( number >= 1) {
}
}
}
}
return false;
}
}
I suggest you start by creating multiple private and static test methods, and then delegate to them in your public isSecurePassword(String) method. Implement test methods like boolean oneUpper(String), boolean oneLower(String), boolean oneDigit(String) and boolean tenCharacters(String) as an example
private static boolean tenCharacters(String str) {
return str.length() > 9;
}
and a second example
private static boolean oneUpper(String str) {
for (char ch : str.toCharArray()) {
if (Character.isUpperCase(ch)) {
return true;
}
}
return false;
}
Then your isSecurePassword(String) is just
public static boolean isSecurePassword(String str) {
return tenCharacters(str) && oneUpper(str) && oneLower(str)
&& oneDigit(str);
}
Since there is only one return in this method, which explicitly returns false, this method will always return false.
Method 1:
Define a boolean, which will be returned in the last statement of the method. This boolean is true by default and will be set false if one condition is wrong.
Method 2:
The last statement is an implicit return true statement, and whenever a condition is not fullfilled return false. This will prevent the method from executing more tests.
Method 3:
Make the method look like this
if (containsUpperCase(string) && contains...)
return true;
return false;
I wrote this code with the intention of chain being incremented each time recurse() is called. It does this, however (from what I saw with the debugger) each time recurse() reaches a return;, it decrements the value of b. This is project euler #14 if you want background on what I'm trying to do.
http://projecteuler.net/problem=14
private static void euler14()
{
int currentstart=1000000;
int longest = 0;
int current=0;
Integer chain=0;
for(int i = currentstart; i>0; i--)
{
recurse(i,chain);
if(chain > current)
{
current=chain;
longest=i;
}
chain = 0;
}
System.out.print("Euler 14: " + longest + "\n");
}
private static void recurse(int a, Integer b)
{
b++;
if(a==1)
{
return;
}
else if(a%2==0)
{
recurse((a/2), b);
}
else if(a%2==1)
{
recurse(((a*3)+1), b);
}
return;
}
Although the reference to Integer is passed (by value) to recurse, the object itself is immutable. When you do b++, the incremented value is assigned to b which is local to recurse. As soon as you return, the value goes back to the unchanged copy of b in the caller.
You can make b a static int variable, and drop it from the parameter list of recurse to fix the problem:
private static int b = 0;
private static void recurse(int a) {
b++;
if(a==1) {
return;
}
if(a%2==0) {
recurse((a/2), b);
} else if(a%2==1) {
recurse(((a*3)+1), b);
}
}
In order to see updates to b in your main method your need to return them back, when you reach end of recursion:
private static int recurse(int a, int b) {
b++;
if(a==1) return b;
else if(a%2==0) return recurse((a/2), b);
else if(a%2==1) return recurse(((a*3)+1), b);
return b;
}
And in your main method you update your chain with new value:
chain = recurse(i,chain);
Since your method currently doesn't have a return value, you can use a return value for the number of steps. Simply add 1 to each recursive step:
private static int recurse(int a) {
if(a==1) {
return 1;
}
if(a%2==0) {
return 1 + recurse(a/2);
} else if(a%2==1) {
return 1 + recurse((a*3)+1);
}
}
I want to use a recursive method but am having trouble making it work correctly.
In this program for example, why when I display my b, the value is 0 and not 10?
public static void main(String[] args) {
int a = 0;
int b = recursivMethod(a);
System.out.println(b);
}
static int recursivMethod(int a)
{
if(a != 10)
recursivMethod(a+1);
return a;
}
The issue is, while you are calling the method recursively, you're not returning that value. That is, you call recursivMethod correctly, but then immediately return the initial value of a. Try this instead:
public static void main(String[] args) {
int a = 0;
int b = recursivMethod(a);
System.out.println(b);
}
static int recursivMethod(int a)
{
if(a != 10)
return recursivMethod(a+1); //here, you return the result of your recursive call
return a; //instead of just immediately returning a, which should only be done only after a == 10
}
Two points:
When your method calls itself recursively, it's ignoring the returned value:
if(a != 10)
recursivMethod(a+1); // <--- did you mean to do something with the result?
Since recursivMethod() doesn't change a, and returns a at the end, then calling recursivMethod(0) will return 0. This is exactly what happens when you run your code.
This is because you are ignoring the return value of your recursive invocation:
static int recursivMethod(int a) {
if(a != 10)
return recursivMethod(a+1);
return a;
}
try
return recursiveMethod(a+1);
instead
You did never assign a new value to the method local variable a.
Try:
public static void main(String[] args) {
int a = 0;
int b = recursivMethod(a);
System.out.println(b);
}
static int recursivMethod(int a)
{
if(a != 10)
a = recursivMethod(a+1);
return a;
}
You are discarding the result of your recursive call.
static int recursivMethod(int a)
{
if(a != 10)
return recursivMethod(a+1); // Note the return
return a;
}
static int recursivMethod(int a)
{
if(a != 10)
return recursivMethod(a+1);
}
missing return:
return recursivMethod(a+1);