String Fragment Combinations Puzzle - java

Let's say I am given a list of String fragments. Two fragments can be concatenated on their overlapping substrings.
e.g.
"sad" and "den" = "saden"
"fat" and "cat" = cannot be combined.
Sample input:
aw was poq qo
Sample output:
awas poqo
So, what's the best way to write a method which find the longest string that can be made by combining the strings in a list. If the string is infinite the output should be "infinite".
public class StringUtil {
public static String combine(List<String> fragments) {
StringBuilder combined = new StringBuilder();
for (int i = 0; i < fragments.size(); i++) {
char last = (char) (fragments.get(i).length() - 1);
if (Character.toString(last).equals(fragments.get(i).substring(0))) {
combined.append(fragments.get(i)).append(fragments.get(i+1));
}
}
return combined.toString();
}
}
Here's my JUnit test:
public class StringUtilTest {
#Test
public void combine() {
List<String> fragments = new ArrayList<String>();
fragments.add("aw");
fragments.add("was");
fragments.add("poq");
fragments.add("qo");
String result = StringUtil.combine(fragments);
assertEquals("awas poqo", result);
}
}
This code doesn't seem to be working on my end... It returning an empty string:
org.junit.ComparisonFailure: expected:<[awas poqo]> but was:<[]>
How can I get this to work? And also how can I get it to check for infinite strings?

I don't understand how fragments.get(i).length() - 1 is supposed to be a char. You clearly casted it on purpose, but I can't for the life of me tell what that purpose is. A string of length < 63 will be converted to an ASCII (Unicode?) character that isn't a letter.
I'm thinking you meant to compare the last character in one fragment to the first character in another, but I don't think that's what that code is doing.
My helpful answer is to undo some of the method chaining (function().otherFunction()), store the results in temporary variables, and step through it with a debugger. Break the problem down into small steps that you understand and verify the code is doing what you think it SHOULD be doing at each step. Once it works, then go back to chaining.
Edit: ok I'm bored and I like teaching. This smells like homework so I won't give you any code.
1) method chaining is just convenience. You could (and should) do:
String tempString = fragments.get(i);
int lengthOfString = tempString.length() - 1;
char lastChar = (char) lengthOfString;//WRONG
Etc.
This lets you SEE the intermediate steps, and THINK about what you are doing. You are literally taking the length of a string, say 3, and converting that Integer to a Char. You really want the last character in the string. When you don't use method chaining, you are forced to declare a Type of intermediate variable, which of course forces you to think about what the method ACTUALLY RETURNS. And this is why I told you to forgo method chaining until you are familiar with the functions.
2) I'm guessing at the point you wrote the function, the compiler complained that it couldn't implicitly cast to char from int. You then explicitly cast to a char to get it to shut up and compile. And now you are trying to figure out why it's failing at run time. The lesson is to listen to the compiler while you are learning. If it's complaining, you're messing something up.
3) I knew there was something else. Debugging. If you want to code, you'll need to learn how to do this. Most IDE's will give you an option to set a break point. Learn how to use this feature and "step through" your code line by line. THINK about exactly what step you are doing. Write down the algorithm for a short two letter pair, and execute it by hand on paper, one step at a time. Then look at what the code DOES, step by step, until you see somewhere it does something that you don't think is right. Finally, fix the section that isn't giving you the desired result.

Looking at your unit test, the answer seems to be quite simple.
public static String combine(List<String> fragments) {
StringBuilder combined = new StringBuilder();
for (String fragment : fragments) {
if (combined.length() == 0) {
combined.append(fragment);
} else if (combined.charAt(combined.length() - 1) == fragment.charAt(0)) {
combined.append(fragment.substring(1));
} else {
combined.append(" " + fragment);
}
}
return combined.toString();
}
But seeing at your inqusition example, you might be looking for something like this,
public static String combine(List<String> fragments) {
StringBuilder combined = new StringBuilder();
for (String fragment : fragments) {
if (combined.length() == 0) {
combined.append(fragment);
} else if (combined.charAt(combined.length() - 1) == fragment.charAt(0)) {
int i = 1;
while (i < fragment.length() && i < combined.length() && combined.charAt(combined.length() - i - 1) == fragment.charAt(i))
i++;
combined.append(fragment.substring(i));
} else {
combined.append(" " + fragment);
}
}
return combined.toString();
}
But note that for your test, it will generate aws poq which seems to be logical.

Related

How can I fix my code to find a certain character in an array and make changes to that array

