Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I looked around a bit for a solution to parsing out a chemical formula that contained molecular components that may have their own suffixes for the purposes of being able to parse a formula for its complete atomic fraction.
How would one do this in Java?
Not having been able to find a way to do this in short order (and not having done a fun algorithm in a while) I settled on a stack implementation, as it's actually less complicated than a math operation stack.
Going backward through the stack, you only have to be aware of a few things, as this is fundamentally a modified implementation of a common solution to parsing a mathematical statement.
1) Your integer suffix can be built of multiple characters
2) Your integer suffix could be a multiplier (next character being a ")")
3) You need to handle for implicit "1"s
The implementation pops characters off one stack and pushes only letters and numbers onto your "return stack".
String expandFormula(String s){
Stack<Character> stack = new Stack();
Stack<Character> hanoi = new Stack();
char[] ca = s.toCharArray();
Character c;
List<Integer> multipliers = new ArrayList();
String multiBuff;
int val;
boolean flag;
for (int i = 0; i < ca.length; i++)
stack.push(ca[i]);
while(!stack.isEmpty()){
c = stack.pop();
if (Character.isLetter(c)){
try{
//previous parse was end of Symbol, implicit "1"
flag = Character.isUpperCase(hanoi.peek());
}
catch(EmptyStackException ese){ //change exception
flag = false;
}
//push implicit 1
if (flag){
stack.push(c);
stack.push('1');
}
//continue as usual
else
hanoi.push(c);
}
//begin number parsing
else if(Character.isDigit(c)){
flag = false;
multiBuff = c +"";
//parse the integer out
while(Character.isDigit(stack.peek())){
c = stack.pop();
multiBuff = c + multiBuff;
}
//if next char is ), then value is a suffix
if (stack.peek() == ')'){
flag = true;
stack.pop();
multipliers.add(Integer.parseInt(multiBuff));
//pop successive )s
while(stack.peek() == ')'){
stack.pop();
multipliers.add(1);
}
}
if(Character.isLetter(stack.peek())){
val = flag ? 0 : Integer.parseInt(multiBuff);
//get full value of
for(Integer i : multipliers){
if (val == 0)
val = i;
else
val *= i;
}
//trim and push first decibit
while(val > 0){
hanoi.push(Character.forDigit(val % 10, 10));
val /= 10;
}
}
}
//end of nest, remove most recent multiplier
else if(c == '(')
try{
multipliers.remove(multipliers.size()-1);
}
catch(ArrayIndexOutOfBoundsException aioobe){
}
}
multiBuff = "";
while(!hanoi.isEmpty())
multiBuff += hanoi.pop();
return multibuff;
}
This solution can be converted directly to your output string by:
1) Change "hanoi" to string
2) Change "hanoi.push(c)" to hanoi = c + hanoi
3) Change "hanoi.peek()" to "hanoi.charAt(0)"
4) Change Exceptions as necessary (or use general exceptions anyway)
5) Just return hanoi instead of the multibuff thing at the bottom.
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 months ago.
Improve this question
can someone help me with string validation? I tried to find the solution, but none was satisfied.
I have the uri e.g. /dog/cat/house,1/mouse/bird,1/rabbit.
I need to check if after word (with comma) bird, there is a number or not. In my case sometimes i receive uri with number: "bird,1" and sometimes with word: "bird,foo".
Thank you for any suggestions.
As #Federico klez Culloca and #The fourth bird suggested you could use a regular expression (\\bbird,(?:[1-9]|1[0-9]|20)\\b) but some security scans don't like regular expressions. In any case, one another (pure Java) solution would be:
Updated the answer after user added more conditions.
would look for range 1, 2 .. 20 (01, 02 would return false).
public static boolean isNumber() {
// you can parametrize these 2
String input = "/dog/cat/house,1/mouse/bird,10/rabbit.";
String strOfInterest = "/bird,";
boolean isStringEndingInLT20 = false;
int indxOfInterest = input.indexOf("/bird,") + strOfInterest.length();
char c1 = input.charAt(indxOfInterest);
char c2 = input.charAt(indxOfInterest + 1);
int i1 = Character.getNumericValue(input.charAt(indxOfInterest));
if (Character.isDigit(c1) && Character.isDigit(c2)) {
int num = Integer.parseInt("" + c1 + c2);
if ((i1 > 0) && (num >= 1) && (i1 <= 20)) isStringEndingInLT20 = true;
} else if (Character.isDigit(c1)) {
if ((i1 >= 1) && (i1 <= 9)) isStringEndingInLT20 = true;
}
return isStringEndingInLT20;
}
NOTE: I personally hate these verbose solutions and would prefer 1 line REGEX. Try to avoid it and use regex. The only times I avoid regex is when it becomes performance bottleneck and/or causes a security concern.
This is a practical algorithm, you can specify the keyword!
The premise is that the validity of the contains parameter is in line with your description.
keyword, (spaces are allowed)123/
public static void main(String[] args) throws IOException {
String contains = "/dog/cat/house,1/mouse/bird,a/rabbit";
FreeTest f = new FreeTest();
boolean has = f.hasNumber(contains, "bird");
System.out.println(has);
}
/**
* Check if string contains number after specific word
*
* #param contains string contains
* #param key the specific word (without comma)
* #return yes or not
*/
public boolean hasNumber(String contains, String key) {
int commaIndex = contains.indexOf(',', contains.indexOf(key));
int startIndex = commaIndex + 1;
boolean hasNumber = true;
while (true) {
char c = contains.charAt(startIndex++);
if (c == '/') break; // exit
if (c != ' ') {
hasNumber = Character.isDigit(c);
}
}
return hasNumber;
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
There's another Stack Overflow post that was created for an algorithm related to vehicle registration numbers...
According to the entered license plate (eg. ABC123) and a list of
replacement values (eg 1 replaced by I). I need to get all possibles
combinations.
The answer by #ArturoMenchaca is perfect for C#, but I'd like it in Java, but given that 'yield' is not available I really can't wrap my head around how to convert it.
How would you translate this code to Java?
public static IEnumerable<string> Combinations(string s, Dictionary<char, char> replacements)
{
return Combinations(s, replacements, 0, string.Empty);
}
private static IEnumerable<string> Combinations(string original, Dictionary<char, char> replacements, int index, string current)
{
if (index == original.Length) yield return current;
else
{
foreach (var item in Combinations(original, replacements, index + 1, current + original[index]))
yield return item;
if (replacements.ContainsKey(original[index]))
foreach (var item in Combinations(original, replacements, index + 1, current + replacements[original[index]]))
yield return item;
}
}
You would call then call the method like this..
Dictionary<char, char> dict = new Dictionary<char,char>();
dict['1'] = 'I';
dict['3'] = 'B';
dict['A'] = 'H';
dict['O'] = '0';
dict['0'] = 'O';
var combs = Combinations("ABC123", dict);
Java doesn't have a feature for iterating values using "push" logic, like the C# yield return does.
Java only supports "pull" logic, using Enumeration, Iterator, or Spliterator (what Stream uses).
If you have the memory for it, you could of course "push" all the combinations into an ArrayList, then "pull" values from there. Converting the yield return logic into list.add() calls is easy, so I'll assume you don't want that.
The Java equivalent of IEnumerable is Iterable, so you need an Iterator implementation.
The code below will do that. It is based on my answer to another question, so please read that answer for an explanation of the overall logic, but basically, your example would be like generating combinations of characters in this jagged array:
{{'A', 'H'}, {'B'}, {'C'}, {'1', 'I'}, {'2'}, {'3', 'B'}}
In the code below, that jagged array is the textChars array, but instead of using char[] it uses a String, because a String is really just a read-only char[].
public static Iterable<String> combinations(String text, String... replacements) {
Map<Character, String> repl = new HashMap<>();
for (String r : replacements)
if (repl.putIfAbsent(r.charAt(0), r) != null)
throw new IllegalArgumentException("Duplicate replacement: [" + repl.get(r.charAt(0)) + "] vs [" + r + "]");
String[] textChars = new String[text.length()];
long count = 1;
for (int i = 0; i < textChars.length; i++) {
textChars[i] = repl.getOrDefault(text.charAt(i), text.substring(i, i+1));
count = Math.multiplyExact(count, textChars[i].length());
}
long comboCount = count;
return () -> new Iterator<>() {
private long combo = 0;
#Override
public boolean hasNext() {
return (this.combo < comboCount);
}
#Override
public String next() {
if (this.combo >= comboCount)
throw new NoSuchElementException();
long c = this.combo++;
char[] buf = new char[textChars.length];
for (int i = buf.length - 1; i >= 0; i--) {
buf[i] = textChars[i].charAt((int) (c % textChars[i].length()));
c /= textChars[i].length();
}
return new String(buf);
}
};
}
Test
combinations("ABC123", "1I", "3B", "AH", "O0", "0O").forEach(System.out::println);
Output
ABC123
ABC12B
ABCI23
ABCI2B
HBC123
HBC12B
HBCI23
HBCI2B
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
How do I write a method that will reverse the letters of each word in a string while leaving all instances of ‘Q’ or ‘q’ in place (stay at the current index). Each word is separated by whitespace(‘ ‘).
Examples:
Hello Worldq > olleH dlroWq
Hiq BQb -> iHq bQB
kjnoqKl -> lKonqjk
jkQuq -> ukQjq
public String reverseWords(String s) {
String[] sub = s.trim.split(“q + ”);
String result = ””;
if (sub.length > 0) {
for (int i = sub.length - 1; i > 0; i--) {
result += sub[i] + ““;
}
}
return result;
}
Here is my solution. What I did first was parse the initial String so we can get individual words. From there, I replaced all the Q and q for that word with an empty string and then reversed it using StringBuilder. Well with StringBuilder you can also insert pretty easily, so I looped back through the word and added all the Q and q back to the orginial spot.
public static void main(String... array){
System.out.println(reverseWords("Hello Worldq"));
}
public static String reverseWords(String s) {
String[] words = s.split(" ");
StringBuilder output = new StringBuilder(words.length);
for (String word : words){ //Iterate through words
StringBuilder temp = new StringBuilder(word.replaceAll("[Qq]", "")).reverse(); //Replace Q's and reverse
for (int i =0; i<word.length(); i++){ //find Q's
char tempChar = s.charAt(i);
if (tempChar == 'Q'){ //If q found insert
temp.insert(i, "Q");
}
if (tempChar == 'q'){
temp.insert(i, "q");
}
}
output.append(temp); //Add to final output
output.append(" "); //Do not forget about space
}
return output.toString();
}
Hope this helps!
Edit:
Some after thoughts, you could potentially store the indexes of the Q's when iterating through the word initially when trying to replaceAll. That way you replaceAll and have the indexes of all the Q's with one iteration instead of 2.
I would do it in two step. First of all, construct a list, or array containing all letters that are not Q or q. Reverse the array.
Then you reconstruct the array by replacing all the non q letters with the reveresed array like this:
int reversedIndex = 0;
for(int i=0; i<s.length(); i++){
if (s.charAt(i) != 'q' && s.charAt(i) != 'Q') {
s[i] = reversedArray[reversedIndex];
reversedIndex++;
}
}
I leave you to make the code to program the reversedArray
Why not just implement a spare string/array with the q or Q included, reverse the string/array to the place -1 space for the q or Q, and if you come across one in your word/place in the array just do nothing be an if statement in your reverse method.Then put that in an string/array. Take the next part of the string/array and do the same until your original word is empty, return the final string/array, whatever you want to use, and done
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 9 years ago.
Improve this question
I have seen this and this question but mine is different. I want to write an efficient code for it in java. I came up with 2 solutions:
Approach 1.
find_first_reapeted(char[] input)
{
HashMap<Character,Integer> myhash = new HashMap<Character,Integer> ();
for(int i=0;i<input.length;i++)
{
if(myhash.containsKey(input[i])
myhash.put(input[i],2); //just put 2 even if it is more than 2
else
myhash.put(input[i],1);
}
for(int i=0;i<input.length;i++)
{
if(myhash.getValue(input[i])==1)
return input[i];
}
}
Approach 2.
find_first_reapeted(char[] input)
{
int[] allchars = new int[26];
for(int i=0;i<input.length;i++)
{
allchars[input[i]-'a'] += 1;
}
for(int i=0;i<input.length;i++)
{
if(allchars[input[i]-'a']==1)
return input[i];
}
}
First is there any better solution? (int term of time and space complexity)?
If not which one of the the above is better? I'm not sure about the space complexity of hashmap!
How about
The first repeating character.
char find_first_repeated(char[] input) {
BitSet bs = new BitSet();
for(char c : input) {
if(bs.get(c))
return c;
bs.set(c);
}
return '\uffff'; // invalid char
}
The first non repeating character, I would use the second approach but using the for-each loop to make it cleaner.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I want the following strings to be split by the (relative to the pairs of parentheses) outer-most operator (in this case: '+'):
1: "((20 + 20) + a)"
2: "(20 + ((20 + 20) + 20))
The results should be like this:
1: "((20 + 20) " and " a)"
2: "(20 " and " ((20 + 20) + 20))"
You can't do this with regex, but you can try something like this:
// locations of top-level operators:
List<Integer> locations = new ArrayList<Integer>();
int level = 0;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (c == '(') {
level++;
}
else if (c == ')') {
level--;
}
else if ("+-*/".indexOf(c) >= 0 && level == 1) {
locations.add(i);
}
}
You can then "split" your string with substring() and whatever is in locations.
If you always want to split on the outermost operator (e.g. split on + in (((a + 1)))), then things get a little more tricky, but your overall approach doesn't have to change drastically. One idea that comes to mind is to build a Map<OperatorData, Integer> (where OperatorData is a class containing the operator token (e.g. +) and an int representing how far it's nested) that maps to locations in the string. OperatorData can be Comparable based on the nest level.
OperatorData might look something like this:
class OperatorData implements Comparable<OperatorData> {
private String token;
private int level;
// constructor etc.
#Override
public int compareTo(OperatorData other) {
return Integer.compare(level, other.level);
}
}
You can then go through this map and split on the operators that have the lowest nest level. The approach might look something like this:
// location of top-level operators:
Map<OperatorData, Integer> operators = new HashMap<>();
int level = 0;
int i = 0;
while (i < str.length()) {
char c = str.charAt(i);
if (c == '(') {
level++;
} else if (c == ')') {
level--;
} else if (isOperatorChar(c)) {
final int index = i;
StringBuilder token = new StringBuilder();
token.append(c);
while (isOperatorChar(c = str.charAt(i + 1))) {
token.append(c);
i++;
}
operators.put(new OperatorData(token.toString(), level), index);
}
i++;
}
// find smallest OperatorData in map