Boolean Expression Tokenization with Primes - java

I have to tokenize a boolean expression into an array list called tokens while considering primes. (apostrophes)
My code works for inputs such as
A'+B: [A', B]
B'+A: [B', A]
A'B'C+A: [A'B'C, A]
AB+C'D: [AB,C'D]
A'B'C: [A', B', C]
but will not work whenever the last character of the input string is an apostrophe such as:
A'+B'
AB+C'
A'B'C'
public static void tokenize(String expression)
{
String current = "";
String temp = "";
int counter=0;
for(int i = 0; i < expression.length(); i++)
{
char c = expression.charAt(i);
if(counter==0 && (c=='+' || c=='*'))
{
tokens.add(current);
limit++;
current = "";
if(tempUsed)
{
tokens.add(temp);
limit++;
tempUsed=false;
}
continue;
}
else if(c=='(')
{
counter++;
}
else if(c==')')
{
if(i+1<expression.length())
{
if(expression.charAt(i+1)=='\'')
{
temp = "("+current+")\'";
tempUsed = true;
}
}
counter--;
}
if(c!='(' && c!=')')
{
if(!(tempUsed && c=='\''))
current += c;
}
}
tokens.add(current);
limit++;
}
Any thoughts? Any help will greatly be appreciated. Thank you!

Related

Finding first non repeating character in a string in relation to Big O

I solved a task concerning finding the first non-repeating character. For example, given the input "apple" the answer would be "a", the first character that isn't repeated. Even though "e" is not repeated it's not the first character. Another example: "lalas" answer is "s".
public static char firstNonRepeatingCharacter(String input) {
boolean unique;
int count = input.length();
char[] chars = input.toCharArray();
for (int i = 0; i < input.length(); i++) {
unique = true;
for (int j = 0; j < input.length(); j++) {
count--;
char c = chars[i];
if (i != j && c == chars[j]) {
unique = false;
break;
}
}
if (unique) {
return input.charAt(i);
}
}
return (0);
}
I want to simplify this code due to the nested loop having O(n2) complexity. I have been looking at the code trying to figure out if i could make it any faster but nothing comes to mind.
Another way is to find the first and last indexOf the character. If both are same then it is unique.
public static char firstNonRepeatingCharacter(String input) {
for(char c:input.toCharArray())
if(input.indexOf(c) == input.lastIndexOf(c))
return c;
return (0);
}
EDIT:
Or with Java 8+
return (char) input.chars()
.filter(c -> input.indexOf(c) == input.lastIndexOf(c))
.findFirst().orElse(0);
O(n) is better.
Use an intermedian structure to handle the number of repetitions.
public static char firstNonRepeatingCharacter(String input) {
boolean unique;
int count = input.length();
char[] chars = input.toCharArray();
for (int i = 0; i < input.length(); i++) {
unique = true;
for (int j = 0; j < input.length(); j++) {
count--;
char c = chars[i];
if (i != j && c == chars[j]) {
unique = false;
break;
}
}
if (unique) {
return input.charAt(i);
}
}
return (0);
}
public static char firstNonRepeatingCharacterMyVersion(String input) {
Map<String,Integer> map = new HashMap();
// first iteration put in a map the number of times a char appears. Linear O(n)=n
for (char c : input.toCharArray()) {
String character = String.valueOf(c);
if(map.containsKey(character)){
map.put(character,map.get(character) + 1);
} else {
map.put(character,1);
}
}
// Second iteration look for first element with one element.
for (char c : input.toCharArray()) {
String character = String.valueOf(c);
if(map.get(character) == 1){
return c;
}
}
return (0);
}
public static void main(String... args){
System.out.println(firstNonRepeatingCharacter("potatoaonionp"));
System.out.println(firstNonRepeatingCharacterMyVersion("potatoaonionp"));
}
See this solution. Similar to the above #Lucbel. Basically, using a LinkedList. We store all non repeating. However, we will use more space. But running time is O(n).
import java.util.LinkedList;
import java.util.List;
public class FirstNone {
public static void main(String[] args) {
System.out.println(firstNonRepeatingCharacter("apple"));
System.out.println(firstNonRepeatingCharacter("potatoaonionp"));
System.out.println(firstNonRepeatingCharacter("tksilicon"));
}
public static char firstNonRepeatingCharacter(String input) {
List<Character> charsInput = new LinkedList<>();
char[] chars = input.toCharArray();
for (int i = 0; i < input.length(); i++) {
if (charsInput.size() == 0) {
charsInput.add(chars[i]);
} else {
if (!charsInput.contains(chars[i])) {
charsInput.add(chars[i]);
} else if (charsInput.contains(chars[i])) {
charsInput.remove(Character.valueOf(chars[i]));
}
}
}
if (charsInput.size() > 0) {
return charsInput.get(0);
}
return (0);
}
}
private static int Solution(String s) {
// to check is values has been considered once
Set<String> set=new HashSet<String>();
// main loop
for (int i = 0; i < s.length(); i++) {
String temp = String.valueOf(s.charAt(i));
//rest of the values
String sub=s.substring(i+1);
if (set.add(temp) && !sub.contains(temp)) {
return i;
}
}
return -1;
}

