I'm trying to write a while switch case kinda code for modeling a finite state machine that searches a string of As and Bs to see if the string "ABBA" is present. When I input just "ABBA", it outputs Word found! like it's supposed to. However, if I input "AABBA" it doesn't find the word & output the right message. Any help is appreciated. Thanks!
import java.util.*;
public class AB{
public static void main(String args[]){
Scanner input = new Scanner(System.in);
String word = input.next();
int current = 0;
int status = 0;
System.out.println("Starting to evaluate...");
while(status != 4){
for(int i = current; i < word.length(); i++){
String part = word.substring(current, i + 1);
switch(status){
case 0: //start
if(part.equals("A")){
status = 1;
}
else if(part.equals("B"){
status = 0;
current = i;
}
break;
case 1: //A is there now
if(part.equals("AB")){
status = 2;
}
else if(part.equals("AA"){
status = 1;
current = 1;
}
break;
case 2: //AB is there now
if(part.equals("ABB")){
status = 3;
}
else if(part.equals("ABA"){
status = 1;
current = 1;
}
break;
case 3: //ABB is there now
if(part.equals("ABBA")){
status = 4;
System.out.println("Word found!");
}
else if(part.equals("ABBB"){
status = 0;
current = i;
}
break;
}
}
}
}
}
What I can see ineffective in your approache is that you actually do not use the power of a state machine. First of all you should understand what drives your machine through the states. In your example each sequential letter of the input string does. Since you have taken a state you should now check to which state would the next symbol switch your machine. Let me suggest the following implementation..
Here is the state diagram:
Here is the code implementing the diagram:
public boolean abbaMatcher(String abba)
{
int state = 0;
int symbol = 0;
while (symbol < abba.length()){
char c = abba.charAt(symbol);
switch (state){
case 0: if(c == 'a'){
state = 1;
}else{
state = 0;
};
break;
case 1: if(c == 'b'){
state = 2;
}else{
state = 1;
};
break;
case 2: if(c == 'b'){
state = 3;
}else{
state = 1;
};
break;
case 3: if(c == 'a'){
return true;
}else{
state = 0;
};
break;
}
symbol++;
}
return false;
}
This could be written more easily with just a for loop, however the while/switch construnction is a requirement.
The following code is similar to your implementation but it accounts for dynamic sequences (different sequences), and does not mess with substrings but rather iterates over the string's underlying character array.
It also accounts for a sequence that starts in another sequence, for instance: Looking for the sequence "ABAB" in the string "ABABAB" would have the results "ABAB" found at index 0 and "ABAB" found at index 2. This can easily be removed by commenting out wIndex = startIndex.
Code:
public static void main (String[] args) throws java.lang.Exception {
// Scanner input = new Scanner(System.in);
String word = "B BABBABBA B";
String seq = "ABBA";
char[] wChars = word.toCharArray();
char[] sChars = seq.toCharArray();
int wIndex = 0; // wChars index
int sIndex = 0; // sChars index
int startIndex = 0; // starting index of the seq found in wChars
System.out.println("Starting to evaluate...");
while(wIndex < wChars.length) {
if(wChars[wIndex] == sChars[sIndex]) {
if(sIndex == 0) {
startIndex = wIndex;
}
sIndex += 1;
} else {
sIndex = 0;
}
if(sIndex >= sChars.length) {
System.out.println("Sequence \"" + seq + "\" found at index " + startIndex + ".");
sIndex = 0;
wIndex = startIndex; // set wIndex to startIndex to account for
// sequence within a sequence, basically
// backtracking
}
wIndex += 1;
}
}
Output:
Starting to evaluate...
Sequence "ABBA" found at index 3.
Sequence "ABBA" found at index 6.
Related
Here what I tried
sample input is "aabaa"
eg: in if condition val[0] = a[4]
if it is equal i stored it in counter variable if it is half of the length it original string it is palindrome
if it is not it is not a palindrome
I tried with my basic knowledge in java if there is any errors let me know
boolean solution(String inputString) {
int val = inputString.length();
int count = 0;
for (int i = 0; i<inputString.length(); i++) {
if(inputString.charAt(i) == inputString.charAt(val-i)) {
count = count++;
if (count>0) {
return true;
}
}
}
return true;
}
How about
public boolean isPalindrome(String text) {
String clean = text.replaceAll("\\s+", "").toLowerCase();
int length = clean.length();
int forward = 0;
int backward = length - 1;
while (backward > forward) {
char forwardChar = clean.charAt(forward++);
char backwardChar = clean.charAt(backward--);
if (forwardChar != backwardChar)
return false;
}
return true;
}
From here
In your version you compare first element with last, second with second last etc.
last element in this case is inputString.length()-1(so need to use 'inputString.charAt(val-i-1)' . If you iterate till end, then the count should be equal to length of the string.
for(int i = 0; i<inputString.length(); i++){
if(inputString.charAt(i) == inputString.charAt(val-i-1)){
count ++;
}
}
return (count==val); //true when count=val
Or alternatlively iterate till the mid point of the array, then count value is val/2.
for(int i = 0; i<inputString.length()/2; i++){
if(inputString.charAt(i) == inputString.charAt(val-i-1)){
count ++;
}
}
return (count==val/2); //true when count=val/2
There's no constraints in the question so let me throw in a more cheesy solution.
boolean isPalindrome(String in)
final String inl = in.toLowerCase();
return new StringBuilder(inl).reverse().toString().equals(inl);
}
A palindrome is a word, sentence, verse, or even a number that reads the same forward and backward. In this java solution, we’ll see how to figure out whether the number or the string is palindrome in nature or not.
Method - 1
class Main {
public static void main(String[] args) {
String str = "Nitin", revStr = "";
int strLen = str.length();
for (int i = (strLen - 1); i >=0; --i) {
revStr = revStr + str.charAt(i);
}
if (str.toLowerCase().equals(revStr.toLowerCase())) {
System.out.println(str + " is a Palindrome String.");
}
else {
System.out.println(str + " is not a Palindrome String.");
}
Method - 2
class Main {
public static void main(String[] args) {
int n = 3553, revNum = 0, rem;
// store the number to the original number
int orgNum = n;
/* get the reverse of original number
store it in variable */
while (n != 0) {
remainder = n % 10;
revNum = revNum * 10 + rem;
n /= 10;
}
// check if reversed number and original number are equal
if (orgNum == revNum) {
System.out.println(orgNum + " is Palindrome.");
}
else {
System.out.println(orgNum + " is not Palindrome.");
}
I have been given a task to create a class that given a String will create a palindrome with minimum number of assertions.
Example Runs:
Input: 123333
Output: 12333321
Input: 789
Output: 78987
Input: 1221
Output: 1221221
**Note a Palindrome should NOT return the same Palindrome.
I tried using a modified KMP algorithm as stated here.
I revert the string and compare it to the reverse + original string and then add the mismatches to the original string.
However my function only works for inputs with trailing digits (first example input) however an input like 1234 will return 1234123, '92837465' will return '928374659283746'
public static int[] computelps(String sample){
int[] lps = new int[sample.length()];
lps[0] = 0;
int i = 1;
int len = 0; // length of previous longest prefix suffix
while (i < sample.length()) {
if (sample.charAt(i) == sample.charAt(len)) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0) {
len = lps[len - 1];
}
else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
public static void Solution(File samplefile) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(samplefile));
String firstline = br.readLine();
String line;
while ((line = br.readLine()) != null) {
String reverse_str = "";
String newline = line.replace(".", "");
for (int i = newline.length() - 1; i >= 0; i--) {
reverse_str += newline.charAt(i);
}
int [] lps = computelps(reverse_str); // computes the lps of the pattern string
String tot = reverse_str + newline;
// KMP Algorithm modified.
int x = 0; // index for total_string(tot)
int y = 0; // index for pattern
String palindrome = newline;
while (x < tot.length()){
if(reverse_str.charAt(y) == tot.charAt(x)){
y++;
x++;
}
if(y == reverse_str.length()) {
y = lps[y - 1];
}
else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
palindrome += tot.charAt(x);
if ( y!= 0){
y = lps[y-1];
}
else{
x += 1;
}
}
}
System.out.println(palindrome);
}
}
I would appreciate any help. I find algorithms very challenging so please bear with me if my approach or code is sub-par.
*I fixed sample inputs and outputs as well as added my results.
It helps to split this problem in smaller problems, implement a separate method for each and check to see if each method works as expected. What will really help you will be to learn to use the debugger in your Ide. But until you do that you can test that each part of your code works as expected. So I simplified a little your code and split it up :
public static void main(String[] args){
System.out.println("computelps " + ("[0, 0, 0, 0]".equals(Arrays.toString(computelps("4321"))) ? "works" : "doesn't work" ));
System.out.println("reverse " + ("4321".equals(reverse("1234")) ? "works" : "doesn't work" ));
System.out.println("Solution " + ("1234321".equals(Solution("1234")) ? "works" : "doesn't work" ));
}
public static int[] computelps(String sample){
int[] lps = new int[sample.length()];
lps[0] = 0;
int i = 1;
int len = 0; // length of previous longest prefix suffix
while (i < sample.length()) {
if (sample.charAt(i) == sample.charAt(len)) {
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0) {
len = lps[len - 1];
}
else {
lps[i] = 0;
i++;
}
}
}
return lps;
}
public static String Solution(String line) {
String newline = line.replace(".", "");
String reverse_str = reverse(newline);
int [] lps = computelps(reverse_str); // computes the lps of the pattern string
// KMP Algorithm modified.
return kpmModified(newline, reverse_str, lps);
}
private static String kpmModified(String newline, String reverse_str, int[] lps) {
int x = 0; // index for total_string(tot)
int y = 0; // index for pattern
String tot = reverse_str + newline;
String palindrome = newline;
while (x < tot.length()){
if(reverse_str.charAt(y) == tot.charAt(x)){
y++;
x++;
}
if(y == reverse_str.length()) {
y = lps[y - 1];
}
else if( x < tot.length() && (reverse_str.charAt(y) != tot.charAt(x))){
palindrome += tot.charAt(x);
if ( y!= 0){
y = lps[y-1];
}
else{
x += 1;
}
}
}
return palindrome;
}
private static String reverse(String newline) {
String reverse_str = "";
for (int i = newline.length() - 1; i >= 0; i--) {
reverse_str += newline.charAt(i);
}
return reverse_str;
}
And the result is
computelps works
reverse works
Solution doesn't work
So your bug is in kpmModified method. I can't spend more time and I'm not familiar with the algorithm but you should continue like this and figure our what part of that method has the bug.
I think you overthink the problem. The question is basically adding a string's reversed version back to it's original, but not every character, right? So you might need to find something like a pointer to tell the function where to start to reverse.
One example. Let the string be 12333. If we add every character from the index string.length() to 0, it will be 1233333321, which is not correct, since there are duplicated 3's. We need to ignore those, so we need to add characters from string.length() - numOfDuplicateAtEnd to 0.
public String palindromic(String num) {
int i = num.length() - 1;
while (i > -1 && num.charAt(i) == num.charAt(num.length() - 1))
i--;
for (int k = i; k > -1; --k)
num += num.substring(k, k + 1);
return num;
}
Basically summarized in the title. https://ideone.com/E2BMS8 <-- that's a link to the code. I understand if you don't want to click it though so I'll paste it here as well. will just be disorganized. The code is supposed to flip the letters but keep words in the same position. I would like to figure that part out on my own though. Just need help with the run time error.
import java.util.*;
class Ideone {
public static void main (String[] args) throws java.lang.Exception {
Scanner input = new Scanner(System.in);
String sent, accum = "";
char check, get;
int len, count = 0;
System.out.print("Please enter the sentance you want reversed: ");
sent = input.nextLine();
len = sent.length();
for (int i = 0; i < len; i++) {
check = sent.charAt(len - i);
count += 1;
if (check == ' ') {
for (int p = 0; p < count; p++) {
while (p < count) {
get = sent.charAt(len - p);
accum += (get + ' ');
}
}
}
}
System.out.println("Reversed: " + accum);
}
}
The error String index out of range is cause because of the len is one more than the index range. Remove one on the index such I did below:
import java.util.*;
public class Ideone {
public static void main (String[] args) throws java.lang.Exception {
Scanner input = new Scanner(System.in);
String sent, accum = "";
char check, get;
int len, count = 0;
System.out.print("Please enter the sentance you want reversed: ");
sent = input.nextLine();
len = sent.length();
for (int i = 0; i < len; i++) {
check = sent.charAt(len - i - 1);
count += 1;
if (check == ' ') {
for (int p = 0; p < count; p++) {
get = sent.charAt(len - p - 1);
accum += (get + ' ');
}
}
}
System.out.println("Reversed: " + accum);
}
}
This is a classical "off by one" error -- something you will run into a lot as you find your programming feet. The issue in this case is the 0-based indexing. That is, the first character of a string is at index 0, and the last is at index "string length - 1". If we use sent = "Test"; as an example, then:
sent.charAt(0) == 'T'
sent.charAt(1) == 'e'
sent.charAt(2) == 's'
sent.charAt(3) == 't'
sent.charAt(4) == ??? // "That's an error, Jim!"
Note that index 4 -- which perhaps confusingly is also the length of the string -- is out of bounds. So, what happens during the first iteration of the loop, when i == 0:
check = sent.charAt(len - i); // ERROR! Because ...
==> = sent.charAt((4) - (0));
==> = sent.charAt( 4 ); // Doh!
I leave it to you to figure out how you might fix it.
so if Sequence 1 :CAG and Sequence 2 :AG, i am supposed to get the response
"Best alignment score :2 CAG AG"
but instead i am getting
"Best alignment score :0 CAG AG"
I believe my issue is in the 2nd if statement, as that what it seems like with the debugger.
when using the debugger it shows that the computer not going into the if statement.
public static int allignment (String dnaSequence1 , String dnaSequence2 /*,int offset*/){
int newScore = 0;
int bestScore = 0;
int newOffset = 0;
int bestOffset = 0;
for(int offset =0; offset<=(dnaSequence1.length()-dnaSequence2.length());offset++){
//newOffset ++;
newScore = 0;
for(int place =0; place<dnaSequence2.length();place++ ){
if(dnaSequence1.charAt(place) == dnaSequence2.charAt(place/*+offset*/)){
newScore ++;
if(newScore>bestScore){
bestScore = newScore;
bestOffset = newOffset;
}
}else{ continue;}
}
newOffset ++;
}
String space = " ";
System.out.println("Best alignment score :"+bestScore);
System.out.println(dnaSequence1);
System.out.print( space(bestOffset) + dnaSequence2);
int alignmentScore = dnaSequence1.compareToIgnoreCase(dnaSequence2);
return alignmentScore;
}
public static String space (int bestOffset){
String space = " ";
String offsetScaces = "";
for(int i = 0; i<bestOffset; i++){
offsetScaces+=space;
return offsetScaces;
}
return offsetScaces;
}
Your version is using the same index for both strings. So it checks if the nucleotide at index 0 in sequence1 ('C') matches the nucleotide at index 0 in sequence2 ('A') then it increments the index and checks if the nucleotide at index 1 in sequence1 ('A') matches the nucleotide at index 1 in sequence2 ('G') then it stops without ever finding a match.
012
CAG
AG
You can see from the example above that at no time is the character in the first string the same as the second (0: C/A, 1: A/G, 2: G/null)
It strikes me that maybe you're looking for the longest piece of dnaSequence2 that aligns to something in dnaSequence1, not just the longest piece that starts at index 0.
This version tries to find the whole 2nd sequence inside the 1st sequence and if it can't, it trims 1 nucleotide from the end of the 2nd sequence and tries again. Once it's trimmed the 2nd sequence to nothing, it starts again with the whole 2nd sequence and trims 1 nucleotide from the start and repeats the process (stopping if it finds a match)
public static int allignment(String dnaSequence1, String dnaSequence2 /*,int offset*/) {
int bestScore = -1;
int bestOffset = 0;
String bestSequence = null;
for(String tempSequence = dnaSequence2; tempSequence.length() > 0; tempSequence = tempSequence.substring(1)) {
for(String match = tempSequence; match.length() > 0; match = match.substring(0, match.length() - 1)) {
int matchIndex;
if (-1 != (matchIndex = dnaSequence1.indexOf(match))) {
if (match.length() > bestScore) {
bestOffset = matchIndex;
bestScore = match.length() ;
bestSequence = match;
break;
}
}
}
if (null != bestSequence && bestScore > tempSequence.length()) {
break; // don't bother checking any shorter sequences, we already have a better match
}
}
if (null != bestSequence) {
System.out.println("Best alignment score :" + bestScore);
System.out.println(dnaSequence1);
System.out.print(space(bestOffset) + bestSequence);
} else {
System.out.print(dnaSequence1+" and "+dnaSequence2+" cannot be aligned");
}
int alignmentScore = dnaSequence1.compareToIgnoreCase(dnaSequence2);
return alignmentScore;
}
public static String space(int bestOffset) {
StringBuilder builder = new StringBuilder();
for (int i = 0; i < bestOffset; i++) {
builder.append(" ");
}
return builder.toString();
}
I'm trying to figure out how to solve one of the problems from one of the ACM ICPC finals (from 2012, so I guess the most recent). It's called Fibonacci Words and is described here under Problem D.
I think I'm very close, as all the test cases except the last are giving the correct answer. But for the last, I'm getting 6440026026380244497, which is on the right order of magnitude but still way off--since the order of magnitude is huge. :)
Here's my Java code, with a lot of comments (too many, you think? could it be refactored?):
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class FibonacciWords {
public static StringBuilder[] updateChars(StringBuilder lastOneBack, StringBuilder firstTwoBack, StringBuilder lastTwoBack, StringBuilder firstThreeBack) {
int pattLen = lastOneBack.length();
StringBuilder[] newChars = new StringBuilder[2];
newChars[0] = new StringBuilder(pattLen); // will become the new lastOneBack!
newChars[1] = new StringBuilder(pattLen); // will become the new firstTwoBack!
if(lastOneBack.charAt(0) == 'E') { // lastOneBack not full yet
int shiftCharsBy = 0; // holds amount to shift lastOneBack by
for(int i = 0; i < pattLen; i++) {
if(firstTwoBack.charAt(i) != 'E') {
shiftCharsBy++; // need to move whatever is at beginning of firstTwoBack to end of lastOneBack
} else {
break; // when first 'E' is reached in firstTwoBack, the rest are 'E' also
}
}
for(int i = 0; i < pattLen-shiftCharsBy; i++) {
newChars[0].append(lastOneBack.charAt(i+shiftCharsBy)); // shift lastOneBack by shiftCharsBy characters
}
for(int i = 0; i < shiftCharsBy; i++) {
newChars[0].append(firstTwoBack.charAt(i)); // fill remainder of new lastOneBack with what's in firstTwoBack
}
} else { // lastOneBack already full
newChars[0] = lastTwoBack; // make lastOneBack lastTwoBack (following pattern)
}
if(firstTwoBack.charAt(pattLen-1) == 'E') { // firstTwoBack not full yet
if(lastOneBack.charAt(0) == 'E') {
for(int i = 1; i < pattLen; i++) {
if(lastOneBack.charAt(i) != 'E') {
newChars[1].append(lastOneBack.substring(i)); // move last characters of lastOneBack to front of new firstTwoBack
break;
}
}
int charsAdded = newChars[1].length();
for(int i = 0; i < pattLen-charsAdded; i++) {
newChars[1].append('E'); // fill whatever might remain with 'E'
}
} else {
//newChars[1] = lastOneBack;
for(int i = 0; i < pattLen; i++) {
if(firstTwoBack.charAt(i) != 'E') {
newChars[1].append(firstTwoBack.charAt(i));
} else {
break;
}
}
int charsAdded = newChars[1].length();
// now take from firstThreeBack--which also isn't full if firstTwoBack isn't--until pattLen is reached
for(int i = 0; i < pattLen-charsAdded; i++) {
newChars[1].append(firstThreeBack.charAt(i));
}
}
} else {
newChars[1] = firstTwoBack; // firstTwoBack doesn't change when already full
}
return newChars;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
String pattern = br.readLine();
long numPattTwoPrior = 0; // number of times pattern occurred in F(n-2)
if(pattern.equals("0")) {
numPattTwoPrior++; // since n starts at 2 below, increment this if pattern is F(0), or "0"
}
long numPattOnePrior = 0; // number of times pattern occurred in F(n-1)
if(pattern.equals("1")) {
numPattOnePrior++; // since n starts at 2 below, increment this if pattern is F(1), or "1"
}
int pattLen = pattern.length();
StringBuilder lastCharsInOnePrior = new StringBuilder(pattLen); // keeps track of last pattLen characters in F(n-1)
for(int i = 0; i < pattLen; i++) {
lastCharsInOnePrior.append('E'); // 'E' stands for empty
}
lastCharsInOnePrior.setCharAt(pattLen-1, '1'); // since F(1) = "1"
StringBuilder firstCharsInTwoPrior = new StringBuilder(pattLen);
for(int i = 0; i < pattLen; i++) {
firstCharsInTwoPrior.append('E');
}
firstCharsInTwoPrior.setCharAt(0, '0'); // since F(0) = "0"
StringBuilder lastCharsInTwoPrior = null; // last characters always the same as 2 back, so keep track of this
StringBuilder firstCharsInThreePrior = null; // used for special case in updateChars
// number of times pattern occurs in F(n)
long numPattCurr = (n == 0) ? numPattTwoPrior : (n == 1) ? numPattOnePrior : 0;
for(int i = 2; i <= n; i++) { // finding F(n) up to the n given by the input
numPattCurr = numPattTwoPrior + numPattOnePrior; // at least this many times in F(n)
// adding to above all patterns found as part of concatenating F(n-1) and F(n-2), but not either on its own
middle:
for(int j = 1; j < pattLen; j++) { // starting at pos. 1 b/c [0, pattLen) is all F(n-1)
if(lastCharsInOnePrior.charAt(j) == 'E') {
continue;
}
StringBuilder compareWith = new StringBuilder(pattLen); // to compare with pattern
for(int k = 0; k < pattLen; k++) {
if(j + k >= pattLen) { // reached end of characters in F(n-1), start checking F(n-2)
int posInFirstChars = (j + k) % pattLen;
if(firstCharsInTwoPrior.charAt(posInFirstChars) == 'E') {
break middle; // none of the remaining overlap between F(n-1) and F(n-2) is as long as pattern, so can stop here
} else {
compareWith.append(firstCharsInTwoPrior.charAt(posInFirstChars));
}
} else {
compareWith.append(lastCharsInOnePrior.charAt(j + k));
}
}
if(pattern.equals(compareWith.toString())) {
numPattCurr++; // this overlap matched pattern
}
}
// changing characters of F(n-1) and F(n-2), as needed, for next iteration
StringBuilder[] updatedChars = updateChars(lastCharsInOnePrior, firstCharsInTwoPrior, lastCharsInTwoPrior, firstCharsInThreePrior);
lastCharsInTwoPrior = lastCharsInOnePrior;
firstCharsInThreePrior = firstCharsInTwoPrior;
lastCharsInOnePrior = updatedChars[0];
firstCharsInTwoPrior = updatedChars[1];
// changing number of times pattern found for F(n-1) and F(n-2) for next iteration
numPattTwoPrior = numPattOnePrior;
numPattOnePrior = numPattCurr;
}
System.out.println(numPattCurr);
System.exit(0);
}
}
I think I only left in one line of commented code, which gave the exact same answers in all the test cases when that was the only line within its else block--though what I replaced it with is more correct.
Any suggestions on what I'm missing or how I might go about debugging the last test case? Or interested in talking it through with someone because you're preparing for the contest or just working on learning algorithms? Please let me know.
C++ solution with verification (online judge)