Do global variables take longer fetch time? - java

The below code works fine for attached input.
public class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
return wordBreakMemo(s, new HashSet<>(wordDict), 0, new Boolean[s.length()]);
}
private boolean wordBreakMemo(String s, Set<String> wordDict, int start, Boolean[] memo) {
if (start == s.length()) {
return true;
}
if (memo[start] != null) {
return memo[start];
}
for (int end = start + 1; end <= s.length(); end++) {
if (wordDict.contains(s.substring(start, end)) && wordBreakMemo(s, wordDict, end, memo)) {
return memo[start] = true;
}
}
return memo[start] = false;
}
}
But when I change the local variables to global as below, my code take longer to execute, resulting in 'Time Limit Exceeded' on LeetCode.
class Solution {
HashSet<String> set;
String s;
Boolean dp[];
public boolean wordBreak(String s, List<String> wordDict) {
set=new HashSet();
set.addAll(wordDict);
this.s=s;
dp=new Boolean[s.length()];
return wordMemo(0);
}
public boolean wordMemo(int start)
{
if(start==s.length())
return true;
if(dp[start]!=null)
return dp[start];
for(int i=start+1; i<=s.length(); i++)
{
if(set.contains(s.substring(start, i)) && wordMemo(i))
{
dp[start]=true;
return true;
}
}
return false;
}
}
Input:
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab"
["a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"]
Can someone please explain what is happening around here?

Global variables don't have slower fetch times, no.
Whenever you get Time Limit Exceeded in a coding challenge you should assume you have a a flawed or buggy algorithm or data structure. It's never micro factors like fetch times or access modifiers or the language you've chosen. Even if you could speed up your program 10% with better memory access patterns or 100% by switching from Python to C, you're probably off by 10,000% or 10,000,000%, not 100%. That's how bad it can be when your program is accidentally O(n2) or O(2n) when the challenge designers expect O(n).
Here, the first program has:
return memo[start] = false;
While the second one has just:
return false;
It never memoizes false results. There are a lot more repeated computations, enough to kill the algorithm's Big-O time complexity.

Related

For if loop wont loop: any pointers to why that might be?