What is wrong with this Vowel question? Out of index

I'm doing a homework task that is:
Find a unique vowel in the string that is preceded by a consonant, and this consonant is preceded by a vowel.
Example: "eeaaAOEacafu"
Result is: u
What i already did:
Main.class
public class Principal {
public static void main(String[] args) {
// TODO Auto-generated method stub
Stream str = new Stream();
str.setText("eeaaAOEacafu");
System.out.println(str.returnChar(str.getVowel()));
}
Stream.class
public class Stream {
String text;
char vowel;
public String getText() {
return texto;
}
public void setText(String text) {
this.text = text;
}
public char getVowel() {
return vowel;
}
public void setVowel(char vowel) {
this.vowel = vowel;
}
public boolean isVowel(String str) {
str = str.toLowerCase();
for(int i=0; i<str.length(); i++) {
char c = str.charAt(i);
if(c=='a' || c=='e' || c=='i' || c=='o'|| c=='u') {
return true;
} else {
return false;
}
}
return false;
}
public char returnChar(String str) {
char last;
char next;
char result = '0';
int j=1;
for(int i=0; i<str.length(); i++) {
last = str.charAt(i-1);
next = str.charAt(i+1);
j++;
if(!vogal(str.charAt(i))) {
if(vogal(last) && vogal(next)) {
result = next;
}
}
}
this.setVowel(result);
return result;
} }
This returns: String index out of range: -1
This j=1, was to fix this -1 out of range. It fix but i got new one: out of range 11 because of the next.
The thing is: I have to use pure java and no API.
Can you guys help me?
use regular expressions for the test and locating the character
[aeiouAEIOU][bcdfghjklmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ]([aeiouAEIOU])
Use a String as a cheap map to keep track of which vowels you've already seen. Also, keep a count of how many consecutive consonants you've encountered. Then, when you hit a vowel that you haven't seen before preceded by a single consonant you've found your answer.
public static void main(String[] args)
{
String s = "eeaaAOEacafu".toLowerCase();
int consCount = 0;
String seenVowels = "";
for(int i=0; i<s.length(); i++)
{
char c = s.charAt(i);
if("aeiou".indexOf(c) >= 0)
{
if(seenVowels.indexOf(c) == -1)
{
if(consCount == 1)
{
System.out.println("Result: " + c);
break;
}
seenVowels += c;
}
consCount = 0;
}
else consCount++;
}
}
Output:
Result: u
The above works if we take 'unique' to mean that we haven't seen the vowel before. If the vowel has to be unique within the input string then things are a little more complicated. Now we have to keep track of each vowel that meets the original criteria, but remove the solution if we subsequently encounter another instance of the same vowel.
Here's some code to illustrate:
public static void main(String[] args)
{
String s = "afuxekozue".toLowerCase();
int consCount = 0;
String seenVowels = "";
String answer = "";
for(int i=0; i<s.length(); i++)
{
char c = s.charAt(i);
if("aeiou".indexOf(c) >= 0)
{
if(seenVowels.indexOf(c) == -1)
{
if(consCount == 1)
{
answer += c;
}
seenVowels += c;
}
else if(answer.indexOf(c) >= 0)
{
answer = answer.replaceAll(String.valueOf(c), "");;
}
consCount = 0;
}
else consCount++;
}
if(answer.length() > 0)
System.out.println("Result: " + answer.charAt(0));
}
Output:
Result: o

Check if letter 1 is always followed by number 2 and number 2 by number 3

I want to write a function that return true if if and only if
String a is always followed by String b, and String b is always followed by string c, this is what I wrote but it doesn't work :
public static boolean follows2(String s, String a, String b, String c) {
boolean res = true;
for (int i = 0; i < s.length(); i++) {
if (charAtPos(s, i).equals(a)) {
if (!(charAtPos(s, i + 1).equals(b))) {
res = false;
if (!(charAtPos(s, i + 2).equals(c))) {
res = false;
}
}
}
}
return res;
}
public static void main(String[] args) {
System.out.println(follows2(" koali oliali ", "a", "l", "i"));
// RETURN TRUE OK since for each " a" is followed by "l" then "i"
System.out.println(follows2("ipoipa", "i", "p", "a"));
//RETURN TRUE BUT IT'S NOT !
// The first " i" is followed by " p" then "o" which is not good
}
Here is the function that I wrote for:
String a is always followed by String b ( It works )
public static boolean follows(String s, String a, String b) {
boolean res = true;
for (int i = 0; i < s.length(); i++) {
if (charAtPos(s, i).equals(a)) {
if (!(charAtPos(s, i + 1).equals(b))) {
res = false;
}
}
}
return res;
}
public static String charAtPos(String s, int i) {
return String.valueOf(s.charAt(i));
}
public static void main(String[] args) {
System.out.println(follows("Arnold Barney", "r", "n"));
// RETURN TRUE because each "r" are followed by the letter "n"
System.out.println(follows("Arnold Barney", "n", "o"));
// RETURN FALSE , because not every "n" is followed by "o"
}
What can be done in my first program to make it work ?
Thank you
With recursion:
public static boolean follows(String s, String a, String b, String c) {
int ai = s.indexOf(a);
if (ai == -1) {
return true; // No more 'a' string, we're all good
}
int bi = s.indexOf(a + b);
int ci = s.indexOf(a + b + c);
if (bi != ai || ci != ai) {
return false; // Strings 'b' and 'bc' don't follow 'a', so the check failed
}
return follows(s.substring(ai + a.length()), a, b, c);
}
In reality, bi could be removed.
The problem you have is that you are not actually entering the nested if statements due to a minor flaw in your logic.
I would change it to this which checks whether i + 1 is equal to String b || i + 2 is equal to String c
public static boolean follows2(String s, String a, String b, String c) {
boolean res = true;
for (int i = 0; i < s.length(); i++) {
if (charAtPos(s, i).equals(a)) {
if (!(charAtPos(s, i + 1).equals(b)) || !(charAtPos(s, i + 2).equals(c))) {
res = false;
}
}
}
return res;
}
Because the code doesn't do what you think it does.
if you'll add some prints to the code, you'll see you never set "res" to false.
Let's debug the case you're testing:
When meet the the first letter - "i" - it entered the first if.
the next letter is "p" so you're not entered the 2nd if, so you'll continue to the next letter in the "for".
Here's my attempt (haven't tested it)
boolean hasOnlyCompleteSequences(String source, char.. chars) {
for (int s = 0; s < source.length(); s++) {
int c = 0;
if (source.charAt(s) == chars[c]) {
if (!isCompleteSequence(source, s + 1, chars, c + 1)) {
return false;
}
}
}
return true;
}
boolean isCompleteSequence(String source, int s, char[] chars, int c) {
while (s < source.length() && c < chars.length) {
// note: the indices get increased AFTER comparison
if (source.charAt(s++) != chars[c++]) {
return false;
}
}
// cover the case that the source String ends with an incomplete sequence
if (s == source.length() && c < chars.length) {
return false;
}
return true;
}
This is a much cleaner answer (tested & working great):
public static boolean follows(String s, String...strings) {
int number = 0;
for(int i = 0; i<s.length(); i++){
if(strings[number].length()+i<s.length() && s.substring(i, strings[number].length()+i).equals(strings[number]) && number+1 != strings.length) number++;
else if(number!=0 && !s.substring(i, strings[number].length()+i).equals(strings[number])) return false;
else number = 0;
}
return true;
}
It fixes many problems with your code:
Working with strings but using "charAt"
Copying the function just to add a parameter

