I have a list of strings and with each string I want to check it's characters against every other string to see if all it's characters are identical except for one.
For instance a check that would return true would be checking
rock against lock
clock and flock have one character that is different, no more no less.
rock against dent will obviously return false.
I have been thinking about first looping through the list and then having a secondary loop within that one to check the first string against the second.
And then using split(""); to create two arrays containing the characters of each string and then checking the array elements against each other (i.e. comparing each string with the same position in the other array 1-1 2-2 etc...) and so long as only one character comparison fails then the check for those two strings is true.
Anyway I have a lot of strings (4029) and considering what I am thinking of implementing at the moment would contain 3 loops each within the other that would result in a cubic loop(?) which would take a long long time with that many elements wouldn't it?
Is there an easier way to do this? Or will this method actually work okay? Or -hopefully not- but is there some sort of potential logical flaw in the solution I have proposed?
Thanks a lot!
Why not do it the naive way?
bool matchesAlmost(String str1, String str2) {
if (str1.length != str2.length)
return false;
int same = 0;
for (int i = 0; i < str1.length; ++i) {
if (str1.charAt(i) == str2.charAt(i))
same++;
}
return same == str1.length - 1;
}
Now you can just use a quadratic algorithm to check every string against every other.
Assuming the length of two strings are equal
String str1 = "rock";
String str2 = "lick";
if( str1.length() != str2.length() )
System.out.println( "failed");
else{
if( str2.contains( str1.substring( 0, str1.length()-1)) || str2.contains( str1.substring(1, str1.length() )) ){
System.out.println( "Success ");
}
else{
System.out.println( "Failed");
}
}
Not sure if this is the best approach but this one works even when two strings are not of same length. For example : cat & cattp They differ by one character p and t is repeated. Looks like O(n) time solution using additional space for hashmap & character arrays.
/**
* Returns true if two strings differ by one character
* #param s1 input string1
* #param s2 input string2
* #return true if strings differ by one character
*/
boolean checkIfTwoStringDifferByOne(String s1, String s2) {
char[] c1, c2;
if(s1.length() < s2.length()){
c1 = s1.toCharArray();
c2 = s2.toCharArray();
}else{
c1 = s2.toCharArray();
c2 = s1.toCharArray();
}
HashSet<Character> hs = new HashSet<Character>();
for (int i = 0; i < c1.length; i++) {
hs.add(c1[i]);
}
int count = 0;
for (int j = 0; j < c2.length; j++) {
if (! hs.contains(c2[j])) {
count = count +1;
}
}
if(count == 1)
return true;
return false;
}
Assuming that all the strings have the same length, I think this would help:
public boolean differByOne(String source, String destination)
{
int difference = 0;
for(int i=0;i<source.length();i++)
{
if(source.charAt(i)!=destination.charAt(i))
{
difference++;
if(difference>1)
{
return false;
}
}
}
return difference == 1;
}
Best way is to concatenate strings together one forward and other one in reverse order. Then check in single loop for both ends matching chars and also start from middle towards ends matching char. If more than 2 chars mismatch break.
If one mismatch stop and wait for the next one to complete if it reaches the same position then it matches otherwise just return false.
public static void main(String[] args) {
New1 x = new New1();
x.setFunc();
}
static void setFunc() {
Set s = new HashSet < Character > ();
String input = " aecd";
String input2 = "abcd";
String input3 = new StringBuilder(input2).reverse().toString();
String input4 = input.concat(input3);
int length = input4.length();
System.out.println(input4);
int flag = 0;
for (int i = 1, j = length - 1; j > i - 1; i++, j--) {
if (input4.charAt(i) != input4.charAt(j)) {
System.out.println(input4.charAt(i) + " doesnt match with " + input4.charAt(j));
if (input4.charAt(i + 1) != input4.charAt(j)) {
System.out.println(input4.charAt(i + 1) + " doesnt match with " + input4.charAt(j));
flag = 1;
continue;
} else if (input4.charAt(i) != input4.charAt(j - 1)) {
System.out.println(input4.charAt(i) + " doesnt match with " + input4.charAt(j - 1));
flag = 1;
break;
} else if (input4.charAt(i + 1) != input4.charAt(j - 1) && i + 1 <= j - 1) {
System.out.println(input4.charAt(i + 1) + " doesnt match with xxx " + input4.charAt(j - 1));
flag = 1;
break;
}
} else {
continue;
}
}
if (flag == 0) {
System.out.println("Strings differ by one place");
} else {
System.out.println("Strings does not match");
}
}
Related
char [] text = {'H','e','l','L','o','H','e','l','L','o'};
char[] pat = {'H','e','?','l','o'}; //'?' stands for every possible sign
We can ignore if the letters are upper or lower case.
Now I need to output how often it occurs.
Output: He?lo is in HelLoHelLo 2x
I know that you can use string methods like "contain" but how can I consider the question mark ?
public int matchCount(char[] text, char[] pattern) {
int consecCharHits = 0, matchCount = 0;
for (int i = 0; i < text.length; i++) {
if (text[i] == pattern[consecCharHits] || '?' == pattern[consecCharHits]) { // if char matches
consecCharHits++;
if (consecCharHits == pattern.length) { // if the whole pattern matches
matchCount++;
i -= consecCharHits - 1; // return to the next position to be evaluated
consecCharHits = 0; // reset consecutive char hits
}
} else {
i -= consecCharHits;
consecCharHits = 0;
}
}
return matchCount;
}
The way I would naively implement it without thinking too much about it
create inputIndex and set it to 0
create matchIndex and set it to 0
iterate over the input by incrementing the inputIndex one by one
compare the char in the input at inputIndex with the char in the match at matchIndex
if they "match" increment the matchIndex by one - if they don't set matchIndex to 0
if the matchIndex equals to your pat length increment the actual count of matches by one and set matchIndex back to 0
Where I wrote "match" you need to implement your custom match logic, ignoring the case and considering everything a match if the pattern at this place is a ?.
#Test
public void match() {
char [] text = {'H','e','l','L','o','H','e','l','L','o'};
char[] pat = {'H','e','?','l','o'}; //'?' stands for every possible sign
printMatch(text, pat);
}
private void printMatch(char[] text, char[] pat) {
String textStr = new String(text);
String patStr = new String(pat);
final String regexPattern = patStr.replace('?', '.').toLowerCase();
final Pattern pattern = Pattern.compile(regexPattern);
final Matcher matcher = pattern.matcher(textStr.toLowerCase());
while (matcher.find()) {
System.out.println(patStr + " is in " + textStr );
}
}
What about this ?
static int countPatternOccurences (char [] text, char [] pat)
{
int i = 0;
int j = 0;
int k = 0;
while ( i < text.length)
{
int a = Character.getNumericValue(pat[j]);
int b = Character.getNumericValue(text[i]);
if (a == b || pat[j] =='?')
{
j++;
}
else
{
j=0;
//return 0;
}
if(j == pat.length)
{
k++;
j = 0;
}
i++;
}
return k; // returns occurrences of pat in text
}
How to remove Consecutive Characters at each Iteration..
Below is the screenshot that explains the question with more details
MySolution
Initially I checked whether there are any Consecutive characters.
If yes,Then,remove all the consecutive characters and when there are no consecutive characters add the remaining characters to another String.
If no Consecutive Characters just simply increment it.
public static void print(){
String s1="aabcccdee"; I have taken a sample test case
String s2="";
for(int i=0;i<s1.length();){
if(s1.charAt(i)==s1.charAt(i+1)){
while(s1.charAt(i)==s1.charAt(i+1)){
i++;
}
for(int j=i+1;j<s1.length();j++){
s2=s2+s1.charAt(j);
}
s1=s2;
}
else
i++;
}
System.out.println(s1);
}
Output Shown
An infinite Loop
Expected Output for the give sample is
bd
Can Anyone guide me how to correct?
You can simply use String::replaceFirts with this regex (.)\1+ which means matche any charater (.) which followed by itself \1 one or more time + with empty.
In case you want to replace first by first you have to check the input, if after each iteration still contain more than one consecutive characters or not, in this case you can use Pattern and Matcher like this :
String[] strings = {"aabcccdee", "abbabba", "abbd "};
for (String str : strings) {
Pattern pattern = Pattern.compile("([a-z])\\1");
// While the input contain more than one consecutive char make a replace
while (pattern.matcher(str).find()) {
// Note : use replaceFirst instead of replaceAll
str = str.replaceFirst("(.)\\1+", "");
}
System.out.println(str);
}
Outputs
aabcccdee -> bd
abbabba -> a
abbd -> ad
Update
I had misread the question. The intent is to also remove the consecutive characters after each replacement. The below code does that.
private static String removeDoubles(String str) {
int s = -1;
for (int i = 1; i < str.length(); i++) {
// If the current character is the same as the previous one,
// remember its start position, but only if it is not set yet
// (its value is -1)
if (str.charAt(i) == str.charAt(i - 1)) {
if (s == -1) {
s = i - 1;
}
}
else if (s != -1) {
// If the current char is not equal to the previous one,
// we have found our end position. Cut the characters away
// from the string.
str = str.substring(0, s) + str.substring(i);
// Reset i. Notice that we don't have to loop from 0 on,
// instead we can start from our last replacement position.
i = s - 1;
// Finally reset our start position
s = -1;
}
}
if (s != -1) {
// Check the last portion
str = str.substring(0, s);
}
return str;
}
Note that this is almost 10 times faster than YCF_L's answer.
Original post
You are almost there, but you don't have to use multiple for loops. You just need one loop, because whether to remove characters from the string only depends on subsequent characters; we don't need to count anything.
Try this:
private static String removeDoubles(String s) {
boolean rem = false;
String n = "";
for (int i = 0; i < s.length() - 1; i++) {
// First, if the current char equals the next char, don't add the
// character to the new string and set 'rem' to true, which is used
// to remove the last character of the sequence of the same
// characters.
if (s.charAt(i) == s.charAt(i + 1)) {
rem = true;
}
// If this is the last character of a sequence of 'doubles', then
// reset 'rem' to false.
else if (rem) {
rem = false;
}
// Else add the current character to the new string
else {
n += s.charAt(i);
}
}
// We haven't checked the last character yet. Let's add it to the string
// if 'rem' is false.
if (!rem) {
n += s.charAt(s.length() - 1);
}
return n;
}
Note that this code is on average more than three times faster than regular expressions.
Try something like this:
public static void print() {
String s1 = "abcccbd"; // I have taken a sample test case
String s2 = "";
while (!s1.equals(s2)) {
s2 = s1;
s1 = s1.replaceAll("(.)\\1+", "");
}
System.out.println(s1);
}
consider this easier to understand code
String s1="aabcccdee";
while (true) {
rvpoint:
for (int x = 0; x < s1.length() -1; x++)
{
char c = s1.charAt(x);
if (c == s1.charAt(x+ 1)) {
s1 = s1.replace(String.valueOf(c), "");
continue rvpoint; // keep looping if a replacement was made
}
}
break; // break out of outer loop, if replacement not found
}
System.out.println(s1);
note
This will only work for the first iteration, put into a method and keep calling until the sizes do not change
I want to append certain string in the last item of the foreach array.
The program works perfectly fine. Given the items in the "pending" array, it should append the out value in the last item in the pending value:
String a = out + "-" + rptdate + "-";
for (String pn : pending) {
//checks if total value + pending length value is less than 160
if (a.length() + pn.length() < 160) { // < to leave room for the comma as well
if (a.length() != 0) {
if (a.length() != 14) {
a += ",";
}
}
a += pn;
} else {
resultingStrings.add(a);
a = pn;
Log.d("messages", a);
}
}
resultingStrings.add(a);
for (String r : resultingStrings) {
sendSMS(r);
}
Try simple code
int size = pending.size();
int index = 0;
for (String pn : pending) {
if(index == size - 1){
// it is last foreach => add your last string here
}
index++;
...
}
Hope this help
You could also do,
for(int i = 0; i < array.length; i++) {
if(i = (array.length - 1)) {
//this is the last element in the array
}
}
If all you need to do is grab the last element of a Collection and append some text to it then this should work.
String out = "Some value";
int lastIndex = pending.getSize() -1; // < 0 indexed
String lastItem = pending.get(lastIndex)
String newLastItem = lastItem + out; // < String concatenation
but from your snippet I don't think that's what your after because if we remove some of the magic numbers and correct the indentation, and make some assumptions about what your trying to do your left with
String a = out + "-" + rptdate + "-";
int prefixLength = a.length();
for (String pn : pending) {
//checks if total value + pending length value is less than 160
if (a.length() + pn.length() < MAX_LENGTH) { // < to leave room for the comma as well
if (a.length() > prefixLength) {
a += ",";
}
a += pn;
} else {
// have string longer than max length, so save and start a new sms.
resultingStrings.add(a);
Log.d("messages", a); // < log a before you overwrite it.
a = pn;
}
}
// DO YOU WANT TO APPEND out AS A SUFFIX TO a HERE ???
// a += out;
// but if so youll want to consider the case if a is now > MAX_LENGTH
resultingStrings.add(a); // add the last string
// send all composed strings
for (String r : resultingStrings) {
sendSMS(r);
}
I am picking your relatively new to coding so I'd suggest first you start off with some pseudo-code of what your trying to do, it can then become comments in your code. Always keep your code formatted nicely so that indents are matched, and use descriptive names for your variables, and constants.
I need to fetch a sub string that lies between two same or different delimiters. The delimiters will be occurring multiple times in the string, so i need to extract the sub-string that lies between mth occurrence of delimiter1 and nth occurrence of delimiter2.
For eg:
myString : Ron_CR7_MU^RM^_SAF_34^
What should i do here if i need to extract the sub-string that lies between 3rd occurrence of '_' and 3rd occurence of '^'?
Substring = SAF_34
Or i could look for a substring that lies between 2nd '^' and 4th '_', i.e :
Substring = _SAF
An SQL equivalent would be :
substr(myString, instr(myString, '',1,3)+1,instr(myString, '^',1,3)-1-instr(myString, '',1,3))
I would use,
public static int findNth(String text, String toFind, int count) {
int pos = -1;
do {
pos = text.indexOf(toFind, pos+1);
} while(--count > 0 && pos >= 0);
return pos;
}
int from = findNth(text, "_", 3);
int to = findNth(text, "^", 3);
String found = text.substring(from+1, to);
If you can use a solution without regex you can find indexes in your string where your resulting string needs to start and where it needs to end. Then just simply perform: myString.substring(start,end) to get your result.
Biggest problem is to find start and end. To do it you can repeat this N (M) times:
int pos = indexOf(delimiterX)
myString = myString.substring(pos) //you may want to work on copy of myString
Hope you get an idea.
You could create a little method that simply hunts for such substrings between delimiters sequentially, using (as noted) String.indexOf(string); You do need to decide whether you want all substrings (whether they overlap or not .. which your question indicates), or if you don't want to see overlapping strings. Here is a trial for such code
import java.util.Vector;
public class FindDelimitedStrings {
public static void main(String[] args) {
String[] test = getDelimitedStrings("Ron_CR7_MU'RM'_SAF_34'", "_", "'");
if (test != null) {
for (int i = 0; i < test.length; i++) {
System.out.println(" " + (i + 1) + ". |" + test[i] + "|");
}
}
}
public static String[] getDelimitedStrings(String source,
String leftDelimiter, String rightDelimiter) {
String[] answer = null;
;
Vector<String> results = new Vector<String>();
if (source == null || leftDelimiter == null || rightDelimiter == null) {
return null;
}
int loc = 0;
int begin = source.indexOf(leftDelimiter, loc);
int end;
while (begin > -1) {
end = source
.indexOf(rightDelimiter, begin + leftDelimiter.length());
if (end > -1) {
results.add(source.substring(begin, end));
// loc = end + rightDelimiter.length(); if strings must be
// returned as pairs
loc = begin + 1;
if (loc < source.length()) {
begin = source.indexOf(leftDelimiter, loc);
} else {
begin = -1;
}
} else {
begin = -1;
}
}
if (results.size() > 0) {
answer = new String[results.size()];
results.toArray(answer);
}
return answer;
}
}
I want to find the longest common prefix of two strings.
Is there a way to loop my last couple of if statements so that I can end at the last characters that do not match each other?
System.out.println("Enter the first string: ");
String s = input.nextLine();
System.out.println("Enter the second string: ");
String s2 = input.nextLine();
//check if first characters are same
if (s.charAt(0) != s2.charAt(0)) {
System.out.println(""+s+ " and "+s2+ " have no common prefix");
System.exit(0);
}
if (s.charAt(0) == s2.charAt(0))
System.out.print(" "+s.charAt(0));
if (s.charAt(0) == s2.charAt(0))
System.out.print(" "+s.charAt(1));
if (s.charAt(0) == s2.charAt(0))
System.out.print(" "+s.charAt(2));
}
}
Example:
Enter first string: Welcome to c++
Enter second string: Welcome to java
The code should return Welcome to as the common prefix.
try this. I guess this is what you are trying to achieve. If this is correct I will add explanation later
import java.util.*;
import java.lang.*;
import java.io.*;
class Ideone
{
public static void main (String[] args) throws java.lang.Exception
{
String s = "Hello Wo";
String s2 = "Hello World";
String small,large;
if(s.length() > s2.length())
{small = s2;large = s;}
else
{small = s;large = s2;}
int index = 0;
for(char c: large.toCharArray())
{
if(index==small.length()) break;
if(c != small.charAt(index)) break;
index++;
}
if(index==0)
System.out.println(""+s+ " and "+s2+ " have no common prefix");
else
System.out.println(large.substring(0,index));
}
}
Edit:
I find the larger of the strings and choose it to be the outer string to loop throught
toCharArray() converts the string into characters so you can loop through each characters in the string using Java's foreach (For more click[1])
Inside the loop you should exit on two conditions
End of the string (I use length to find if I reach end of smaller string)
no more matching characters between two strings
you increment the index until you break out in one of the above conditions
By the time you break out of the for loop, index will contain the last index where both string are continuously equal.
If index = 0. just say no matches else print characters from 0 until index
Maybe something like:
int sLength = s.length(),
s2Length = s2.length(),
minLength = (sLength < s2Length) ? sLength : s2Length;
for (int i = 0; i < minLength; i++) {
if (s.charAt(i) == s2.charAt(i)) {
System.out.println(s.charAt(i));
}
else {
break;
}
}
But more details about your question would be great.
Edit: It depends what #afrojuju_ wants to do. That's not clear. Some more logic may be added to accomplish the desired behavior.
Edit 2: Added string length comparison as pointed out by #JavaBeast.
public static String LcpFinder (String s1 , String s2){
if (s1 == null || s2 == null){
throw new IllegalArgumentException();
}
int minLength = 0;
if (s1.length() < s2.length()){
minLength = s1.length();
}
else{
minLength = s2.length();
}
for (int i = 0 ; i < minLength ; i++){
if(s1.charAt(i) == s2.charAt(i)){
continue;
}
else{
return s1.substring(0,i);
}
}
return s1.substring(0,minLength);
}
Try with this code block:
str1 = input().lower()
str2 = input().lower()
for i in range(min(len(str1),len(str2))):
if str1[i] != str2[i]:
break
if i == 0:
print(-2)
else:
print(str1[:i])