I am coding a simple chatbot, and my method seems to be stuck in a loop.
This below is the method, and I suspect there is a problem with the while loop, but I cannot find where I am messing up. No problems with compiling and running other than the stuck loop.
The loop below takes in a complete string, statement, loops for specific keywords, goal, and the starts looking through the string at startPos
private int findKeyword(String statement, String goal, int startPos)
{
String phrase = statement.trim();
int psn = phrase.toLowerCase().indexOf(goal.toLowerCase(), startPos);
while (psn >= 0)
{
String before = " ", after = " ";
if (psn > 0)
{
before = phrase.substring(psn-1, psn).toLowerCase();
}
if (psn + goal.length() < phrase.length())
{
after = phrase.substring(psn + goal.length(), psn + goal.length() + 1).toLowerCase();
}
if (((before.compareTo("a") < 0) || (before.compareTo("z") > 0)) && ((after.compareTo("a") < 0) || after.compareTo("z") > 0))
{
return psn;
}
psn = phrase.indexOf(goal.toLowerCase(), psn + 1);
}
return -1;
}
psn = phrase.indexOf(goal.toLowerCase(), psn + 1);
will never rich to (psn < 0) thats the problem
Related
I have algorithm that translate six types of XPath queries into SQL queries. so, my code contains If-elseif-else statement (multiple if). I read from the internet that the time complexity of the If-elseif-else statement is the worst-case time of one one of the if that has more processing. I need to know what is is the time complexity for this code:
} else if (Query_Type == 5){
for (int i = strXPathQuery.length()-1; i > 0; i--) {
if (strXPathQuery.charAt(i) == '/') {
position = i;
break;
}
} // end for loop
Last_Node = strXPathQuery.substring(position+1);
strAncestor_Path = "";
int bracket_pos=0;
for (int i = 0; i < position; i++) {
if (strXPathQuery.charAt(i) == '[') {
bracket_pos = i;
break;
} else if (strXPathQuery.charAt(i) == '/' && strXPathQuery.charAt(i+1) == '/') {
strAncestor_Path = strAncestor_Path + "%";
}
else {
strAncestor_Path = strAncestor_Path + strXPathQuery.charAt(i);
} // end if statement
} // end for
int operator_pos = 0;
String Node_condition="";
for (int i = bracket_pos+1; i < position-2; i++) {
if ((strXPathQuery.charAt(i) == '<') || (strXPathQuery.charAt(i) == '>') || (strXPathQuery.charAt(i) == '=') || (strXPathQuery.charAt(i) == '!')) {
operator_pos = i;
break;
}
else {
Node_condition = Node_condition + strXPathQuery.charAt(i);
} // end if }
String Value_condition="";
for (int i = operator_pos; i < position-1; i++) {
Value_condition = Value_condition + strXPathQuery.charAt(i);
} // end for loop
strSQLQuery = "SELECT L2.Node_Value \n" +
"FROM Leaf_Node L1, Leaf_Node L2, Ancestor_Path P\n" +
"WHERE P.Ances_PathExp LIKE '" + strAncestor_Path + "'\n" +
"AND L1.Ances_PathID = P.Ances_PathID \n" +
"AND L1.Node_Name = '" + Node_condition + "'\n" +
"AND L1.Node_Value '".replace("'", "") + Value_condition + "'\n".replace("'", "") +
"AND L2.Node_Name = '" + Last_Node + "'\n" +
"AND L1.Ances_PathID = L2.Ances_PathID \n" +
"AND L1.Ances_Pos = L2.Ances_Pos " ;
txtSQLQuery.setText(strSQLQuery);
}
}
You have three looks there that could be O(N^2). For example.
for (int i = 0; i < position; i++) {
...
strAncestor_Path = strAncestor_Path + strXPathQuery.charAt(i);
...
}
Assume (worst case) that for that loop, the value of position is strXPathQuery.length() ... or N. That means that you are appending a character to the same string N times. Since appending a character to a string is an O(N) operation. (The append is creating a new string, copying all characters in the existing string.) The complexity of doing that N times is O(N^2).
The average complexity could be better than that, but it will depend on the input.
(And I don't have the patience to get my head around what you are actually trying to here. The your code's crap style is making my eyes hurt.)
If you want to perform the performance, don't build strings like that. Use a StringBuilder.
StringBuilder path = new StringBuilder();
for (int i = 0; i < position; i++) {
...
path.append(strXPathQuery.charAt(i));
...
}
I am trying to create a function that does the following:
Assuming that the code input is "(a 1 2 (b 3 4 5 (c 6) |7) 8 9)"
where the pipe | symbol is the position of the cursor,
the function returns:
a String "b 3 4 5 (c 6) 7" representing the code that is in the scope of the cursor
an int 8 representing the start index of the string relative to the input
an int 30 representing the end index of the string relative to the input
I already have working code that returns exactly that. However, the problem lies in ignoring comments, while keeping track of context (e.g. String literals, my own literal delimiters, etc).
Here is the code which keeps track of context:
public static void applyContext(Context context, String s, String snext, String sprev) {
if (s.equals("\"")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = true;
} else if (context.context == Context.Contexts.STRING && context.stringDelimiterIsADoubleQuote && !sprev.equals("\\"))
context.context = Context.Contexts.MAIN;
} else if (s.equals("\'")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = false;
} else if (context.context == Context.Contexts.STRING && !context.stringDelimiterIsADoubleQuote && !sprev.equals("\""))
context.context = Context.Contexts.MAIN;
} else if (s.equals("/") && snext.equals("/")) {
if (context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.COMMENT;
} else if (s.equals("\n")) {
if(context.context == Context.Contexts.COMMENT)
context.context = Context.Contexts.MAIN;
}
else if (s.equals("\\")) {
if(context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.PATTERN;
else if(context.context == Context.Contexts.PATTERN)
context.context = Context.Contexts.MAIN;
}
}
Firstly, I'll be using the function above like so:
String sampleCode = "(a b "cdef" g \c4 bb2 eb4 g4v0.75\)";
Context c = new Context(Context.Contexts.MAIN);
for(int i = 0; i < sampleCode.length(); i++) {
String s = String.valueOf(sampleCode.charAt(i));
String snext = *nullcheck* ? String.valueOf(sampleCode.charAt(i + 1)) : "";
String sprev = *nullcheck* ? String.valueOf(sampleCode.charAt(i - 1)) : "";
applyContext(c, s, snext, sprev);
if(c.context == blahlbah) doBlah();
}
Second, I'll be using this both forwards an backwards, as the current method of doing the function stated at the top of the description is (in pseudocode) this:
function returnCodeInScopeOfCursor(theWholeCode::String, cursorIndex::int) {
var depthOfCodeAtCursorPosition::int = getDepth(theWholeCode, cursorIndex);
Context c = new Context(getContextAt(theWholeCode, cursorIndex));
var currDepth::int = depthOfCodeAtCursorPosition;
var startIndex::int, endIndex::int;
for(i = cursorIndex; i >= 0; i--) {//going backwards
s = .....
snext = ......
sprev = ......
applyContext(c, s, snext, sprev);
if(c.context == Context.MAIN) {
if s = "(" then currDepth --;
if s = ")" then currDepth ++;
}
when currDepth < depthOfCodeAtCursorPosition
startIndex = i + 1;
break;
}
currDepth = depthOfCodeAtCursorPosition;//reset
for(i = cursorIndex; i < theWholeCode.length; i++) {//going forwards
s = ...
snex......
sprev.....
applyContext(c, s, snext, sprev);
if(c.context == Context.MAIN) {
if s = "(" then currDepth ++;
if s = ")" then currDepth --;
}
when currDepth < depthOfCodeAtCursorPosition
endIndex = i - 1;
break;
}
var returnedStr = theWholeCode->from startIndex->to endIndex
return new IndexedCode(returnedStr, startIndex, endIndex);
As you can see, this function would work both forwards and in reverse. Or at least most of it. The only problem is that if I were to use this function backwards, the proper scanning of comments (denoted by the standard ECMA double slash "//") goes haywire.
If I were to create a separate function for reverse context application and check every line recursively for a double slash, then making everything after that '//' a COMMENT (or in the direction of the function's usage, everything before that //), it will take way too much processing time as I want to use this as a livecoding environment for music.
Also, removing the comments before trying to do that returnCodeInScopeOfCursor method may not be feasible... as I need to keep track of the indexes of the code and what not. If I were to remove the comments, there will be a big mess with all the code positions and keeping track of where did I remove what exactly and how many characters etc....
The text area input GUI I'm working with (RichTextFX) does not support Line-Char tracking, so everything is tracked using char index only, hence the problems...
So... I'm utterly perplexed as with what to do with my current code. Any help, suggestions, advice etc... will be greatly appreciated.
Could you pre-transform comments from // This is a comment<CR> to { This is a comment}<CR> you then have a language you can walk backwards and forwards.
Apply this transform on the way in and reverse it on the way out and all should be well. Notice we are replacing //... with {...} so all charaqcter offsets are retained.
Anyways, after a little experimenting with OldCurmudgeon's idea, I came up with a separate function to get context of the code in a reverse direction.
public static void applyContextBackwards(Context context, String entireCode, int caretPos) {
String s = String.valueOf(entireCode.charAt(caretPos));
//So far this is not used
//String snext = caretPos + 1 < entireCode.length() ? String.valueOf(entireCode.charAt(caretPos + 1)) : "";
String sprev = caretPos - 1 >= 0 ? String.valueOf(entireCode.charAt(caretPos - 1)) : "";
//Check for all the flags and what not...
if(context.commentedCharsLeft > 0) {
context.commentedCharsLeft--;
if(context.commentedCharsLeft == 0)
context.context = Context.Contexts.MAIN;//The comment is over
}
if(context.expectingEndOfString){
context.context = Context.Contexts.MAIN;
context.expectingEndOfString = false;
}
if(context.expectingEndOfPattern) {
context.context = Context.Contexts.MAIN;
context.expectingEndOfPattern = false;
}
//After all the flags are cleared, do this
if(context.commentedCharsLeft == 0) {
if (s.equals("\"")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = true;
} else if (context.context == Context.Contexts.STRING && context.stringDelimiterIsADoubleQuote && !sprev.equals("\\"))
context.expectingEndOfString = true;//Change the next char to a MAIN, cuz this one's still part of the string
} else if (s.equals("\'")) {
if (context.context == Context.Contexts.MAIN) {
context.context = Context.Contexts.STRING;
context.stringDelimiterIsADoubleQuote = false;
} else if (context.context == Context.Contexts.STRING && !context.stringDelimiterIsADoubleQuote && !sprev.equals("\""))
context.expectingEndOfString = true;//Change the next char to a MAIN, cuz this one's still part of the string
} else if (s.equals("\n")) {
int earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine = -1;//-1 for no comments
//Loop until the next \n is found. In the process, determine location of comment if any
for(int i = caretPos; i >= 0; i--) {
String curr = String.valueOf(entireCode.charAt(i));
String prev = i - 1 >= 0 ? String.valueOf(entireCode.charAt(i - 1)) : "";
if(curr.equals("\n"))
break;//Line has been scanned through
if(curr.equals("/") && prev.equals("/"))
earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine = caretPos - i;
}
//Set the comment context flag
//If no comments, -1 + 1 will be 0 and will be treated as no comments.
context.commentedCharsLeft = earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine + 1;
if(earliestOccuranceOfSingleLineCommentDelimiterAsDistanceFromThisNewLine > 0) {
context.context = Context.Contexts.COMMENT;
}
} else if (s.equals("\\")) {
if (context.context == Context.Contexts.MAIN)
context.context = Context.Contexts.PATTERN;
else if (context.context == Context.Contexts.PATTERN)
context.expectingEndOfPattern = true;//Change the next char to a MAIN cuz this one's still part of the Pattern
}
}
}
This is coding bat exercise: Java > Warmup-2 > stringX
What is the second block of code doing? Why does it produce the wrong answer?
public String stringX(String str) {
String answer = "";
for (int i = 0; i < str.length(); i++) {
if (str.substring(i , i+1).equals("x") && i != 0 && i != str.length()-1) {
answer = answer + "";
}
else {
answer = answer + str.substring(i , i + 1);
}
}
return answer;
}
vs
public String stringX(String str) {
String answer = "";
for (int i = 0; i < str.length(); i++) {
if (str.substring(i , i+1).equals("x") && i != 0 && i != str.length()-1) {
answer = answer + "";
}
answer = answer + str.substring(i , i + 1);
}
return answer;
}
The first block will run else only if the first if statement is false. else statement can only run if none of the above conditional statements returned true (if and else if). However the second block will run regardless of whether the first if statement true or false.
Check out this doc for further explanation: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/if.html
The 2nd block executes all the code shown and thus always takes the substring of answer
Given a string and a non-empty substring sub, compute recursively the largest substring which starts and ends with sub and return its length.
strDist("catcowcat", "cat") → 9
strDist("catcowcat", "cow") → 3
strDist("cccatcowcatxx", "cat") → 9
my solution
public int strDist(String str, String sub) {
int i = sub.length();
int j = str.length();
int count = 0;
if (str.length() == 1 && str.equals(sub)) {
return 1;
} else if (str.length() < sub.length() || str.length() <= 1) {
return 0;
}
if (str.substring(0, i).equals(sub)) {
if (str.substring(str.length() - i, str.length()).equals(sub)) {
return str.length();
} else {
strDist(str.substring(0, str.length() - i), sub);
}
} else {
strDist(str.substring(1, str.length()), sub);
}
return 0;
}
tell me how to correct my code?
Why does this need to be done with recursion?
Edit: fixed code to handle case where sub is not present in str, or only present once.
public int strDist(String str, String sub) {
int last=str.lastIndexOf(sub);
if (last != -1) {
int first=str.indexOf(sub);
if (first != last)
return last - first + sub.length();
}
}
return 0;
}
Recursion is great, if it is suited to the problem. In this case, recursion doesn't add value, and writing it with recursion for the sake of recursion makes the code inefficient.
This will , "compute recursively the largest substring which starts and ends with sub and return its length" as you described.
public class PuzzlingRecursion {
static String substringFound = "";
public static void main(String[] args) {
String sentence = "catcowcat";
String substring = "cat";
int sizeString = findNumberOfStrings(sentence, substring, 0);
System.out.println("you are searching for: " + substring);
System.out.println("in: " + sentence);
System.out.println("substring which starts and ends with sub and return its length is:"+substringFound + ", " + sizeString);
}
private static int findNumberOfStrings(String subStringPassed,
String setenecePassed, int count) {
if (subStringPassed.length() == 0) {
return count + 0;
}
if (subStringPassed.length() < setenecePassed.length()) {
return count + 0;
}
count++;
String lastStringMiddle = subStringPassed.replaceAll("(.*?)" + "("
+ setenecePassed + ")" + "(.*?)" + "(" + setenecePassed + ")"
+ "(.*?.*)", "$3");
if (subStringPassed.contains(setenecePassed)
&& lastStringMiddle.length() != setenecePassed.length()) {
if (subStringPassed.contains(setenecePassed)
&& lastStringMiddle.contains(setenecePassed)) {
// only found one item no pattern but according to the example
// you posted it should return the length of one word/substring
count = setenecePassed.length();
substringFound = subStringPassed;
return count;
}
}
// makesure the lastSrtringMiddle has the key we are search
if (!lastStringMiddle.equals(subStringPassed)) {
subStringPassed = subStringPassed.replaceFirst(setenecePassed, "");
String lastString = subStringPassed.substring(0,
subStringPassed.lastIndexOf(setenecePassed));
if (null != lastString && !"".equals(lastString)) {
count = lastStringMiddle.length() + setenecePassed.length()
+ setenecePassed.length();
substringFound = setenecePassed + lastStringMiddle
+ setenecePassed;
subStringPassed = "";
}
return findNumberOfStrings(subStringPassed, setenecePassed, count);
}
return count;
}
}
I think this is much nicer recursive solution:
public int strDist(String str, String sub) {
if (str.length()==0) return 0;
if (!str.startsWith(sub))
return strDist(str.substring(1),sub);
if (!str.endsWith(sub))
return strDist(str.substring(0,str.length()-1),sub);
return str.length();
}
Hi im trying to count in a if/else but it wont work.
Every time you try to find the number 32 it should count +1. This is not working for me..
So... i want it to count all the try's ive done to find number 32 so it shows me how much times i tried it.
Can anyone help me out?
String antwoord = null;
int getal = 32;
int count = 0;
if((Integer.parseInt(txt_input.getText().toString()) ) == getal)
{
antwoord = "Goed! in: " + count + " keer";
}
else if((Integer.parseInt(txt_input.getText().toString()) ) <= getal)
{
antwoord = "Hoger... ";
count++;
}
else if((Integer.parseInt(txt_input.getText().toString()) ) >= getal)
{
antwoord = "Lager... ";
count++;
}
count++;
lbl_hoger_lager.setText(antwoord);
You are mixing your logic in the if(condition).
It should be
if(number is equal){
// some operation
}
else if(number is greater){
// some operation
}
else if(number is lesser than X ){
// some operation
}
Hope this helps.
I think you wanted to do this :
String antwoord = null;
int getal = 32;
int count = 0;
if ((Integer.parseInt(txt_input.getText().toString())) == getal) {
count++;
antwoord = "Goed! in: " + count + " keer";
} else if ((Integer.parseInt(txt_input.getText().toString())) < getal) {
antwoord = "Hoger... ";
// count++;
}
else if ((Integer.parseInt(txt_input.getText().toString())) > getal) {
antwoord = "Lager... ";
// count++;
}
lbl_hoger_lager.setText(antwoord);
Some tipps:
You should avoid long strings of common code. For example (Integer.parseInt(txt_input.getText().toString()) ) appears three times. It's a long, complicated expression. How about evaluating this only once and storing the result in a local variable?
int userInput = (Integer.parseInt(txt_input.getText().toString()) );
(and the .toString() is probably not necessary, too)
If you want to count always, count outside of the if.
count is a local variable. It will be 0 every time the code is executed. If you want to preserve the value from previous attempts, you must use a field.
I just now tested with your code and it looks ok to me , obviously with some changes :
public class A
{
public static void main(String [] args)
{
String antwoord = null;
int getal = 32;
int count = 0;
String k ="32";
if((Integer.parseInt(k) ) == getal)
{
antwoord = "Goed! in: " + (count+1) + " keer";
}
else if((Integer.parseInt(k) ) <= getal)
{
antwoord = "Hoger... ";
count++;
}
else if((Integer.parseInt(k) ) >= getal)
{
antwoord = "Lager... ";
count++;
}
// count++;
System.out.println(antwoord);
//lbl_hoger_lager.setText(antwoord);
}
}
Output is :
Goed! in: 1 keer
The way you have it set up, count will increment if the input is greater than or less than 32.
This should work for you:
String antwoord = null;
int getal = 32;
int count = 0;
if((Integer.parseInt(txt_input.getText().toString()) ) == getal)
{
antwoord = "Goed! in: " + count + " keer";
}
else if((Integer.parseInt(txt_input.getText().toString()) ) < getal)
{
antwoord = "Hoger... ";
count++;
}
else if((Integer.parseInt(txt_input.getText().toString()) ) > getal)
{
antwoord = "Lager... ";
count++;
}
lbl_hoger_lager.setText(antwoord);