This is supposed to loop 24 times; it does not, and I'm pretty confused as to why. Please help me various Kenobis out there :
private boolean simpleMove(Board bd)
{
int b = rn.nextInt(3);
for (int i = 0; i < 24; i++) {
if (bd.isVacant(i) && rul.isLegalMove(tigerLocs[b], i)) {
bd.swap(tigerLocs[b],i);
bd.setTiger(i);
tigerLocs[b] = i;
System.out.println(i);
return true;
}
else {
System.out.println(i);
}
}
System.out.println("invalid");
return false;
As the comments point out your loop will execute a maximum of 24 times.
But the return statement inside the if statement may cause it to return 'early'.
It looks like it's some kind of board game thing.
The board appears to have 24 'squares' and it makes the first legal move and returns true.
If it fails to find a legal move, it returns false.
I can't confirm the logic overall but that rationale seems sound:
If there's a move available, take it and return true.
If no move is available, make no move and return false.
If you expected it to continue, even after finding a "valid" move, then simply store the fact that a valid move has been found. This can be done in a separate boolean variable:
private boolean simpleMove(Board bd) {
int b = rn.nextInt(3);
boolean valid = false; // until proven otherwise below
for (int i = 0; i < 24; i++) {
if (bd.isVacant(i) && rul.isLegalMove(tigerLocs[b], i)) {
bd.swap(tigerLocs[b],i);
bd.setTiger(i);
tigerLocs[b] = i;
valid = true;
}
System.out.println(i); // why output HERE when we have a return value?
}
if (!valid) {
System.out.println("invalid"); // why output HERE when we have a return value?
}
return valid;
}
It's unclear if multiple "valid" moves could be found, and whether that would be a problem when you "swap" or not. If there is only ever one possible move, then there would be no need to continue iterating with the for loop; simply return in the body like you were doing.

Which one is better, conditional for loop or for loop with a break (for short block of code)?

I am trying to find out which practices make your code more readable, specifically when your block of the code is short. Please look at these two versions of the for loop and let me know which one is more readable;
private boolean isValid(String guessInput)
{
boolean result = true;
for (int i = 0; i < guessInput.length(); i++)
{
if (!Character.isDigit(guessInput.charAt(i)))
{
result = false;
break;
}
}if (result)
{
int guessInputInt = Integer.parseInt(guessInput);
if (guessInputInt >= minGuess && guessInputInt < maxGuess)
guesses.add(guessInput);
else
result = false;
}else
System.out.println("Your input is not valid.");
return result;
}
Version 2
private boolean isValid(String guessInput)
{
boolean result = true;
for (int i = 0; i < guessInput.length() && result; i++)
{
if (!Character.isDigit(guessInput.charAt(i)))
{
result = false;
}
}if (result)
{
int guessInputInt = Integer.parseInt(guessInput);
if (guessInputInt >= minGuess && guessInputInt < maxGuess)
guesses.add(guessInput);
else
result = false;
}else
System.out.println("Your input is not valid.");
return result;
}
Approach to break the loop is better amongst the two. Also, you can move the Sysout statement inside the loop e.g.:
private boolean isValid(String guessInput){
for (int i = 0; i < guessInput.length() && result; i++){
if (!Character.isDigit(guessInput.charAt(i))){
return false;
}
}
return true;
Update
Here's another way to do it (using java 8 stream):
public static boolean isValid(String s){
return !s.chars()
.filter(c -> !Character.isDigit((char)c))
.findFirst()
.isPresent();
}
Agreed with Mark Jeronimus's point. You should call this method and print the messages in calling the method rather than having Sysout in the valildating method.
How about a third option:
private boolean isValid(String guessInput) {
boolean result = isNumeric(guessInput);
if (result)
// ...
}
private boolean isNumeric(String input) {
for (int i = 0; i < guessInput.length(); i++)
if (!Character.isDigit(guessInput.charAt(i)))
return false;
return !input.isEmpty();
}
Or even simpler:
private boolean isValid(String guessInput) {
try {
int guessInputInt = Integer.parseInt(guessInput);
if (guessInputInt >= minGuess && guessInputInt < maxGuess) {
guesses.add(guessInput);
return true;
}
} catch (NumberFormatException nfe) {
System.out.println("Your input is not valid.");
}
return false;
}
On a side note, the method name isValid() implies a read-only getter, which is very misleading when you're modifying state.
In your loops, if you can accurately specify your loop breaking condition in the for loop itself, that is always better.
I always think of break as a hack/patch/fix, never a solution.
Specifically to the question on the usage of break in the loop in your example, I don't think there is a difference in code readability, since it is so short.
However, in general I would prefer the break approach, because:
There is no reason to continue execution once the result is set to false. Depending on the length of "guessInput", and how the compiler may optimize your code, the code with break can be a lot more efficient.
Although the code inside for loop is short in your example, in practice it may likely to grow as the condition become more complex. By always breaking out of the loop where it should, it will become a lot easier follow the code logic when the code inside loop becomes longer or more complex.
Therefore, I would always prefer to use break where it should in a loop.
For this I like the use of
public boolean isValid(String s) {
if (isNum(s)) {
Integer num = Integer.parseInt(s);
return inRange(num, maxGuess, minGuess);
}
return false;
}
private boolean inRange(Integer i, Integer max, Integer min) {
return (i < max && i >= min);
}
private boolean isNum(String s) {
return s.chars().allMatch(Character::isDigit);
}
As others have mentioned System.out.println("Your input is not valid."); is best done by the consumer of the isValid function,
Breaking isValid into smaller operations helps with MURDER!
You can read about murder here
If your intention is to validate numbers, any numbers, then you'd use the API for that, and handle the exception if the number is invalid.
Caveat: In your code, if your string is over 2147483647, the exception is thrown anyway and unhandled, leading to bugs.
Here's a better version, although I'd still argue about splitting up responsibilities in a pure checking method and another method that adds it to the guesses and/or prints stuff.
private boolean isValid(String guessInput)
{
try {
int guessInputInt = Integer.parseInt(guessInput);
if (guessInputInt >= minGuess && guessInputInt < maxGuess) {
guesses.add(guessInput);
} catch (NumberFormatException ex) {
System.out.println("Your input is not valid.");
return false;
}
return true;
}

trying to break out of for loop but keeps going back into it and performing recursive call

I just discovered the project euler website, I have done challenges 1 and 2 and have just started number 3 in java... here is my code so far:
import java.util.ArrayList;
public class IntegerFactorise {
private static int value = 13195;
private static ArrayList<Integer> primeFactors = new ArrayList<Integer>();
private static int maxPrime = 0;
/**
* Check whether a give number is prime or not
* return boolean
*/
public static boolean isPrimeNumber(double num) {
for(int i = 2; i < num; i++) {
if(num % i == 0) {
return false;
}
}
return true;
}
/*Multiply all of the prime factors in the list of prime factors*/
public static int multiplyPrimeFactors() {
int ans = 1;
for(Integer i : primeFactors) {
ans *= i;
}
return ans;
}
/*Find the maximum prime number in the list of prime numbers*/
public static void findMaxPrime() {
int max = 0;
for(Integer i : primeFactors) {
if(i > max) {
max = i;
}
}
maxPrime = max;;
}
/**
* Find all of the prime factors for a number given the first
* prime factor
*/
public static boolean findPrimeFactors(int num) {
for(int i = 2; i <= num; i++) {
if(isPrimeNumber(i) && num % i == 0 && i == num) {
//could not possibly go further
primeFactors.add(num);
break;
}
else if(isPrimeNumber(i) && num % i == 0) {
primeFactors.add(i);
findPrimeFactors(num / i);
}
}
int sumOfPrimes = multiplyPrimeFactors();
if(sumOfPrimes == value) {
return true;
}
else {
return false;
}
}
/*start here*/
public static void main(String[] args) {
boolean found = false;
for(int i = 2; i < value; i++) {
if(isPrimeNumber(i) && value % i == 0) {
primeFactors.add(i);
found = findPrimeFactors(value / i);
if(found == true) {
findMaxPrime();
System.out.println(maxPrime);
break;
}
}
}
}
}
I am not using the large number they ask me to use yet, I am testing my code with some smaller numbers, with 13195 (their example) i get down to 29 in this bit of my code:
else if(isPrimeNumber(i) && num % i == 0) {
primeFactors.add(i);
findPrimeFactors(num / i);
}
}
int sumOfPrimes = multiplyPrimeFactors();
if(sumOfPrimes == value) {
return true;
}
It gets to the break statement then finally the check and then the return statement.
I am expecting the program to go back to the main method after my return statement, but it jumps up to:
findPrimeFactors(num / i);
and tries to finish the iteration...I guess my understanding is a flawed here, could someone explain to me why it is behaving like this? I can't wait to finish it of :) I'll find a more efficient way of doing it after I know I can get this inefficient one working.
You are using recursion, which means that a function will call itself.
So, if we trace what your function calls are when you call return, we will have something like that:
IntegerFactorise.main()
|-> IntegerFactorise.findPrimeFactors(2639)
|-> IntegerFactorise.findPrimeFactors(377)
|-> IntegerFactorise.findPrimeFactors(29) -> return true;
So, when you return in the last findPrimeFactors(), you will only return from this call, not from all the stack of calls, and the execution of the previous findPrimeFactors() will continue just after the point where you called findPrimeFactors().
If you want to return from all the stack of calls, you have to modify your code to do something like that:
else if(isPrimeNumber(i) && num % i == 0) {
primeFactors.add(i);
return findPrimeFactors(num / i);
}
So that when the last findPrimeFactors() returns, all the previous findPrimeFactors() which called it will return too.
I think the problem is that you are ignoring the return value from your recursive call to findPrimeFactors().
Let's walk through this. We start with the initial call to findPrimeFactors that happens in main. We then enter the for loop as it's the first thing in that method. Now let's say at some point we get into the else statement and thus recursively call frindPrimeFactors(num / i). This will suspend the looping, but as this recursive call starts to run you enter the for loop again (remember, the previous loop is merely paused and not finished looping yet). This time around you encounter the break, which allows this recursive call to finish out, returning true of false. When that happens you are now back to the original loop. At this point the original loop continues even if the recursive call returned true. So, you might try something like this:
if (findPrimeFactors(num / i))
return true;
I'm assuming that you need to continue looping if the recursive call returned false. If you should always finish looping upon return (whether true or false) then try this:
return findPrimeFactors(num / i);

Depth-first search terminating early

I'm creating a program in Java that solves the n-puzzle, without using heuristics, simply just with depth-first and breadth-first searches of the state space. I'm struggling a little bit with my implementation of depth-first search. Sometimes it will solve the given puzzle, but other times it seems to give up early.
Here's my DFS class. DepthFirstSearch() is passed a PuzzleBoard, which is initially generated by shuffling a solved board (to ensure that the board is in a solvable state).
public class DepthFirst {
static HashSet<PuzzleBoard> usedStates = new HashSet<PuzzleBoard>();
public static void DepthFirstSearch(PuzzleBoard currentBoard)
{
// If the current state is the goal, stop.
if (PuzzleSolver.isGoal(currentBoard)) {
System.out.println("Solved!");
System.exit(0);
}
// If we haven't encountered the state before,
// attempt to find a solution from that point.
if (!usedStates.contains(currentBoard)) {
usedStates.add(currentBoard);
PuzzleSolver.print(currentBoard);
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != 0) {
System.out.println("Moving left");
DepthFirstSearch(PuzzleSolver.moveLeft(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != PuzzleSolver.n-1) {
System.out.println("Moving down");
DepthFirstSearch(PuzzleSolver.moveDown(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[1] != PuzzleSolver.n-1) {
System.out.println("Moving right");
DepthFirstSearch(PuzzleSolver.moveRight(currentBoard));
}
if (PuzzleSolver.blankCoordinates(currentBoard)[0] != 0) {
System.out.println("Moving up");
DepthFirstSearch(PuzzleSolver.moveUp(currentBoard));
}
return;
} else {
// Move up a level in the recursive calls
return;
}
}
}
I can assert that my moveUp(), moveLeft(), moveRight(), and moveDown() methods and logic work correctly, so the problem must lie somewhere else.
Here's my PuzzleBoard object class with the hashCode and equals methods:
static class PuzzleBoard {
short[][] state;
/**
* Default constructor for a board of size n
* #param n Size of the board
*/
public PuzzleBoard(short n) {
state = PuzzleSolver.getGoalState(n);
}
public PuzzleBoard(short n, short[][] initialState) {
state = initialState;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.deepHashCode(state);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PuzzleBoard other = (PuzzleBoard) obj;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (state[i][j] != other.state[i][j])
return false;
}
}
return true;
}
}
As previously stated, sometimes the search works properly and finds a path to the solution, but other times it stops before it finds a solution and before it runs out of memory.
Here is a snippet of the output, beginning a few moves before the search stops searching.
...
Moving down
6 1 3
5 8 2
0 7 4
Moving right
6 1 3
5 8 2
7 0 4
Moving left
Moving right
Moving up
6 1 3
5 0 2
7 8 4
Moving left
Moving down
Moving right
Moving up
Moving up
Moving right
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
Moving up
Moving down
...
I truncated it early for brevity, but it ends up just moving up and down dozens of times and never hits the solved state.
Can anyone shed light on what I'm doing wrong?
Edit: Here is MoveUp(). The rest of the move methods are implemented in the same way.
/**
* Move the blank space up
* #return The new state of the board after the move
*/
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
I have had many problems with hashset in the past best thing to try is not to store object in hashset but try to encode your object into string.
Here is a way to do it:-
StringBuffer encode(PuzzleBoard b) {
StringBuffer buff = new StringBuffer();
for(int i=0;i<b.n;i++) {
for(int j=0;j<b.n;j++) {
// "," is used as separator
buff.append(","+b.state[i][j]);
}
}
return buff;
}
Make two changes in the code:-
if(!usedStates.contains(encode(currentBoard))) {
usedStates.add(encode(currentBoard));
......
}
Note:- Here no need to write your own hashcode function & also no need to implement equals function as java has done it for you in StringBuffer.
I got one of the problems in your implementation:-
In th following code:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = currentState.state;
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Here you are using the reference of same array as newState from currentState.state so when you make changes to newState your currentState.state will also change which will affect DFS when the call returns. To prevent that you should initialize a new array. Heres what to be done:-
static PuzzleBoard moveUp(PuzzleBoard currentState) {
short[][] newState = new short[n][n];
short col = blankCoordinates(currentState)[0];
short row = blankCoordinates(currentState)[1];
short targetCol = col;
short targetRow = row;
for(int i=0;i<n;i++) {
for(int j=0;j<n;j++) {
newState[i][j] = currentState.state[i][j];
}
}
newState[targetCol][targetRow] = currentState.state[col - 1][row];
newState[targetCol - 1][targetRow] = 0;
return new PuzzleBoard(n, newState);
}
Do this change for all moveup,movedown....
Moreover I donot think your hashset is working properly because if it was then you would always find your new state in hashset and your program would stop. As in equals you comparing the state arrays with same reference hence will always get true. Please try and use my encode function as hash.

Need to convert this for loop to a while loop

I solved a problem recently. But I have this one piece of code where I dont utilize the for loop initialization and condition check. It looks a bit odd that way for a for loop. I want to convert it into a while loop. Please help me do it. I tried many times, but somewhere something is missing.
for(;;current =(current+1)%n){
if(eliminated[current%n]){
continue;
}else{
inkiPinki++;
if(inkiPinki == m){
eliminated[current%n] = true;
printStatus(eliminated, people);
remainingGuys--;
break;
}
}
}
In the above code eliminiated[index] is a boolean.
Edit: Thanks to Geoff who provided me with a solution which I further minimized like this.
while( eliminated[current] || ++inkiPinki != m )
current = (current+1) % n;
eliminated[current] = true;
printStatus( eliminated, people );
remainingGuys--;
All for loops can be converted to while loops using the following pattern:
for (..xxx..; ..yyy..; ..zzz..) {
..aaa..
}
becomes
...xxx...
while (...yyy...) {
..aaa..
..zzz..
}
remember that
for (;;) {
..aaa..
}
is equivalent to
for (nop; true; nop) {
..aaa..
}
where "nop" means no operations.
In your example this makes your loop:
for(;;current =(current+1)%n){
if(eliminated[current%n]){
continue;
}else{
inkiPinki++;
if(inkiPinki == m){
eliminated[current%n] = true;
printStatus(eliminated, people);
remainingGuys--;
break;
}
}
}
equivalent to
// no initialzation needed
while(true) {
//if(eliminated[current%n]){
// continue;
//}else{
if(!eliminated[current%n]){
inkiPinki++;
if(inkiPinki == m){
eliminated[current%n] = true;
printStatus(eliminated, people);
remainingGuys--;
break;
}
}
current =(current+1)%n;
}
From there, you can simplify it further, if you wish.
Try
while( true ) {
if( !eliminated[current] ) {
if( ++inkiPinki == m ) {
break;
}
}
current = (current+1) % n;
}
eliminated[current] = true;
printStatus( eliminated, people );
remainingGuys--;
It should be logically equivalent.
How I would do it:
while (inkiPinki < m) {
if (!eliminated[current % n]) {
inkiPinki++;
if (inkiPinki == m) {
eliminated[current % n] = true;
}
}
if (inkiPinki < m) {
current = (current + 1) % n;
}
}
printStatus(eliminated, people);
remainingGuys--;
This code accomplishes exactly the same thing as your original for loop, except it uses logical tests to determine whether or not it should continue to loop. There's no need for continue or break. If you find yourself using either of these statements, there's probably some refactoring that should be done.
I seem to have an inordinate fondness for using Booleans as integers:
for (;inkiPinki<m; inkPinki += !eliminated[current])
current = (current + 1) %n;
eliminated[current] = true;
printStatus(eliminated, people);
remainingGuys--;
I've also changed current%n to simply current in a couple of places, because the %n is already done where current is incremented, so current should already be reduced modulo n.
If I were doing it, I'd probably change the sense, so instead of eliminated, it was something like remaining:
for (;inkiPinki<m; inkPinki += remaining[current])
current = (current + 1) %n;
remaining[current] = false;
printStatus(remaining, people);
remainingGuys--;

Categories