I'm trying to write a code that split a spaceless string into meaningful words but when I give sentence like "arealways" it returns ['a', 'real', 'ways'] and what I want is ['are', 'always'] and my dictionary contains all this words. How can I can write a code that keep backtracking till find the best matching?
the code that returns 'a', 'real', 'ways':
splitter.java:
public class splitter {
HashMap<String, String> map = new HashMap<>();
Trie dict;
public splitter(Trie t) {
dict = t;
}
public String split(String test) {
if (dict.contains(test)) {
return (test);
} else if (map.containsKey(test)) {
return (map.get(test));
} else {
for (int i = 0; i < test.length(); i++) {
String pre = test.substring(0, i);
if (dict.contains(pre)) {
String end = test.substring(i);
String fixedEnd = split(end);
if(fixedEnd != null){
map.put(test, pre + " " + fixedEnd);
return pre + " " + fixedEnd;
}else {
}
}
}
}
map.put(test,null);
return null;
}
}
Trie.java:
public class Trie {
public static class TrieNode {
private HashMap<Character, TrieNode> charMap = new HashMap<>();
public char c;
public boolean endOWord;
public void insert(String s){
}
public boolean contains(String s){
return true;
}
}
public TrieNode root;
public Trie() {
root = new TrieNode();
}
public void insert(String s){
TrieNode p = root;
for(char c : s.toCharArray()) {
if(! p.charMap.containsKey(c)) {
TrieNode node = new TrieNode();
node.c = c;
p.charMap.put(c, node);
}
p = p.charMap.get(c);
}
p.endOWord = true;
}
public boolean contains(String s){
TrieNode p = root;
for(char c : s.toCharArray()) {
if(!p.charMap.containsKey(c)) {
return false;
}
p = p.charMap.get(c);
}
return p.endOWord;
}
public void insertDictionary(String filename) throws FileNotFoundException{
File file = new File(filename);
Scanner sc = new Scanner(file);
while(sc.hasNextLine())
insert(sc.nextLine());
}
public void insertDictionary(File file) throws FileNotFoundException{
Scanner sc = new Scanner(file);
while(sc.hasNextLine())
insert(sc.nextLine());
}
}
WordSplitter class:
public class WordSplitter {
public static void main(String[] args) throws FileNotFoundException {
String test = "arealways";
String myFile = "/Users/abc/Desktop/dictionary.txt";
Trie dict = new Trie();
dict.insertDictionary(myFile);
splitter sp = new splitter(dict);
test = sp.split(test);
if(test != null)
System.out.println(test);
else
System.out.println("No Splitting Found.");
}
}
Using the OP's split method and the implementation of Trie found in The Trie Data Structure in Java Baeldung's article, I was able to get the following results:
realways=real ways
arealways=a real ways
However, if I remove the word "real" or "a" from the dictionary, I get the following results:
realways=null
arealways=are always
Here's the entire code I used to get these results:
public class Splitter {
private static Map<String, String> map = new HashMap<>();
private Trie dict;
public Splitter(Trie t) {
dict = t;
}
/**
* #param args
*/
public static void main(String[] args) {
List<String> words = List.of("a", "always", "are", "area", "r", "way", "ways"); // The order of these words does not seem to impact the final result
String test = "arealways";
Trie t = new Trie();
for (String word : words) {
t.insert(word);
}
System.out.println(t);
Splitter splitter = new Splitter(t);
splitter.split(test);
map.entrySet().forEach(System.out::println);
}
public String split(String test) {
if (dict.find(test)) {
return (test);
} else if (map.containsKey(test)) {
return (map.get(test));
} else {
for (int i = 0; i < test.length(); i++) {
String pre = test.substring(0, i);
if (dict.find(pre)) {
String end = test.substring(i);
String fixedEnd = split(end);
if (fixedEnd != null) {
map.put(test, pre + " " + fixedEnd);
return pre + " " + fixedEnd;
} else {
}
}
}
}
map.put(test, null);
return null;
}
public static class Trie {
private TrieNode root = new TrieNode();
public boolean find(String word) {
TrieNode current = root;
for (int i = 0; i < word.length(); i++) {
char ch = word.charAt(i);
TrieNode node = current.getChildren().get(ch);
if (node == null) {
return false;
}
current = node;
}
return current.isEndOfWord();
}
public void insert(String word) {
TrieNode current = root;
for (char l : word.toCharArray()) {
current = current.getChildren().computeIfAbsent(l, c -> new TrieNode());
}
current.setEndOfWord(true);
}
#Override
public String toString() {
return toString(root);
}
/**
* #param root2
* #return
*/
private String toString(TrieNode node) {
return node.toString();
}
public static class TrieNode {
private Map<Character, TrieNode> children = new HashMap<>() ;
private String contents;
private boolean endOfWord;
public Map<Character, TrieNode> getChildren() {
return children;
}
public void setEndOfWord(boolean endOfWord) {
this.endOfWord = endOfWord;
}
public boolean isEndOfWord() {
return endOfWord;
}
#Override
public String toString() {
StringBuilder sbuff = new StringBuilder();
if (isLeaf()) {
return sbuff.toString();
}
children.entrySet().forEach(entry -> {
sbuff.append(entry.getKey() + "\n");
});
sbuff.append(" ");
return children.toString();
}
private boolean isLeaf() {
return children.isEmpty();
}
}
public void delete(String word) {
delete(root, word, 0);
}
private boolean delete(TrieNode current, String word, int index) {
if (index == word.length()) {
if (!current.isEndOfWord()) {
return false;
}
current.setEndOfWord(false);
return current.getChildren().isEmpty();
}
char ch = word.charAt(index);
TrieNode node = current.getChildren().get(ch);
if (node == null) {
return false;
}
boolean shouldDeleteCurrentNode = delete(node, word, index + 1) && !node.isEndOfWord();
if (shouldDeleteCurrentNode) {
current.getChildren().remove(ch);
return current.getChildren().isEmpty();
}
return false;
}
}
}
I improved the original code by adding a toString() method to the Trie and TrieNode. Now, when I print out the Trie object "t", I get the following result:
{a={r={e={a=}}, l={w={a={y={s=}}}}}, w={a={y={s=}}}}
My conclusion is that the OP's TrieNode implementation is incorrect. The way the Trie is built, given the inputted string value, the behavior described by the OP seems to be correct.
Related
Code: Search word in Trie
Implement the function SearchWord for the Trie class.
For a Trie, write the function for searching a word. Return true if the word is found successfully, otherwise return false.
Note: main function is given for your reference which we are using internally to test the code.
class TrieNode{
char data;
boolean isTerminating;
TrieNode children[];
int childCount;
public TrieNode(char data) {
this.data = data;
isTerminating = false;
children = new TrieNode[26];
childCount = 0;
}
}
public class Trie {
private TrieNode root;
public int count;
public Trie() {
root = new TrieNode('\0');
count = 0;
}
private boolean add(TrieNode root, String word){
if(word.length() == 0){
if (!root.isTerminating) {
root.isTerminating = true;
return true;
} else {
return false;
}
}
int childIndex = word.charAt(0) - 'a';
TrieNode child = root.children[childIndex];
if(child == null){
child = new TrieNode(word.charAt(0));
root.children[childIndex] = child;
root.childCount++;
}
return add(child, word.substring(1));
}
public void add(String word){
if (add(root, word)) {
this.count++;
}
}
public boolean search(String word){
// add your code here
return search(root,word);
}
private boolean search(TrieNode root, String word){
if(word.length()==0){
return true;
}
int childIndex = word.charAt(0) -'a';
TrieNode child = root.children[childIndex];
if(child==null){
return false;
}
return search(child, word.substring(1));
}
}
//Main Function
code
import java.io.*;
public class Runner {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
public static void main(String[] args) throws IOException{
Trie t = new Trie();
String[] string = br.readLine().split("\\s");
int choice = Integer.parseInt(string[0]);
String word = "Null";
if (string.length!=1)
{
word = string[1];
}
while(choice != -1) {
switch(choice) {
case 1 : // insert
t.add(word);
break;
case 2 : // search
System.out.println(t.search(word));
break;
default :
return;
}
string = br.readLine().split("\\s");
choice = Integer.parseInt(string[0]);
if (string.length!=1)
{
word = string[1];
}
}
}
}
You need to make use of the isTerminating information. In search, change:
if(word.length()==0){
return true;
}
To:
if(word.length()==0){
return root.isTerminating;
}
I am trying to acheive JSON to JSON conversion in java based on the specification given on runtime.
Example : if at runtime source : com.gsdetails.gname,target : com.track.trackName (i.e source field should be mapped to target field in generated JSON)
My approach was to create N-array tree for the specification part and do breadth first travesal (get queue with it to craeate structure for resulting json)
I am using Jackson api to create tree from input JSON and traversing both queue(bfs) and input tree to create resulting json.
Unable to get expected output
PS : I thought of using JOLT api but it will not serve my purpose
Tree (for specification)
public class TrieBuilder {
public static void main(String[] args) throws Exception {
createSpec();
}
public static Trie createSpec() throws Exception {
BufferedReader reader = new BufferedReader(
new FileReader(""));
String currentLine = reader.readLine();
Trie trie = new Trie();
while (currentLine != null) {
String[] lines = currentLine.split(",");
String sourceLine = lines[0];
String targetLine = lines[1];
String sourcePath = sourceLine.split("=")[1];
String targetPath = targetLine.split("=")[1];
trie.insertWord(sourcePath.trim(), targetPath.trim());
currentLine = reader.readLine();
}
return trie;
}
}
class TrieNode {
String source;// consider this as content/reference point of a tree
String target;
boolean isEnd;
int count;
List childList;
boolean isRoot;
/* Constructor */
public TrieNode(String source, String target) {
childList = new ArrayList<TrieNode>();
isEnd = false;
count = 0;
this.source = source;
this.target = target;
}
public TrieNode subNodeWord(String word) {
if (childList != null) {
for (TrieNode eachChild : childList)
if (eachChild.source.equals(word))
return eachChild;
}
return null;
}
}
class Trie {
public TrieNode root;
/* Constructor */
public Trie() {
root = new TrieNode("", "");
}
public void insertWord(String sourceWords, String targetWords) {
if (searchWord(sourceWords) == true)
return;
TrieNode current = root;
String[] sourceArray = sourceWords.split(":");
String[] targetArray = targetWords.split(":");
for (int i = 0; i < sourceArray.length; i++) {
TrieNode child = current.subNodeWord(sourceArray[i]);
if (child != null) {
current = child;
} else {
current.childList.add(new TrieNode(sourceArray[i],
targetArray[i]));
current = current.subNodeWord(sourceArray[i]);
}
current.count++;
}
current.isEnd = true;
}
public boolean searchWord(String words) {
TrieNode current = root;
for (String word : words.split(":")) {
if (current.subNodeWord(word) == null) {
return false;
} else {
current = current.subNodeWord(word);
}
}
if (current.isEnd == true)
return true;
return false;
}
public Queue<TrieNode> bfsTraversal(TrieNode node) {
// TODO need to add logic for bfs/dfs for traversing the trie
Queue<TrieNode> queue = new LinkedList<>();
Queue<TrieNode> tempQueue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
TrieNode tempNode = queue.poll();
tempQueue.add(tempNode);
int counter = tempNode.childList.size(), i = 0;
if (tempNode == null)
break;
if (!tempNode.source.isEmpty())
System.out.println("Source :" + tempNode.source
+ " Target : " + tempNode.target);
while (i < counter) {
queue.add(tempNode.childList.get(i++));
}
}
tempQueue.poll();
return tempQueue;
}
Source to target mapping file :
source = com:track:trackDetails:fname, target = gsUser:gsProp:gsDetails:gsFirstName
source = com:track:trackDetails:lname, target = gsUser:gsProp:gsDetails:gsLastName
helper class (Actual transform):
public class JsonHelperClass{
// private Files file = null;// create a tempfile
private JsonNodeFactory factory;
private JsonFactory jsonFactory;
private ObjectMapper mapper;
private JsonNode jsonRoot;
private Queue<TrieNode> queue;
// private JsonParser jsonParser =
public JsonHelperClass() throws JsonProcessingException, IOException {
this.factory = JsonNodeFactory.instance;
this.jsonFactory = new JsonFactory();
this.mapper = new ObjectMapper();
this.jsonRoot = mapper.readTree(new File("json with data"));
}
public static void main(String[] args) throws Exception, Exception {
JsonHelperClass helperClass = new JsonHelperClass();
helperClass.jsonCreator();
ObjectNode objectNode = null;
ObjectNode result = helperClass.createJsonRecursively(objectNode);
System.out.println(result.toString());
}
public void jsonCreator() throws Exception {
Trie trie = TrieBuilder.createSpec();
queue = trie.bfsTraversal(trie.root);
}
public ObjectNode createJsonRecursively(ObjectNode outputJson) throws Exception {
TrieNode nodeOfQueue = queue.poll();
if(outputJson == null){
// create a root of the JSON
outputJson = factory.objectNode();
outputJson.put(nodeOfQueue.target, createJsonRecursively(outputJson));
}else if (jsonRoot.get(nodeOfQueue.source).isObject()){
// create an object to conatin other values/object
ObjectNode objectNode = factory.objectNode();
objectNode.put(nodeOfQueue.target,createJsonRecursively(outputJson));
outputJson.putAll(objectNode);
}else if(jsonRoot.get(nodeOfQueue.source).isArray()){
// create an array node and call for to create value it contains
ArrayNode arrayNode = factory.arrayNode();
int size = jsonRoot.get(nodeOfQueue.source).size();
for(int index = 0 ; index < size ; index++){
arrayNode.add(jsonRoot.get(nodeOfQueue.source).get(index));
}
outputJson.put(nodeOfQueue.target,arrayNode);
}else if(nodeOfQueue.isEnd){
// create leaf node
outputJson.put(nodeOfQueue.target, jsonRoot.get(nodeOfQueue.source));
return outputJson;
}
return outputJson;
}
I am working with java at the moment and I am trying to find out a way to stop printing to the console (for simplicity) after a certain index of a linkedList is reached. Any help explaining this would be much appreciated.
Below is my Node class used to create the list:
protected Integer data;
protected Node link;
public Node(Integer data, Node link) {
this.data = data;
this.link = link;
}
public Node addNodeAfter(Integer element) {
return link = new Node(element, link);
}
public String toString() {
String msg = "";
try {
if (link == null) {
msg = data + " null in tail";
} else {
msg = data + ", " + link.toString();
}
} catch (StackOverflowError e) {
// System.err.println("shit happened here");
}
return msg;
}
public Integer getData() {
return data;
}
public Node getLink() {
return link;
}
Create a method toString(int i) which takes as argument the number of elements which still have to be printed. If the argument is larger than zero and there is a valid link, then recursively call the toString(i - 1) method with i decreased by one:
Code:
public class Node {
public static void main(String[] args) {
Node linkedList = new Node(1, null);
Node node = linkedList;
for (int i = 2; i < 10; ++i)
node = node.addNodeAfter(i);
System.out.println(linkedList.toString(5));
}
public String toString(int i) {
if (i > 0) {
if (link == null)
return data.toString();
else
return data.toString() + " " + link.toString(i - 1);
} else
return "";
}
protected Integer data;
protected Node link;
public Node(Integer data, Node link) {
this.data = data;
this.link = link;
}
public Node addNodeAfter(Integer element) {
return link = new Node(element, link);
}
public Integer getData() {
return data;
}
public Node getLink() {
return link;
}
}
Output
1 2 3 4 5
You will need to extend the LinkedList class and override the toString() method, and then use your subclass.
Something like this:
public class MyLinkedList<E> extends LinkedList<E> {
#Override
public String toString() {
StringBuffer out = new StringBuffer("[");
for (int i=0; i < 3; i++) {
out.append(get(0).toString());
out.append(" ");
}
return out.toString();
}
}
And test it like this:
public class Main {
public static void main(String[] args) {
LinkedList<String> myList = new MyLinkedList<String>();
myList.add("one");
myList.add("two");
myList.add("three");
myList.add("four");
System.out.println(myList);
}
}
I am stuck at the logic as for how to generate a tree when a string input is provided . Such as when i have a input of following form -
(1 (2 (3) (4)) (5 (6) ())
Representing tree will be like so -
1
/ \
2 5
/ \ /\
3 4 6 ()
I can build tree from usual like tree.add(data) and then looking for the new node to be self added by judging if its greater or smaller than parent node . But i am not able to understand how to implement how to store above the above mention string in binary data structure form.
Here's what i have tried so far -
public class BinaryTree {
static Node root;
public static void levelorder(Node<?> n) {
Queue<Node<?>> nodequeue = new LinkedList<Node<?>>();
if (n != null)
nodequeue.add(n);
while (!nodequeue.isEmpty()) {
Node<?> next = nodequeue.remove();
System.out.print(next.data + " ");
if (next.getLeft() != null) {
nodequeue.add(next.getLeft());
}
if (next.getRight() != null) {
nodequeue.add(next.getRight());
}
}
}
private static String[] breakString(String elements) {
int indexOfOpenBracket = elements.indexOf("(");
int indexOfLastBracket = elements.lastIndexOf(")");
String removedPString = elements.substring(indexOfOpenBracket + 1,
indexOfLastBracket);
String[] breakRemovedPString = removedPString.split(" ");
if (breakRemovedPString[1].contains("(")) {
add(breakRemovedPString[0], breakRemovedPString[1], breakRemovedPString[2]);
}
return breakRemovedPString;
}
static void add(String parent, String leftString, String rightString) {
Node<String> nodeToAdd = new Node<String>(parent);
if (root == null) {
root = nodeToAdd;
root.left = new Node<String>(leftString);
root.right = new Node<String>(rightString);
} else {
}
}
public static void main(final String[] args) {
String treeString = "(1 (2) (3))";
breakString(treeString);
levelorder(root);
System.out.println();
}
}
Please suggest some implementation for this problem.
This is a classical parsing problem. The simplest approach is probably recursive descent. Here is a grammar for the tree language:
T -> ( number T T )
| ( number )
| ()
To turn this into a parser, we can go through a formal transformation to LL(1) form and then code. I'll let you read up on that and show what results.
package treereader;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.Reader;
enum Token { LPAREN, RPAREN, NUMBER, EOF, ERROR };
class Scanner {
final Reader in;
final char [] buf = new char[1];
final StringBuilder token = new StringBuilder();
private static final char EOF_MARK = Character.MIN_VALUE;
Scanner(Reader in) {
this.in = in;
read();
}
final void read() {
try {
if (in.read(buf) < 1) {
buf[0] = EOF_MARK;
}
} catch (IOException ex) {
System.err.println("i/o error");
buf[0] = EOF_MARK;
}
}
Token getNext() {
while (Character.isWhitespace(buf[0])) {
read();
}
if (Character.isDigit(buf[0])) {
token.setLength(0);
do {
token.append(buf[0]);
read();
} while (Character.isDigit(buf[0]));
return Token.NUMBER;
}
if (buf[0] == '(') {
read();
return Token.LPAREN;
}
if (buf[0] == ')') {
read();
return Token.RPAREN;
}
if (buf[0] == EOF_MARK) {
return Token.EOF;
}
return Token.ERROR;
}
String getString() {
return token.toString();
}
}
class Node {
public void print(PrintStream out) {
out.print("()");
}
}
class UnaryNode extends Node {
int val;
public UnaryNode(int val) {
this.val = val;
}
#Override
public void print(PrintStream out) {
out.print("(" + val + ")");
}
}
class BinaryNode extends Node {
int val;
Node left, right;
public BinaryNode(int val, Node left, Node right) {
this.val = val;
this.left = left;
this.right = right;
}
#Override
public void print(PrintStream out) {
out.print("(" + val + " ");
left.print(out);
out.print(' ');
right.print(out);
out.print(')');
}
}
class Parser {
final Scanner scanner;
Token lookAhead;
Parser(Reader in) {
scanner = new Scanner(in);
lookAhead = scanner.getNext();
}
void advance() {
lookAhead = scanner.getNext();
}
void match(Token token) throws IOException {
if (lookAhead == token) {
advance();
} else {
throw new IOException("Expected " + token + ", found " + lookAhead);
}
}
Node parse() throws IOException {
Node tree;
match(Token.LPAREN);
if (lookAhead == Token.NUMBER) {
int val = Integer.valueOf(scanner.getString());
advance();
if (lookAhead == Token.LPAREN) {
Node left = parse();
Node right = parse();
tree = new BinaryNode(val, left, right);
} else {
tree = new UnaryNode(val);
}
} else {
tree = new Node();
}
match(Token.RPAREN);
return tree;
}
}
public class TreeReader {
public static void main(String[] args) {
try {
Parser parser = new Parser(new BufferedReader(new FileReader(new File(args[0]))));
Node tree = parser.parse();
tree.print(System.out);
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
}
I'm writing program with several different algorithms for solving n-puzzle problem. I have problem with DFS algorithm, as it only finds solution for simplest combinations of depth 1 to 4, then it shows stack overflow error. Also, for depth 4 it shows solution of length 2147, which is obviously wrong. I ran out of ideas what is the problem.
I use HashMap to keep explored nodes and to retrace path. Here is my code for DFS:
public class DFS extends Path{
Node initial;
Node goal;
String order;
boolean isRandom = false;
ArrayList<Node> Visited = new ArrayList<Node>();
boolean goalFound=false;
public DFS(Node initial, String order, byte [][] goal_state){
this.initial=initial;
goal=new Node(goal_state);
this.order=order;
if(order.equals("Random"))isRandom=true;
Visited.add(initial);
path.put(this.initial, "");
runDFS(initial);
}
public void runDFS(Node current){
if(current.equals(goal))
{
goalFound=true;
System.out.println("Goal");
retracePath(current,true);
return;
}
if(!current.equals(goal) && goalFound==false)
{
Node child;
Moves m = new Moves(current);
if(isRandom)order=randomOrder("LRUD");
for (int i=0; i<4; i++)
{
String s = order.substring(i,i+1);
if(m.CanMove(s)==true)
{
child=m.move();
if(Visited.contains(child))
{
continue;
}
else
{
path.put(child,s);
Visited.add(child);
runDFS(child);
}
}
}
}
}
}
Node:
public class Node {
public byte[][] status;
private int pathcost;
public int getPathcost() {
return pathcost;
}
public void setPathcost(int pathcost) {
this.pathcost = pathcost;
}
public Node(byte[][] status)
{
this.status=new byte[status.length][status[0].length];
for(int i=0;i<status.length;i++){
for(int j=0;j<status[0].length;j++){
this.status[i][j]=status[i][j];
} }
}
#Override
public boolean equals(Object other)
{
if (!(other instanceof Node))
{
return false;
}
return Arrays.deepEquals(status, ((Node)other).status);
}
#Override
public int hashCode()
{
return Arrays.deepHashCode(status);
}
}
and Path:
public class Path {
public HashMap<Node,String> path;
public Path(){
path=new HashMap<Node, String>(100);
}
public void retracePath(Node nstate, boolean print){
String dir=path.get(nstate);
String textPath="";
int i=0;
while(!dir.equals("")){
textPath+=dir + ", ";
boolean changed=false;
if(dir.equals("L")) {dir="R"; changed=true;}
if(dir.equals("R") && changed==false) {dir="L";}
if(dir.equals("U")) {dir="D"; changed=true;}
if(dir.equals("D") && changed==false) {dir="U";}
Moves m=new Moves(nstate);
m.CanMove(dir);
nstate=new Node(m.move().status);
dir=path.get(nstate);
i++;
}
if(print==true) {textPath=textPath.substring(0,(textPath.length()-2));
System.out.println(i);
System.out.print(new StringBuffer(textPath).reverse().toString());}
}
public Node getParent(Node n){
String dir=path.get(n);
boolean changed=false;
if(dir.equals("L")) {dir="R"; changed=true;}
if(dir.equals("R") && changed==false) {dir="L";}
if(dir.equals("U")) {dir="D"; changed=true;}
if(dir.equals("D") && changed==false) {dir="U";}
Moves m=new Moves(n);
m.CanMove(dir);
n=new Node(m.move().status);
return n;
}
public String randomOrder(String order) {
ArrayList<Character> neworder = new ArrayList<Character>();
for(char c : order.toCharArray()) {
neworder.add(c);
}
Collections.shuffle(neworder);
StringBuilder newstring = new StringBuilder();
for(char c : neworder) {
newstring.append(c);
}
return newstring.toString();
}
}
If you have any ideas what is the problem and where is mistake I would be very thankful!