I'm currently writing a parser for a language that I'm creating, which needs to check if the current part of the stream fits one of the items in the passed array. A short version of the code is:
public abstract class Parser {
private StringReader reader; //This is a BufferedReader with rollback
//A single string lookahead method
public boolean lookahead(String toMatch, boolean rollback) throws ParseException {
char c;
//Mark the current position in the stream, so we can come back to it if needed
MarkToken currentMark = reader.mark();
//Iterate through the toMatch and check if each character matches
for(int i = 0; i < toMatch.length(); ++i) {
c = reader.nextChar();
if(toMatch.charAt(i) != c) {
break;
}
}
//Get the current image
String got = reader.currentImage(currentMark);
//If we don't have a match, rollback if necessary and return false
if(!got.equals(toMatch)) {
if(rollback) {
reader.rollBack();
}
return false;
}
return true;
}
//The String[] lookahead method
public int lookahead(String[] toMatch, boolean rollback) throws ParseException {
if(toMatch.length == 1) {
//If there is only one element in toMatch, send it to a cheaper function
if(lookahead(toMatch[0]))
return 0;
else return 1;
} else {
int maxLength = toMatch[0].length();
//We use this variable to keep track of how many valid choices are left
int choicesLeft = toMatch.length;
int i, j;
char current;
//Mark the current position in the stream, so we can come back to it if needed
MarkToken mark = s().mark();
//Get the length of the longest string in toMatch
for(i = 1; i < toMatch.length; ++i) {
maxLength = Math.max(maxLength, toMatch[i].length());
}
//Go up to the length of the longest string
for(i = 0; i < maxLength; ++i) {
//Get the next character from the stream
current = reader.nextChar();
//If we've reached the end of the stream:
if(current == -1 || current == '\uffff') {
//Get back a character in the stream
reader.rollbackChar();
//And check to see if we have a match
return ArrayUtils.indexOf(toMatch, reader.currentImage(mark));
}
//Go through each item in toMatch
for(j = 0; j < toMatch.length; ++j) {
if(toMatch[j] != null) {
//Check to see if the character matches or not
if(toMatch[j].charAt(i) != current) {
//We null an item in toMatch if it doesn't apply any more
toMatch[j] = null;
--choicesLeft;
}
}
}
//If we only have one choice left, see if there is a match (will return -1 if not)
if(choicesLeft == 1) {
return ArrayUtils.indexOf(toMatch, reader.currentImage(mark));
}
}
//If there is no
if(rollback) {
reader.rollBackTo(mark);
}
}
return -1;
}
}
This function would be called to check if the stream contained certain symbols (. .* $# // " ' """ ''' etc.) and consume them greedily.
I would only be providing an array of maximum 10-15 items at once, so removing items from the array may not be the best optimisation.
Is there a more efficient way of doing this, certain methods or loops that I should be using?
Related
If anyone could help me find out what I did wrong, it would be really appreciated. I have taken a few shots at this and have gotten closer with each version of my code. I started by having a linked list within the SearchPath class itself but now I moved it to the Node class. For some reason the code works and finds the end, but it does not properly remove some stuff from the stack. Feel free to give it a try. When the code finishes elements from the stack are supposed to be removed and it does but some extra coordinates end up in there. Not sure if it is because of the way I handled the processing of the already checked nodes or if it the recursion itself. This could also just be a horrible implementation of the problem that needs to be solved and maybe I need to think of another way to solve it, but I know the answer is right there. Possibly also take a look at how I included the linked list and stack as static variables within the node class. Should they have maybe been added elsewhere or could that have been causing some of the issues. Thanks a lot. Also the way it works is by inputting a grid of the same dimensions. Finish is indicated with F and start is indicated with S. The walls are X and the path is O to find the way throught path.
/* This program will implement a stack to try and traverse
a grid from a text file that contains a path. It will try
and find a path to the end and when it does it succeeds.
If it does not find the end that means that there was
not path that exists to it. Reads a file as input.
*/
import java.util.Stack;
import java.util.Scanner;
import java.io.File;
import java.io.FileReader;
import java.lang.Exception;
import java.util.LinkedList;
// This class will represent information about a part in the board and will be used by the
// algorithim to determine what to do next.
class Node {
private static Stack<Node> pathLocation = new Stack<>(); // Create a stack that will hold nodes for the algorithm
// to traverse the area.
private static LinkedList<int[]> checkedLocations = new LinkedList<int[]>();
private static int totalMoves = 0;
private int rowNumber, columnNumber;
private boolean checked;
public Node() { // Constructor for a default node.
}
// Gets the current node in the stack.
public Node getLocaiton() {
return pathLocation.peek();
}
// Removes a node from the stack.
public void removeLocation() {
pathLocation.pop();
}
// Adds a new node to the stack.
public void newLocation(Node nextPath) {
pathLocation.push(nextPath);
}
public Stack<Node> getStack() {
return pathLocation;
}
public int getRowLocation() {
return rowNumber;
}
public int getColumnLocation() {
return columnNumber;
}
public void setRowLocation(int inputRow) {
rowNumber = inputRow;
}
public void setColumnLocation(int inputColumn) {
columnNumber = inputColumn;
}
public void setChecked(boolean input) {
checked = input;
}
public boolean getChecked() {
return checked;
}
public int getTotalMoves() {
return totalMoves;
}
public void setTotalMoves(int input) {
totalMoves = input;
}
public boolean getChecked(int inputColumn, int inputRow) {
for (int[] i : checkedLocations) {
if (inputColumn == i[0] && inputRow == i[1]) {
return true;
}
}
return false;
}
public boolean addChecked(int inputColumn, int inputRow) {
this.setColumnLocation(inputColumn);
this.setRowLocation(inputRow);
for (int[] i : checkedLocations) {
if (this.getColumnLocation() == i[0] && this.getRowLocation() == i[1]) {
--totalMoves;
this.checked = true;
return this.checked;
}
}
int[] temp = { this.getColumnLocation(), this.getRowLocation() };
checkedLocations.push(temp);
this.checked = false;
++totalMoves;
return this.checked;
}
}
class Board {
private int size; // This will determine the size of the board which is obtained from the
// BoardFile class.
private char[][] boardArea; // The current location on the board. This current program supports double
// array. Could later be upgraded to support more dimensions.
private int boardColumn;
private int boardRow;
Board(BoardFile inputBoard) throws Exception { // This constructor could throw and exception.
Scanner boardRead = inputBoard.processedBoard(); // Obtained the scanner from the boardFile class.
String temp; // Strings that will be processed and saved by the scanner.
while (boardRead.hasNext()) { // Processes infromation from the board as long as there is information to read.
temp = boardRead.nextLine(); // Sets a temp string equal to what was next in the file.
int tempSize; // Remembers the size of the temp string.
size = temp.length(); // Sets the total size of game area.
boardColumn = size;
boardArea = new char[size][size];
int j = 0;
boolean startFound = false, endFound = false; // Makes sure there is a finish and a start.
while (temp.length() == size) {
for (int i = 0; i < temp.length(); ++i) { // This loop will construct the game board and
// and makes sure everything is correct.
if (temp.charAt(i) == 'X' || temp.charAt(i) == 'O' || temp.charAt(i) == 'F' || temp.charAt(i) == 'S') {
boardArea[i][j] = temp.charAt(i);
// The following if statements check to make sure there is only one instance of
// finish and start.
if (temp.charAt(i) == 'F' && !endFound) {
endFound = true;
}
else if (temp.charAt(i) == 'F' && endFound) {
throw new Exception("The finish was already found. Please check and try again.");
}
else if (temp.charAt(i) == 'S' && !startFound) {
startFound = true;
}
else if (temp.charAt(i) == 'S' && startFound) {
throw new Exception("The start was already found. Please check and try again.");
}
}
else {
// throws an exception in case one of the characters was not excpected.
throw new Exception("There was a incorrect character within the board. Please check and try again.");
}
}
if (boardRead.hasNext()) {
tempSize = temp.length(); // Assign the previous line size.
temp = boardRead.nextLine(); // Assign the next line.
if (tempSize != temp.length()) { // Check to make sure both lines are the same size.
throw new Exception("The size of the board is not correct. Please check and try again.");
}
}
else {
break;
}
++j; // Increment the row.
if (j > size - 1) { // Makes sure the area in the map is correct.
throw new Exception("The area in the map is not the same. Please check and try again.");
}
boardRow = j; // Sets the row number.
}
if (j != size - 1) {
throw new Exception("The area in the map is not the same. Please check and try again.");
}
if (!endFound) {
throw new Exception("The end was not found. Please check and try again.");
}
if (!startFound) {
throw new Exception("The start was not found. Please check and try again.");
}
}
}
public char[][] getBoardArea() { // Returns the array.
return boardArea;
}
public char getBoardLocation(int inputColumn, int inputRow) { // Gets a character a certain location
return boardArea[inputColumn][inputRow]; // within the array.
}
public int getBoardColumn() { // Gets the column total.
return boardColumn - 1;
}
public int getBoardRow() { // Gets the row total.
return boardRow;
}
}
// The class used to read a file.
class BoardFile {
private File file;
private FileReader createdBoard;
private Scanner readBoard;
BoardFile(String fileName) throws Exception { // Creates a file reader object.
file = new File(fileName);
if (!file.exists()) { // Makes sure the file is found.
throw new Exception("The file could not be found.");
}
createdBoard = new FileReader(file); // Creates the file reader.
readBoard = new Scanner(createdBoard); // Creates a new scanner object to read the board.
}
public Scanner processedBoard() { // Gets the scanner object from the read board.
return this.readBoard;
}
}
// This class is the actual searching and will be used to traverse the map.
public class PathSearch {
private Node node = new Node(); // Creates the node object to traverse the map area.
private Board board; // Creates the map.
private Integer[] saveLocation = new Integer[2]; // Create an array that saves a certain location.
PathSearch() throws Exception { // Accepts nothing but asks for a string that searchs for a file.
Scanner input = new Scanner(System.in);
String userFile;
System.out.println("Please enter the name of the file.");
userFile = input.nextLine();
input.close();
board = new Board(new BoardFile(userFile)); // This creates the board from a file that was input.
for (int i = 0; i < board.getBoardColumn(); ++i) { // Searches the board for the starting point.
for (int j = 0; j < board.getBoardRow(); ++j) {
if (board.getBoardLocation(i, j) == 'S') {
node.newLocation(new Node()); // Creates a new element in the stack.
saveLocation[0] = i; // Saves the column in which the node was found.
saveLocation[1] = j; // Saves the row in which the node was found.
System.out.println("Start found at " + (saveLocation[0]) + " " + (saveLocation[1]));
break; // Exits the loop since the information that was needed was processed.
}
}
}
if (saveLocation == null) {
throw new Exception("No starting point was found. Please check and try again.");
}
checkPath(saveLocation[0], saveLocation[1]);
}
// This method accepts two seperate inputs because it needs to remember if it
// checked the position it is currently at.
public Stack<Node> checkPath(int inputColumn, int inputRow) throws Exception {
node.addChecked(inputColumn, inputRow); // Get the current node and check if has been used already.
if (node.getChecked() && !node.getStack().empty()) { // Sees if it was checked and if the stack is not empty.
node.removeLocation(); // Removes the current node from the stack.
checkPath(node.getLocaiton()); // Uses the previous node to keep checking,
}
else {
Node tempNode = new Node(); // Creates a new temp node.
tempNode.setColumnLocation(inputColumn);
tempNode.setRowLocation(inputRow);
node.newLocation(tempNode); // Adds the temp node into the stack.
checkPath(node.getLocaiton()); // Starts checking at the new location.
}
return null; // Path was not found.
}
// This is a overloaded version of checkPath that accepts the current node
// and begins looking at the current node.
public Stack<Node> checkPath(Node node) throws Exception {
int inputColumn = node.getLocaiton().getColumnLocation();
int inputRow = node.getLocaiton().getRowLocation();
if (board.getBoardLocation(inputColumn, inputRow) == 'F') {
System.out.println("The end was found at " + node.getLocaiton().getColumnLocation()
+ " " + node.getLocaiton().getRowLocation());
System.out.println("Here is the path.");
while (!node.getStack().empty()) { // While the stack has information.
System.out.println(node.getLocaiton().getColumnLocation() + " " + node.getLocaiton().getRowLocation());
node.removeLocation(); // Remove the node to process the next.
}
System.out.println("The total moves were " + node.getTotalMoves());
return node.getStack();
}
// All statements to determine where to move next within the board.
if (inputColumn < board.getBoardColumn() && (board.getBoardLocation(inputColumn + 1, inputRow) == 'O'
|| board.getBoardLocation(inputColumn + 1, inputRow) == 'F')
&& !node.getChecked(inputColumn + 1, inputRow)) {
checkPath(inputColumn + 1, inputRow);
}
if (inputColumn > 0 && (board.getBoardLocation(inputColumn - 1, inputRow) == 'O'
|| board.getBoardLocation(inputColumn - 1, inputRow) == 'F')
&& !node.getChecked(inputColumn - 1, inputRow)) {
checkPath(inputColumn - 1, inputRow);
}
if (inputRow < board.getBoardRow() && (board.getBoardLocation(inputColumn, inputRow + 1) == 'O'
|| board.getBoardLocation(inputColumn, inputRow + 1) == 'F')
&& !node.getChecked(inputColumn, inputRow + 1)) {
checkPath(inputColumn, inputRow + 1);
}
if (inputRow > 0 && (board.getBoardLocation(inputColumn, inputRow - 1) == 'O'
|| board.getBoardLocation(inputColumn, inputRow - 1) == 'F')
&& !node.getChecked(inputColumn, inputRow - 1)) {
checkPath(inputColumn, inputRow - 1);
}
return null; // No path was found at that location.
}
}
I have to write a boolean function that takes a string and check if a string is a palindrome or not in java.
Here is my code
static boolean isPalindrome(String input)
{
int i = 0;
last = input.length() - 1;
while (i < last) {
if (input.charAt(i) != input.charAt(last))
return false;
i++;
last--;
}
return true;
}
I want to add this part to my code but I got stuck on that if there is only one character mismatch I should consider it as valid palindrome.
Sample results:
“book” -> true
“refer” -> true
“” -> true
Instead of immediately returning false when two characters are different, you keep a count of how many pairs of characters are different:
static boolean isPalindrome(String input)
{
int i = 0;
int last = input.length() - 1;
int differentCount = 0;
while (i < last) {
if (input.charAt(i) != input.charAt(last)) {
differentCount++;
// only return false if more than one character is different
if (differentCount > 1) {
return false;
}
}
i++;
last--;
}
return true;
}
Add a boolean flag that tracks whether you already found a mismatching pair of characters:
static boolean isPalindrome(String input)
{
boolean firstMismatch = true;
int i = 0;
last = input.length() - 1;
while (i < last) {
if (input.charAt(i) != input.charAt(last)) {
if (firstMismatch) {
firstMismatch = false;
} else {
return false;
}
}
i++;
last--;
}
return true;
}
I have these two methods- My code doesn't seem to be working as planned
What is is supposed to do is- Go through the array of characters- If there's not another character the same in the array, it is supposed to add itself to the index variable-
This is my comparing method
private boolean isValid(char c) {
for(int i = 0; i < letters.length; i++) {
if(Arrays.asList(letters).equals(c)) {
return false; //Not valid
}
}
return true;
Full code is below though
public void generate(String first, String second) {
tempString = new StringBuilder(first+second).reverse();
letters = new char[tempString.length()];
for(int i = 0; i < tempString.length(); i++) {
letters[i]= tempString.charAt(i);
if(isValid(tempString.charAt(i))) {
index += i;
}
}
}
private boolean isValid(char c) {
for(int i = 0; i < letters.length; i++) {
if(Arrays.asList(letters).equals(c)) {
return false; //Not valid
}
}
return true;
}
There is no need to convert to a List (and a List is not a primitive char), you can use == for comparing primitive values (such as your chars). Something like,
private boolean isValid(char c) {
for (int i = 0; i < letters.length; i++) {
if (letters[i] == c) {
return false;
}
}
return true;
}
or with an enhanced for-each loop like
private boolean isValid(char c) {
for (char letter : letters) { // <-- for each letter in letters.
if (letter == c) { // <-- if the letter is equal to the argument.
return false;
}
}
return true;
}
You should also test for validity before adding to the array like
if (isValid(tempString.charAt(i))) {
letters[index] = tempString.charAt(i);
index++;
}
Arrays.asList(letters).equals(c) is comparing the list to the character (Is the list equal to this character which is not what you want.
To find if a character is in the string you can instead do
string.indexOf('a') which will return -1 if the character is not present and >= 0 if it is in the string.
I have the class:
public class WordNode {
private String _word;
private WordNode _next;
....
}
and the following list:
public class TextList {
private WordNode _head;
public char mostFrequentStartingLetter(....){}
}
In the TextList class I should use a recursive method (mostFrequentStartingLetter) which returns the most frequent letter the words in the list starts with...
I have no idea from where to start even.....
Please help...
Thanks,
Alona
Just so you know i am not cheating:
public class TextList {
private WordNode _head;
public TextList(String text) {
String word = "";
WordNode tmp;
// After the split that in the array we are going over all the array
for (int i = 0; i < text.length(); i++) {
for (int j = 0; j < text.length(); j++) {
if (text.charAt(j) == ' ') {
word = text.substring(0, j);
text = text.substring(j + 1);
i = 0;
break;
} else if (j == text.length() - 1) {
word = text.substring(0, j + 1);
text = text.substring(j + 1);
break;
}
}
if (_head == null) {
tmp = new WordNode(word, null);
_head = tmp;
}
// if the word starts with a smalles letter then the head, make it
// the head
else if (_head.getWord().compareTo(word) > 0) {
tmp = new WordNode(word, _head);
_head = tmp;
} else {
WordNode current;
current = _head;
// go over all the nodes in the list and push the current word
// to the list in the right order
while (current.getNext() != null) {
if (current.getWord().compareTo(word) < 1
&& current.getNext().getWord().compareTo(word) > 0) {
tmp = new WordNode(word, current.getNext());
current.setNext(tmp);
break;
}
current = current.getNext();
}
// If the current was the tail, check that the word is bigger
// and then make it the tail.
if (current.getNext() == null
&& current.getWord().compareTo(word) < 1) {
tmp = new WordNode(word, null);
current.setNext(tmp);
}
}
}
}
public String mostFrequentWord() {
String frequentWord = _head.getWord();
WordNode current = _head;
int count = 0;
int max = 0;
while (current.getNext() != null) {
if (current.getWord().compareTo(current.getNext().getWord()) == 0) {
count++;
}
if (count > max) {
max = count; frequentWord = current.getWord();
}
current = current.getNext();
}
return frequentWord;
}
public String toString() {
String s = "";
WordNode current = _head;
int count = 1;
while (current != null) {
while (current.getNext() != null && current.getWord().equals(current.getNext().getWord())) {
count++;
current = current.getNext();
}
s += current.getWord() + "\t" + count + "\n";
count = 1;
current = current.getNext();
}
return s;
}
public char mostFrequentStartingLetter(....){}
}
Since this is homework, I'll only give you some hints.
There are two things you need to do here.
Iterate over your linked list recursively.
Keep track of starting letters.
When you have a recursive function, you need a stopping condition. Think about the stopping condition for your linked list. How do you know when you have reached the end of your linked list? What would the value of _next be?
Your method would end up looking something like this:
///The pieces in the angle brackets are for you to figure out.
public void determineStartingLetter(WordNode currentNode) {
if(!<stopping condition>) {
determineStartingLetter(<next node after currentNode>);
}
}
Now this only traverses the linked list. You also need to keep track of the starting characters you've seen so far. Think about the structure you could use to do that. You want to map the character to the number of times you've seen it. What data structure would do that for you?
Now where could you maintain such a structure? The easiest solution (but not the most maintainable or elegant) would be a private member of the TextList class. But there is a better way. What if you could simply pass this data structure into the recursive method, and then pass into every recursive call?
So then your method would look like this:
//As before, the things in angle brackets are for you to figure out.
public <data structure> determineStartingLetter(WordNode currentNode, <data structure>) {
if(!stopping condition>) {
<look at starting letter for currentNode>
<increment the count for this letter in the data structure>
return determineStartingLetter(<next node after currentNode>, <data structure>);
}
return <data structure>
}
This should give you enough of a hint to figure out how to do it. In the second part I've actually given you some more hints than I should have :).
I am very close to finishing my one practice problem that deals with a palindrome and a string parameter and I am stuck with the main method to call the method. Every time I compile my code it compiles, but then when I go to input data, it keeps on running and does not give me a result. Can anyone aid in me in what I need to do to get it to return the result? The problem just asks to create a method that checks if it is a palindrome, my main method to test it is what is giving me trouble.
This is my code:
import java.util.*;
public class TestisPalindrome
{
public static boolean isPalindrome(String str) {
int left = 0;
int right = str.length() -1;
while(left < right) {
if(str.charAt(left) != str.charAt(right)) {
return false;
}
}
left ++;
right --;
return true;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("Enter a string to see if it is a palindrome or not: ");
String st1 = scan.nextLine();
System.out.println(isPalindrome(st1));
}
}
right & left increment should be in while loop
while(left < right)
{
if(str.charAt(left) != str.charAt(right))
{
return false;
}
left ++;
right --;
}
You've created an infinite loop. You have a while loop, but never change the conditions.
while(left < right)
{
if(str.charAt(left) != str.charAt(right))
{
return false;
}
}
Assuming left < right when you start, this will never change.
You have lines to increment left and right, but your code will never reach those lines, since it never gets out of the while loop.
You are overthinking this. Look at StringBuffer:
StringBuffer input = new StringBuffer(str);
return str.equals(input.reverse()).toString);
Please note that there is a performance impact of your implementation:
while(left < right) { //multiply inner operations by n/2
if(str.charAt(left) != str.charAt(right)) { //three operations
return false;
}
//This need to be inside your while loop
left ++; //one operation
right --; //one operation
}
This leads to an O(n) = (n * 5) / 2. On the other hand, if you simply reverse a string, it's only O(n) = n in the worst case. This is not a significant impact, but can add up depending on how you're accessing this.
You can also solve it like this:
public static boolean isPalindrome (String str){
String convertedStr = "";
for (int i = 0; i <str.length(); i++){
if (Character.isLetterOrDigit(str.charAt(i)))
convertedStr += Character.toLowerCase(str.charAt(i));
}
if (convertedStr.equals(reverseString(convertedStr)))
return true;
else
return false;
} //End of isPalindrome
Here is the code I used to determine whether a string is Palindrome String or not:
private static boolean isPalindromeString(String str){
if (str == null)
return false;
int len = str.length();
for (int i=0; i<len/2 ; i++){
if (str.charAt(i) != str.charAt(len - i - 1)){
return false;
}
}
return true;
}
I hope this can help you.