Separating compound and simple words

I know this problem is probably best served with DP, but I was wondering if it was possible to do it with recursion as a brute force way.
Given a set of words, say {"sales", "person", "salesperson"}, determine which words are compound (that is, it is the combination of 2 or more words in the list). So in this case, salesperson = sales + person, and is compound.
I based my answer heavily off of this problem: http://www.geeksforgeeks.org/dynamic-programming-set-32-word-break-problem/
public static void main(String args[]) throws Exception {
String[] test = { "salesperson", "sales", "person" };
String[] output = simpleWords(test);
for (int i = 0; i < output.length; i++)
System.out.println(output[i]);
}
static String[] simpleWords(String[] words) {
if (words == null || words.length == 0)
return null;
ArrayList<String> simpleWords = new ArrayList<String>();
for (int i = 0; i < words.length; i++) {
String word = words[i];
Boolean isCompoundWord = breakWords(words, word);
if (!isCompoundWord)
simpleWords.add(word);
}
String[] retVal = new String[simpleWords.size()];
for (int i = 0; i < simpleWords.size(); i++)
retVal[i] = simpleWords.get(i);
return retVal;
}
static boolean breakWords(String[] words, String word) {
int size = word.length();
if (size == 0 ) return true;
for (int j = 1; j <= size; j++) {
if (compareWords(words, word.substring(0, j)) && breakWords(words, word.substring(j, word.length()))) {
return true;
}
}
return false;
}
static boolean compareWords(String[] words, String word) {
for (int i = 0; i < words.length; i++) {
if (words[i].equals(word))
return true;
}
return false;
}
The problem here is now that while it successfully identifies salesperson as a compound word, it will also identify sales and person as a compound word. Can this code be revised so that this recursive solution works? I'm having trouble coming up with how I can easily do this.
Here is a solution with recursivity
public static String[] simpleWords(String[] data) {
List<String> list = new ArrayList<>();
for (String word : data) {
if (!isCompound(data, word)) {
list.add(word);
}
}
return list.toArray(new String[list.size()]);
}
public static boolean isCompound(String[] data, String word) {
return isCompound(data, word, 0);
}
public static boolean isCompound(String[] data, String word, int iteration) {
if (data == null || word == null || word.trim().isEmpty()) {
return false;
}
for (String str : data) {
if (str.equals(word) && iteration > 0) {
return true;
}
if (word.startsWith(str)) {
String subword = word.substring(str.length());
if (isCompound(data, subword, iteration + 1)) {
return true;
}
}
}
return false;
}
Just call it like this:
String[] data = {"sales", "person", "salesperson"};
System.out.println(Arrays.asList(simpleWords(data)));

