Given two small String of different length and one full String. Check if the full String is merged from two small String.
Example1: Input - "beautiful", "bauful", "eti" Output - true
Example2: Input - "beautiful", "baufl", "eti" Output - false
That means the characters in small String 1 and small String 2 are in the same order as in full String.
Here is my code:
public class StringMerger {
public static boolean isMerge(String s, String part1, String part2) {
StringBuilder sb = new StringBuilder();
int minLength = Math.min(part1.length(), part2.length());
int maxLength = Math.max(part1.length(), part2.length());
for(int i = 0; i < minLength; i++){
sb.append(part1.charAt(i)).append(part2.charAt(i));
}
for(int i = minLength; i < maxLength; i++){
if(part1.length() >= part2.length()) sb.append(part1.charAt(i));
else sb.append(part2.charAt(i));
}
String temp = sb.toString();
return (temp.equalsIgnoreCase(s)) ? true : false;
}
}
But I have only solve with: Input - "beautiful", "batfl", "euiu" Output - true. This is only one of that' cases. So how to solve it?
Checkout the below solution, you are welcome to break it
Edit1 Fix bug: the bug is not due to the space, it is because when there is a character match in both small strings, the algorithm need to examine which character to take by checking both alternatives
Edit2 Reduce unnecessary depth first search to improve efficiency
public class StringMerger {
public static void main(String[] args) {
System.out.println(isMerge("beautiful", "bauful", "eti")); // true
System.out.println(isMerge("beautiful", "baufl", "eti")); // false
System.out.println(isMerge("bbbbb", "bbb", "bb")); // true
System.out.println(isMerge("xyzxyz", "xyz", "xyz")); // true
System.out.println(isMerge("xyzxyz", "xyz", "xyzd")); // false
System.out.println(isMerge("backstreetboy", "beetb", "ackstroy")); // true
System.out.println(isMerge("Can we merge it? Yes, we can!", "Cn w riYes n!", "aemege t? , weca")); //true
System.out.println(isMerge("beautifulxyzx", "baufulx", "etixyz")); // true
}
public static boolean isMerge(String s, String part1, String part2) {
if (s.length() != part1.length() + part2.length()) return false;
int part1Counter = 0;
int part2Counter = 0;
int fullStrLen = s.length();
int fullStrCounter = 0;
while (fullStrCounter < fullStrLen) {
boolean part1match = part1Counter < part1.length() && s.charAt(fullStrCounter) == part1.charAt(part1Counter);
boolean part2match = part2Counter < part2.length() && s.charAt(fullStrCounter) == part2.charAt(part2Counter);
if (part1match && part2match) { // if find a match in both substring, we need to find out whichever way works
boolean decision1 = isMerge(s.substring(fullStrCounter + 1), part1.substring(part1Counter + 1), part2.substring(part2Counter));
if (decision1) return decision1; // no need to check the second branch if the first branch matches
boolean decision2 = isMerge(s.substring(fullStrCounter + 1), part1.substring(part1Counter), part2.substring(part2Counter + 1));
return decision2;
}
if (part1match) {
++part1Counter;
++fullStrCounter;
} else if (part2match) {
++part2Counter;
++fullStrCounter;
} else {
return false;
}
}
return true;
}
}
Here's a shorter method. It makes use of Arrays.
private static boolean isMerge(String original, String one, String two){
String combinedStrings = one + two;
char[] mergedStrings = combinedStrings.toCharArray();
char[] originalString = original.toCharArray();
Arrays.sort(mergedStrings);
Arrays.sort(originalString);
return Arrays.equals(mergedStrings, originalString);
}
A possible brute-force starting algorithm, without giving you the solution for your homework:
Walk the word String looking for matches in each candidate String.
If there is no match (or both Strings are exhausted), then return False.
If there is a match, move the index for this candidate String.
If we exhaust the word String and all candidate Strings, return True.
I'm hand-waving past the edge conditions here, which would ideally be caught by tests.
It occurs to me that this class should be able to generate candidate Strings from any word String, meaning that you could even make the class symmetric.
Related
This question already has answers here:
Check string for palindrome
(42 answers)
Closed 1 year ago.
I am trying to write a method to check if a given word is a palindrome, but as of now it does not work. I suspect the error lies within the if-statement and the fact that you don't compare objects such as strings with == but instead with equals, is that right? However Java does not allow me to write: if (firstHalf.charAt(i).equals(secondHalf.charAt(j))), so what can I do to make it work? Are there other errors in the code?
public static boolean isPalindrome(String string) {
String firstHalf = string.substring(0, string.length() / 2);
String secondHalf = string.substring(string.length() / 2, string.length());
for (int i = 0; i <= firstHalf.length(); i++) {
for (int j = secondHalf.length(); j <= 0; j--) {
if (firstHalf.charAt(i) == secondHalf.charAt(j)) {
return true;
}
}
}
return false;
}
Why not do it this way?
public static boolean isPalindrome(String string){
StringBuilder sb = new StringBuilder(string);
sb.reverse();
return sb.toString().equals(string);
}
Your character test was backwards. All of the comparisons have to be equal for the String to be a palindrome.
Also, splitting the String is unnecessary. You can logically split the String with two indices.
Try this code.
public static boolean isPalindrome(String string) {
int frontIndex = 0;
int backIndex = string.length() - 1;
while (frontIndex < backIndex) {
if (string.charAt(frontIndex++) != string.charAt(backIndex--)) {
return false;
}
}
return true;
}
you can make each character a String like so
String s1 = "" + c1;
and then compare them with .equals(s1, s2)
Or you can use the Character class which is a wrapper around primitive character.
That would also enable you to use c1.equals(c2)
How to check if some String contains a specific String like "ABC72961". So we search for String which starts with "ABC" following by 5 digits. I've implemented a algorithm but I want it with "matches" or somehow else and then check the speed of these two solutions.
You may want to use regex for this
^ABC[0-9]{5}$
^ : Beginning of the string
ABC : Matches ABC literally (case-sensitive)
[0-9]{5} : Matches 5x numbers from 0 to 9
$ : End of the string
And use String#matches to test it
Regex101
Example
String regex = "^ABC[0-9]{5}$";
String one = "ABC72961";
String two = "ABC2345";
String three = "AB12345";
String four = "ABABABAB";
System.out.println(one.matches(regex)); // true
System.out.println(two.matches(regex)); // false
System.out.println(three.matches(regex)); // false
System.out.println(four.matches(regex)); // false
EDIT
Seeing your comment, you want it to work for String one = "textABC72961text" also. For that to be possible, you should just erase ^ and $ that limit the String.
.*ABC[0-9]{5}.*
EDIT 2
Here is if you want to extract it
if (s.matches(".*ABC[0-9]{5}.*")) {
Matcher m = Pattern.compile("ABC[0-9]{5}").matcher(s);
m.find();
result = m.group();
}
str.contains("ABC72961");
Returns true if str contains the string. False if not.
public String getString() {
String str = extractString();
return str;
}
public boolean exists() {
return !getString().trim().equals("") ? false : true;
}
private List<Integer> getPositionsOfABC() {
List<Integer> positions = new ArrayList<>();
int index = text.indexOf("ABC");
while (index > 0) {
positions.add(index);
index = text.indexOf("ABC", index + 1);
}
return positions;
}
private static boolean isInteger(String str) {
boolean isValidInteger = false;
try {
Integer.parseInteger(str);
isValidInteger = true;
} catch (NumberFormatException ex) {
return isValidInteger;
}
return isValidInteger;
}
private String extractString() {
List<Integer> positions = getPositionsOfABC();
for (Integer position : positions) {
int index = position.intValue();
String substring = text.substring(index, index + LENGTH_OF_DIGITS);
String lastDigits = substring.substring(3, substring.length());
if (isInteger(lastDigits)) {
return substring;
}
}
return "";
}
Here's a simple code that checks whether a substring exists in a string without using library functions, regex or other complex data structures.
class SSC {
public static void main(String[] args) {
String main_str <-- MAIN STRING
String sub_str <-- SUBSTRING
String w; int flag=0;
for(int i=0;i<=main_str.length()-sub_str.length();i++){
w="";
for(int j=0;j<sub_str.length();j++){
w+=main_str.charAt(i+j);
}
if(w.equals(sub_str))
flag++;
}
if(flag>0)
System.out.print("exists "+flag+" times");
else
System.out.print("doesn't exist");
}
}
Hope this helps.
I think what you want to use is java.util.regex.Pattern.
Pattern p = Pattern.compile("ABC(\d*)");
Matcher m = p.matcher("ABC72961");
boolean b = m.matches();
or if it shall be exactly 5 digits after "ABC", you can use the regex ABC(\d{5})
https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html#compile(java.lang.String)
Another solution would be:
String stringToTest = "ABC72961"
boolean b = stringToTest.contains("ABC");
http://www.tutorialspoint.com/java/lang/string_contains.htm
You can use the String indexOf command like this:
int result = someString.indexOf("ABC72961")
result will be -1 if there are no matches.
If there is a match, the result will be the index where the match starts.
I was practicing on lintcode and trying to solve this question
Compare two strings A and B, determine whether A contains all of the characters in B.
The characters in string A and B are all Upper Case letters.
I wrote this code which checks each character of B in A and eliminates found characters from A but somehow it fails the test for the input
A = "ABCD" and B = "ACC" . It gives output as true when it should be giving false
I don't understand the problem in my code
public class Solution {
/**
* #param A : A string includes Upper Case letters
* #param B : A string includes Upper Case letter
* #return : if string A contains all of the characters in B return true else return false
*/
public boolean compareStrings(String A, String B) {
// write your code here
int aLen = A.length();
int bLen = B.length();
if (aLen == 0) {
return bLen == 0;
}
for(int i = 0; i<bLen; i++){
String temp = B.substring(i,i);
if(A.contains(temp))
A.replace(temp, "");
else
return false;
}
return true;
}
}
the replace() method of String class will replace every occurrence of the first parameter with the second, try with replaceFirst() instead. Sample implementation
public static boolean compareStrings(String A, String B) {
boolean isOk = true;
for (int i = 0;i < B.length();i++) {
if (!A.contains(B.charAt(i) + "")) {
isOk = false;
break;
}
A = A.replaceFirst(B.charAt(i) + "", "");
}
return isOk;
}
You only want to get rid of one character from A each time. Otherwise it won't be there next time you encounter the same character in B.
Try using replaceFirst instead of replace.
Also you need to assign the result back to A using A = A.replaceFirst(...), because otherwise you won't actually change the String.
Finally, B.substring(i,i); is a string of length 0, not a string of length 1. Try "" + B.charAt(i) or B.substring(i, i + 1) instead.
Here is a complete version that works
public static boolean compareStrings(String A, String B) {
// write your code here
int aLen = A.length();
int bLen = B.length();
if (aLen == 0) {
return bLen == 0;
}
for(int i = 0; i<bLen; i++){
String temp = B.substring(i,i + 1);
if(A.contains(temp))
A = A.replaceFirst(temp, "");
else
return false;
}
return true;
}
So I'm creating a program that will output the first character of a string and then the first character of another string. Then the second character of the first string and the second character of the second string, and so on.
I created what is below, I was just wondering if there is an alternative to this using a loop or something rather than substring
public class Whatever
{
public static void main(String[] args)
{
System.out.println (interleave ("abcdefg", "1234"));
}
public static String interleave(String you, String me)
{
if (you.length() == 0) return me;
else if (me.length() == 0) return you;
return you.substring(0,1) + interleave(me, you.substring(1));
}
}
OUTPUT: a1b2c3d4efg
Well, if you really don't want to use substrings, you can use String's toCharArray() method, then you can use a StringBuilder to append the chars. With this you can loop through each of the array's indices.
Doing so, this would be the outcome:
public static String interleave(String you, String me) {
char[] a = you.toCharArray();
char[] b = me.toCharArray();
StringBuilder out = new StringBuilder();
int maxLength = Math.max(a.length, b.length);
for( int i = 0; i < maxLength; i++ ) {
if( i < a.length ) out.append(a[i]);
if( i < b.length ) out.append(b[i]);
}
return out.toString();
}
Your code is efficient enough as it is, though. This can be an alternative, if you really want to avoid substrings.
This is a loop implementation (not handling null value, just to show the logic):
public static String interleave(String you, String me) {
StringBuilder result = new StringBuilder();
for (int i = 0 ; i < Math.max(you.length(), me.length()) ; i++) {
if (i < you.length()) {
result.append(you.charAt(i)); }
if (i < me.length()) {
result.append(me.charAt(i));
}
}
return result.toString();
}
The solution I am proposing is based on the expected output - In your particular case consider using split method of String since you are interleaving by on character.
So do something like this,
String[] xs = "abcdefg".split("");
String[] ys = "1234".split("");
Now loop over the larger array and ensure interleave ensuring that you perform length checks on the smaller one before accessing.
To implement this as a loop you would have to maintain the position in and keep adding until one finishes then tack the rest on. Any larger sized strings should use a StringBuilder. Something like this (untested):
int i = 0;
String result = "";
while(i <= you.length() && i <= me.length())
{
result += you.charAt(i) + me.charAt(i);
i++;
}
if(i == you.length())
result += me.substring(i);
else
result += you.substring(i);
Improved (in some sense) #BenjaminBoutier answer.
StringBuilder is the most efficient way to concatenate Strings.
public static String interleave(String you, String me) {
StringBuilder result = new StringBuilder();
int min = Math.min(you.length(), me.length());
String longest = you.length() > me.length() ? you : me;
int i = 0;
while (i < min) { // mix characters
result.append(you.charAt(i));
result.append(me.charAt(i));
i++;
}
while (i < longest.length()) { // add the leading characters of longest
result.append(longest.charAt(i));
i++;
}
return result.toString();
}
I need to write a method where I'm given a string s and I need to return the shortest string which contains s as a contiguous substring twice.
However two occurrences of s may overlap. For example,
aba returns ababa
xxxxx returns xxxxxx
abracadabra returns abracadabracadabra
My code so far is this:
import java.util.Scanner;
public class TwiceString {
public static String getShortest(String s) {
int index = -1, i, j = s.length() - 1;
char[] arr = s.toCharArray();
String res = s;
for (i = 0; i < j; i++, j--) {
if (arr[i] == arr[j]) {
index = i;
} else {
break;
}
}
if (index != -1) {
for (i = index + 1; i <= j; i++) {
String tmp = new String(arr, i, i);
res = res + tmp;
}
} else {
res = res + res;
}
return res;
}
public static void main(String args[]) {
Scanner inp = new Scanner(System.in);
System.out.println("Enter the string: ");
String word = inp.next();
System.out.println("The requires shortest string is " + getShortest(word));
}
}
I know I'm probably wrong at the algorithmic level rather than at the coding level. What should be my algorithm?
Use a suffix tree. In particular, after you've constructed the tree for s, go to the leaf representing the whole string and walk up until you see another end-of-string marker. This will be the leaf of the longest suffix that is also a prefix of s.
As #phs already said, part of the problem can be translated to "find the longest prefix of s that is also a suffix of s" and a solution without a tree may be this:
public static String getShortest(String s) {
int i = s.length();
while(i > 0 && !s.endsWith(s.substring(0, --i)))
;
return s + s.substring(i);
}
Once you've found your index, and even if it's -1, you just need to append to the original string the substring going from index + 1 (since index is the last matching character index) to the end of the string. There's a method in String to get this substring.
i think you should have a look at the Knuth-Morris-Pratt algorithm, the partial match table it uses is pretty much what you need (and by the way it's a very nice algorithm ;)
If your input string s is, say, "abcde" you can easily build a regex like the following (notice that the last character "e" is missing!):
a(b(c(d)?)?)?$
and run it on the string s. This will return the starting position of the trailing repeated substring. You would then just append the missing part (i.e. the last N-M characters of s, where N is the length of s and M is the length of the match), e.g.
aba
^ match "a"; append the missing "ba"
xxxxxx
^ match "xxxxx"; append the missing "x"
abracadabra
^ match "abra"; append the missing "cadabra"
nooverlap
--> no match; append "nooverlap"
From my understanding you want to do this:
input: dog
output: dogdog
--------------
input: racecar
output: racecaracecar
So this is how i would do that:
public String change(String input)
{
StringBuilder outputBuilder = new StringBuilder(input);
int patternLocation = input.length();
for(int x = 1;x < input.length();x++)
{
StringBuilder check = new StringBuilder(input);
for(int y = 0; y < x;y++)
check.deleteCharAt(check.length() - 1);
if(input.endsWith(check.toString()))
{
patternLocation = x;
break;
}
}
outputBuilder.delete(0, input.length() - patternLocation);
return outputBuilder.toString();
}
Hope this helped!