while (scan_file.hasNext()) {
String b = scan_file.nextLine();
// checks if string b contains the tag <h>
if (b.contains("<h>")) {
char arrayString[] = b.toCharArray();
for (int i = 0; i < arrayString.length; i++) {
if (arrayString[i] == '<') {
arrayString[i] = arrayString[i + 2];
}
System.out.print(arrayString[i]);
}
}
}
What I was expecting the program to do was(for now) iterate through the while loop and store each line as string 'b'.
I want to check if that string b contains a certain string like <h> for this example. And I want to convert string b into an array if it contains said string like <h> and iterate through that array to check for '<' and move the array up 2 spaces.
For example, string b had <h>hello, I wanted to eventually print hello because the program would have moved up 2 elements.
I feel like I got the loops and general idea on how I want to tackle the problem.. but when I ran the program, nothing printed so I don't know if I did the loops and if statements correctly.
I really don't know how to word my problem well, so bear with me and I'm sorry in advance.
All feedbacks are greatly appreciated (:
System.out.print(arrayString[i]); just print the ith character of arrayString, it's definitely not what you want.
In fact you don't have to convert a String to char[], String has many utils method can help you with your goal.
I won't give you full code , but I can give you some tips.
You can use String.indexof('<') to find the index of '<'.
You can use String.subString(startIndex) to get the subString start with the specified index.
Suppose your code scan_file.hasNext() and scan_file.nextLine() is work well. You can try code below to remove all from current line:
if (b != null && b.contains("<h>")) {
System.out.println(b.replaceAll("<h>", ""));
}

recursion moving char to the end of the string

i need to get a string and rearrange it with recursion by getting char and by that char i have to move that char everywhere on the string to the end
like "Hello world!" ,'l' => "Heo word!lll"
i have problems understading the recursion way of thinking
so i started with this:
public static String ChToLast (String str, char ch){
if(str.indexOf(ch)== -1){
return str;
}else{
if(str.indexOf(0) == ch){
return str;
}
}
thank you for your help :)
Recursion is the practise of reusing your method inside itself. In this case, I will provide a solution to explain what happens:
public static String chrToLast(String str, char ch) {
//This if statement details the end condition
if(str.length() < 1) {
return "";
}
String newString = str.substring(1); //Create new string without first character
if(str.indexOf(ch) == 0) { //This happens when your character is found
return chrToLast(newString, ch) + ch;
} else { //This happens with all other characters
return str.charAt(0) + chrToLast(newString, ch);
}
}
If you execute:
chrToLast("Hello, World!", 'l')
This will result in the desired result: Heo, Word!lll
Process
In general, this method works by checking which character is currently the first in the given string, and then deciding what to do. If the first character is the same as the one your looking for (l), it will then remove that character from the string and use chrToLast on that new string. But, it also adds the character it found to the end of the result by using + ch. It continues to do this until there are no more characters left, which is what the end condition is for.
The end condition
The end condition returns an empty string "" because that is what is called the base case of the algorithm. You can think of a recursive algorithm as something solving a problem by calling itself a number of times. By calling themselves, recursive algorithms move towards a base. In this particular case, it does that by subtracting one character off the string each time the method is executed. Once there are no characters left, it reaches the base case which is "", where the string is finally empty and no characters can be subtracted anymore. (Hence it returns nothing as it's final state)
I hope this answers your question. It's important to understand this concept, as it is very powerful. Try to study the code and comment if something's not clear.
Something that can also help is by executing this code in an IDE and using the debugger to walk through its execution. You can then see for yourself what the flow of the program is, and see the value of the variables in play.
If you use recursion, it will be pretty expensive call for the result you are expecting. Lot of movement of String or charArray elements, eitherway you do. I don't see its a wiser choice. I would do it this way, it will be of space complexity O(2n) & performance complexity O(n).
public class Solve {
public static void main(String[] args) {
System.out.println(ChToLast("Hello world!", 'l'));
}
public static String ChToLast(String str, char ch) {
char[] chars = str.toCharArray();
char[] modChars = new char[chars.length];
int i = 0;
for(char element : chars){
if(ch != element){
modChars[i++] = element;
}
}
Arrays.fill(modChars, i, chars.length , ch);
return new String(modChars);
}
}
If you use while loop and write a method to check if that string means perfect statement then that may work for you
Here you would need some help of NLP concept to check everytime if arranged chars are making any statement or are grammatically correct.
This will help

Splitting string algorithm in Java

I'm trying to make the following algorithm work. What I want to do is split the given string into substrings consisting of either a series of numbers or an operator.
So for this string = "22+2", I would get an array in which [0]="22" [1]="+" and [2]="2".
This is what I have so far, but I get an index out of bounds exception:
public static void main(String[] args) {
String string = "114+034556-2";
int k,a,j;
k=0;a=0;j=0;
String[] subStrings= new String[string.length()];
while(k<string.length()){
a=k;
while(((int)string.charAt(k))<=57&&((int)string.charAt(k))>=48){
k++;}
subStrings[j]=String.valueOf(string.subSequence(a,k-1)); //exception here
j++;
subStrings[j]=String.valueOf(string.charAt(k));
j++;
}}
I would rather be told what's wrong with my reasoning than be offered an alternative, but of course I will appreciate any kind of help.
I'm deliberately not answering this question directly, because it looks like you're trying to figure out a solution yourself. I'm also assuming that you're purposefully not using the split or the indexOf functions, which would make this pretty trivial.
A few things I've noticed:
If your input string is long, you'd probably be better off working with a char array and stringbuilder, so you can avoid memory problems arising from immutable strings
Have you tried catching the exception, or printing out what the value of k is that causes your index out of bounds problem?
Have you thought through what happens when your string terminates? For instance, have you run this through a debugger when the input string is "454" or something similarly trivial?
You could use a regular expression to split the numbers from the operators using lookahead and lookbehind assertions
String equation = "22+2";
String[] tmp = equation.split("(?=[+\\-/])|(?<=[+\\-/])");
System.out.println(Arrays.toString(tmp));
If you're interested in the general problem of parsing, then I'd recommend thinking about it on a character-by-character level, and moving through a finite state machine with each new character. (Often you'll need a terminator character that cannot occur in the input--such as the \0 in C strings--but we can get around that.).
In this case, you might have the following states:
initial state
just parsed a number.
just parsed an operator.
The characters determine the transitions from state to state:
You start in state 1.
Numbers transition into state 2.
Operators transition into state 3.
The current state can be tracked with something like an enum, changing the state after each character is consumed.
With that setup, then you just need to loop over the input string and switch on the current state.
// this is pseudocode -- does not compile.
List<String> parse(String inputString) {
State state = INIT_STATE;
String curr = "";
List<String> subStrs = new ArrayList<String>();
for(Char c : inputString) {
State next;
if (isAnumber(c)) {
next = JUST_NUM;
} else {
next = JUST_OP;
}
if (state == next) {
// no state change, just add to accumulator:
acc = acc + c;
} else {
// state change, so save and reset the accumulator:
subStrs.add(acc);
acc = "";
}
// update the state
state = next;
}
return subStrs;
}
With a structure like that, you can more easily add new features / constructs by adding new states and updating the behavior depending on the current state and incoming character. For example, you could add a check to throw errors if letters appear in the string (and include offset locations, if you wanted to track that).
If your critera is simply "Anything that is not a number", then you can use some simple regex stuff if you dont mind working with parallel arrays -
String[] operands = string.split("\\D");\\split around anything that is NOT a number
char[] operators = string.replaceAll("\\d", "").toCharArray();\\replace all numbers with "" and turn into char array.
String input="22+2-3*212/21+23";
String number="";
String op="";
List<String> numbers=new ArrayList<String>();
List<String> operators=new ArrayList<String>();
for(int i=0;i<input.length();i++){
char c=input.charAt(i);
if(i==input.length()-1){
number+=String.valueOf(c);
numbers.add(number);
}else if(Character.isDigit(c)){
number+=String.valueOf(c);
}else{
if(c=='+' || c=='-' || c=='*' ||c=='/'){
op=String.valueOf(c);
operators.add(op);
numbers.add(number);
op="";
number="";
}
}
}
for(String x:numbers){
System.out.println("number="+x+",");
}
for(String x:operators){
System.out.println("operators="+x+",");
}
this will be the output
number=22,number=2,number=3,number=212,number=21,number=23,operator=+,operator=-,operator=*,operator=/,operator=+,

Check abecedarian in recursive way (Not a homework, part of my learning)

I have created this function to check abecedarian with while loop (A word is said to be "abecedarian" if the letters in the word appear in alphabetical order, such as "abdest")-
public static boolean isAbecedarian(String s) {
int index = 0;
char c = 'a';
while (index < s.length()) {
if (c > s.charAt(index)) {
return false;
}
c = s.charAt(index);
index = index + 1;
}
return true;
}
I want to change this function to a recursive function and I have written this function -
public static boolean isAbecedarianrec(String s){
char first = s.charAt(0);
char second = first ++;
if (first<second){
return isAbecedarianrec(s);
}
return false;
}
recursive function is not working as it should and I am not getting the expected result. Please check and help me to pin point the issue with this function.
Note - As I mentioned this is not a homework question and it is part of my self Java learning.
Two issues:
The following code char second = first++ should be char second = s.charAt(1);
The recursive call should be return isAbecedarianrec(s.substring(1));
Finally, you need length checks where appropriate. On method entry, ensure the string has at least 2 characters if not, return true.
When using recursion, you need to keep two things in mind. First, the input to the recursive should in some way be different than the previous input. Second, there must be a valid stopping point so that you don't recurse infinitely and thereby run out of memory.
Typically with recursion you need two things:
A base case (e.g. empty string, zero, etc.)
A way to check part of the more complex case, and then reduce it to a simpler recursive call.
The empty string does form a good base case here - it's trivially abecedarian. So the first part of your recursive method should be to check for the empty string and return true. This forms the base case that will be the termination of your recursive method in the "happy path" case.
Otherwise, you know you have a non-empty string. The recursive decomposition can be achieved by checking its first character, then recursively calling with the rest of the string. However, in order to perform the check, you'll need to remember what the previous character of the string was (just like c in the iterative method), so you'll need an additional argument to the recursive call to act as a sort of variable.
This is not uncommon with recursion - often the majority of the work is done in a "helper" method, and the public method just calls this with initial/dummy values.
Putting these together then, a solution would look something like the following:
// s must not be null
public boolean isAbecedarianrec(String s) {
return isAbecedarianRecImpl(s, (char)0);
}
private boolean isAbecedarianRecImpl(String s, char c) {
if (s.isEmpty())
return true;
else {
if (c > s.charAt(0))
return false;
else
return isAbecedarianRecImpl(s.substring(1), s.charAt(0));
}
}
Java does not have pointer arithmetics (it seems you are trying to do something like that). You code will take the first char (always the first char of the String), and afterwards it will increment the char (turning 'a' into 'b' etc) and furthermore store the value to second also. This means that first and second will always contain the same value.
A simple (but not very efficient solution could be:
public static boolean isAbecedarianrec(String s, char c){
if (s.equals("")) return true;
char first = s.charAt(0);
if (first>=c){
return isAbecedarianrec(s.subString(1), first);
}
return false;
}
(Notice that I have also flipped the equality. That seemed to be wrong).
Call the function with the value of the lowest character. E.g.: isAbecedarianrec(s, 'a').
Notice that this solution (like yours) requires that the code points of the letters have the same numerical order as the alphabetical order of the letters. That is not generally correct, for example you will see strange results if the string contains both capital and small letters.
To create a recursive function, you need two things: an end case that stops execution, and some way to modify the successive calls to the recursive function.
In your case, you have one end case covered (the case where the string is not abecedarian), but not the other. For your function to ever return true, it needs to contain a return true statement or a return statement with a boolean comparison in it. The condition in this case would probably be finding the end of the string (being called with an empty string).
You are also missing a modification of successive calls: every call to isAbecedarian is made with the same string. Depending on what works best in Java, you could either shorten the string by 1 character on every call, or pass the index as an argument to the function and increment it on each call.

Is there an existing library method that checks if a String is all upper case or lower case in Java?

I know there are plenty of upper() methods in Java and other frameworks like Apache commons lang, which convert a String to all upper case.
Are there any common libraries that provide a method like isUpper(String s) and isLower(String s), to check if all the characters in the String are upper or lower case?
EDIT:
Many good answers about converting to Upper and comparing to this. I guess I should have been a bit more specific, and said that I already had thought of that, but I was hoping to be able to use an existing method for this.
Good comment about possible inclusion of this in apache.commons.lang.StringUtils.
Someone has even submitted a patch (20090310). Hopefully we will see this soon.
https://issues.apache.org/jira/browse/LANG-471
EDIT:
What I needed this method for, was to capitalize names of hotels that sometimes came in all uppercase. I only wanted to capitalize them if they were all lower or upper case.
I did run in to the problems with non letter chars mentioned in some of the posts, and ended up doing something like this:
private static boolean isAllUpper(String s) {
for(char c : s.toCharArray()) {
if(Character.isLetter(c) && Character.isLowerCase(c)) {
return false;
}
}
return true;
}
This discussion and differing solutions (with different problems), clearly shows that there is a need for a good solid isAllUpper(String s) method in commons.lang
Until then I guess that the myString.toUpperCase().equals(myString) is the best way to go.
Now in StringUtils isAllUpperCase
This if condition can get the expected result:
String input = "ANYINPUT";
if(input.equals(input.toUpperCase())
{
// input is all upper case
}
else if (input.equals(input.toLowerCase())
{
// input is all lower case
}
else
{
// input is mixed case
}
Not a library function unfortunately, but it's fairly easy to roll your own. If efficiency is a concern, this might be faster than s.toUpperCase().equals(s) because it can bail out early.
public static boolean isUpperCase(String s)
{
for (int i=0; i<s.length(); i++)
{
if (!Character.isUpperCase(s.charAt(i)))
{
return false;
}
}
return true;
}
Edit: As other posters and commenters have noted, we need to consider the behaviour when the string contains non-letter characters: should isUpperCase("HELLO1") return true or false? The function above will return false because '1' is not an upper case character, but this is possibly not the behaviour you want. An alternative definition which would return true in this case would be:
public static boolean isUpperCase2(String s)
{
for (int i=0; i<s.length(); i++)
{
if (Character.isLowerCase(s.charAt(i)))
{
return false;
}
}
return true;
}
Not that i know.
You can copy the string and convert the copy to lower/upper case and compare to the original one.
Or create a loop which checks the single characters if the are lower or upper case.
This method might be faster than comparing a String to its upper-case version as it requires only 1 pass:
public static boolean isUpper(String s)
{
for(char c : s.toCharArray())
{
if(! Character.isUpperCase(c))
return false;
}
return true;
}
Please note that there might be some localization issues with different character sets. I don't have any first hand experience but I think there are some languages (like Turkish) where different lower case letters can map to the same upper case letter.
Guava's CharMatchers tend to offer very expressive and efficient solutions to this kind of problem.
CharMatcher.javaUpperCase().matchesAllOf("AAA"); // true
CharMatcher.javaUpperCase().matchesAllOf("A SENTENCE"); // false
CharMatcher.javaUpperCase().or(CharMatcher.whitespace()).matchesAllOf("A SENTENCE"); // true
CharMatcher.javaUpperCase().or(CharMatcher.javaLetter().negate()).matchesAllOf("A SENTENCE"); // true
CharMatcher.javaLowerCase().matchesNoneOf("A SENTENCE"); // true
A static import for com.google.common.base.CharMatcher.* can help make these more succinct.
javaLowerCase().matchesNoneOf("A SENTENCE"); // true
Try this, may help.
import java.util.regex.Pattern;
private static final String regex ="^[A-Z0-9]"; //alpha-numeric uppercase
public static boolean isUpperCase(String str){
return Pattern.compile(regex).matcher(str).find();
}
with this code, we just change the regex.
I realise that this question is quite old, but the accepted answer uses a deprecated API, and there's a question about how to do it using ICU4J. This is how I did it:
s.chars().filter(UCharacter::isLetter).allMatch(UCharacter::isUpperCase)
If you expect your input string to be short, you could go with myString.toUpperCase().equals(myString) as you suggested. It's short and expressive.
But you can also use streams:
boolean allUpper = myString.chars().noneMatch(Character::isLowerCase);
You can use java.lang.Character.isUpperCase()
Then you can easily write a method that check if your string is uppercase (with a simple loop).
Sending the message toUpperCase() to your string and then checking if the result is equal to your string will be probably slower.
Here's a solution I came up with that's a bit universal as it doesn't require any libraries or special imports, should work with any version of Java, requires only a single pass, and should be much faster than any regex based solutions:
public static final boolean isUnicaseString(String input) {
char[] carr = input.toCharArray();
// Get the index of the first letter
int i = 0;
for (; i < carr.length; i++) {
if (Character.isLetter(carr[i])) {
break;
}
}
// If we went all the way to the end above, then return true; no case at all is technically unicase
if (i == carr.length) {
return true;
}
// Determine if first letter is uppercase
boolean firstUpper = Character.isUpperCase(carr[i]);
for (; i < carr.length; i++) {
// Check each remaining letter, stopping when the case doesn't match the first
if (Character.isLetter(carr[i]) && Character.isUpperCase(carr[i]) != firstUpper) {
return false;
}
}
// If we didn't stop above, then it's unicase
return true;
}

Categories

Resources