remove duplicate characters from a string

import java.util.Scanner;
public class StringWithoutDuplicate {
public static void stringWithoutDuplicate(String s1)
{
int n = s1.length();
int i = 0;
while(i<n)
{
if(s1.charAt(i) == s1.charAt(i+1))
{
if(s1.charAt(i) == s1.charAt(n-1))
{
System.out.println(s1.charAt(i));
}
i++;
}
else if(s1.charAt(i) != s1.charAt(i+1))
{
if(s1.charAt(i) == s1.charAt(n-1))
{
System.out.println(s1.charAt(i));
}
System.out.println(s1.charAt(i));;
i++;
}
}
}
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
s.useDelimiter(",");
String s1 = s.next();
System.out.println(s1);
stringWithoutDuplicate(s1);
}
}
The code is giving the output but with an exception
please tell me the error in my code and ways to correct it.
I don't want to change the logic of my code so kindly solve it using this logic only.
ERROR:
Range of your i is from 0 to (n-1) which is same as the range of index of characters in your string s1. This is correct.
But during the last iteration of your while loop, i = n-1
At this point, s1.charAt(i+1) becomes same as s1.charAt(n). This should be giving an error.
public static void stringWithoutDuplicate(String s1) {
int prev = -1;
for (int i = 0, size = s1.length(); i < size; ++i) {
char c = s1.charAt(i);
if (c != prev) {
System.out.println(c);
prev = c;
}
}
}

Categories

Resources