Matching subsequence of length 2 (at same index) in two strings - java

Given 2 strings, a and b, return the number of the positions where they contain the same length 2 substring. For instance a and b is respectively "xxcaazz" and "xxbaaz" yields 3, since the "xx", "aa", and "az" substrings appear in the same place in both strings.
What is wrong with my solution?
int count=0;
for(int i=0;i<a.length();i++)
{
for(int u=i; u<b.length(); u++)
{
String aSub=a.substring(i,i+1);
String bSub=b.substring(u,u+1);
if(aSub.equals(bSub))
count++;
}
}
return count;
}

In order to fix your solution, you really don't need the inner loop. Since the index should be same for the substrings in both string, only one loop is needed.
Also, you should iterate till 2nd last character of the smaller string, to avoid IndexOutOfBounds. And for substring, give i+2 as second argument instead.
Overall, you would have to change your code to something like this:
int count=0;
for(int i=0; i < small(a, b).length()-1; i++)
{
String aSub=a.substring(i,i+2);
String bSub=b.substring(i,i+2);
if(aSub.equals(bSub))
count++;
}
}
return count;
Why I asked about the length of string is, it might become expensive to create substrings of length 2 in loop. For length n of smaller string, you would be creating 2 * n substrings.
I would rather not create substring, and just match character by character, while keeping track of whether previous character matched or not. This will work perfectly fine in your case, as length of substring to match is 2. Code would be like:
String a = "iaxxai";
String b = "aaxxaaxx";
boolean lastCharacterMatch = false;
int count = 0;
for (int i = 0; i < Math.min(a.length(), b.length()); i++) {
if (a.charAt(i) == b.charAt(i)) {
if (lastCharacterMatch) {
count++;
} else {
lastCharacterMatch = true;
}
} else {
lastCharacterMatch = false;
}
}
System.out.println(count);

The heart of the problem lies with your usage of the substring method. The important thing to note is that the beginning index is inclusive, and the end index is exclusive.
As an example, dissecting your usage, String aSub=a.substring(i,i+1); in the first iteration of the loop i = 0 so this line is then String aSub=a.substring(0,1); From the javadocs, and my explanation above, this would result in a substring from the first character to the first character or String aSub="x"; Changing this to i+2 and u+2 will get you the desired behavior but beware of index out of bounds errors with the way your loops are currently written.

String a = "xxcaazz";
String b = "xxbaaz";
int count = 0;
for (int i = 0; i < (a.length() > b.length() ? b : a).length() - 1; i++) {
String aSub = a.substring(i, i + 2);
String bSub = b.substring(i, i + 2);
if (aSub.equals(bSub)) {
count++;
}
}
System.out.println(count);

Related

How to find frequency of characters in a string without using array in java

Given a String, I want to create a frequency distribution of characters in the String. That is, for each distinct character in the string, I want to count how many times it occurs.
Output is a String that consists of zero or more occurrences of the pattern xd, where x is a character from the source String, and d is the number of occurrences of x within the String. Each x in the output should occur once.
The challenge is to do this without using an array or Collection.
Examples:
Source: "aasdddr" Result: "a2s1d3r1"
Source: "aabacc" Result: "a3b1c2"
Source: "aasdddraabcdaa" Result: "a6s1d4r1b1c1"
I tried this way:
String str = "aasdddr", result = "";
int counter = 0;
for(int i = 0; i < str.length(); i++){
result += "" + str.charAt(i);
for(int j = 1; j < str.length(); j++){
if(str.charAt(i) == str.charAt(j)){
counter++;
}
}
result += counter;
}
System.out.println(result);
My output is a1a2s3d6d9d12r13
Finally, I found the solution. But I think any question has more than one solution.
First, we should declare an empty string to keep the result. We use a nested loop because the outer loop will keep a character fixed during each iteration of the inner loop. Also, we should declare a count variable inside the outer loop. Because in each match, it will be increased by one and after controlling each character in the inner loop, it will be zero for the next check. Finally, after the inner loop, we should put a condition to check whether we have that character inside the result string. If there isn't any character like that, then it will be added to the result string. After that, its frequency (count) will be added. Outside of the loop, we can print it.
public class FrequenciesOfChar {
public static void main(String[] args) {
String str = "aabcccd"; // be sure that you don't have any digit in your string
String result = ""; // this will hold new string
for (int i = 0; i < str.length(); i++) { // this will hold a character till be checked by inner loop
int count = 0; // put here so that it can be zero after each cycle for new character
for (int j = 0; j < str.length(); j++) { // this will change
if(str.charAt(i) == str.charAt(j)){ // this will check whether there is a same character
count++; // if there is a same character, count will increase
}
}
if( !(result.contains(""+str.charAt(i))) ){ // this checks if result doesn't contain the checked character
result += ""+str.charAt(i); // first if result doesn't contain the checked character, character will be added
result += count; // then the character's frequency will be added
}
}
System.out.println(result);
}
}
Run Result:
aabcccd - a2b1c3d1
First, counter needs to be reset inside the for loop. Each time you encounter a character in the source String, you want to restart the counter. Otherwise, as you have seen, the value of the counter is strictly increasing.
Now, think about what happens if a character occurs in more than one place in the source String, as in the "aasdddraabcdaa" example. A sequence of 1 or more a appears in 3 places. Because, at the time you get to the 2nd occurrence of a, a has been previously counted, you want to skip over it.
Because the source String cannot contain digits, the result String can be used to check if a particular character value has already been processed. So, after fixing the problem with counter, the code can be fixed by adding these two lines:
if (result.indexOf (source.charAt(i)) >= 0) {
continue; }
Here is the complete result:
package stackoverflowmisc;
public class StackOverflowMisc {
public static String freqDist(String source) {
String result = "";
int counter ;
for (int i = 0; i < source.length(); i++) {
if (result.indexOf (source.charAt(i)) >= 0) { continue; }
counter = 1;
result += source.charAt(i);
for (int j = 1; j < source.length(); j++) {
if (source.charAt(i) == source.charAt(j)) {
counter++;
}
}
result += counter;
}
return result;
}
public static void main(String[] args) {
String [] test = {"aasdddr", "aabacc", "aasdddraabcdaa"};
for (int i = 0; i < test.length; ++i) {
System.out.println (test[i] + " - " + freqDist (test[i]));
}
System.out.println ("End of Program");
}
}
Run results:
aasdddr - a2s2d4r2
aabacc - a3b2c3
aasdddraabcdaa - a6s2d5r2b2c2
End of Program
In one of the Q&A comments, you said the source string can contain only letters. How would the program work if it were allowed to contain digits? You can't use the result String, because the processing inserts digits there. Again, this is an easy fix: Add a 3rd String to record which values have already been found:
public static String freqDist2(String source) {
String result = "", found = "";
int counter ;
for (int i = 0; i < source.length(); i++) {
if (found.indexOf (source.charAt(i)) >= 0) { continue; }
counter = 1;
result += source.charAt(i);
found += source.charAt(i);
for (int j = 1; j < source.length(); j++) {
if (source.charAt(i) == source.charAt(j)) {
counter++;
}
}
result += counter;
}
return result;
}
Another possibility is to delete the corresponding characters from the source String as they are counted. If you are not allowed to modify the Source String, make a copy and use the copy.
Comment: I don't know if this is what your professor or whomever had in mind by placing the "No array" restriction, because a String is essentially built on a char array.

Why am I doing i < a.length()-1 in my for loop

The question is: Given two Strings, return the number of the positions where they contain the same substring with a length of 2 .
The code I wrote works but my question is why do I have to add the minus 1 to line 3 which is this part: i<a.length()-1
(I know it has something to do with me using (i,i+2))
public int stringMatch(String a, String b) {
int count = 0;
if (a.length() < b.length()) {
for (int i=0; i<a.length()-1; i++) {
if (a.substring(i,i+2).equals(b.substring(i,i+2))) {
count++;
}
}
} else {
for (int i=0; i<b.length()-1; i++) {
if (b.substring(i,i+2).equals(a.substring(i,i+2))) {
count++;
}
}
}
return count;
}
Since the substring goes from the index i (included) to i + 2 (excluded), in order not to go out of the substring the loop needs to finish 1 step before.
String.length() function returns length of the string, but when you access the characters you access it using index. That is why you have to do "-1".
For Example:
String s = "Hello";
Length is 5.
Index is from 0 to 4.

Substring a String depending on int [duplicate]

This question already has answers here:
Java: How to split a string by a number of characters?
(11 answers)
Closed 5 years ago.
I wanted to substring a String depending on int that I will passed on the method. I used nested loop for this. But everytime it loops I wanted to substring only from last substring to int the I passed in the method and get also the last string. How can I achieve this?
private static void input(String s, int I)
{
List list = new ArrayList();
for(int a = 0; a < s.length(); a++)
{
for(int position = 0; position < s.length(); position++)
{
if(position + a + I <= s.length())
{
list.add(s.substring(position, position + a + I));
}
}
}
}
input("abaca", 2);
Expected output: "ab", "ac", "a"
You don't need nested loops. Just iterate over the String once, and add an I character substring in each iteration.
Note that a is the starting index of the current substring, and it therefore incremented by I in each iteration.
The last substring may have a shorter length. If a + I > s.length(), the last index of the last substring will be s.length() - 1 instead of a + I - 1.
for(int a = 0; a < s.length(); a+=I) {
list.add(s.substring(a, Math.min(a + I, s.length())));
}
This produces
[ab, ac, a]
for input("abaca", 2).
You can also simply split the string:
private static void input(String s, int i){
List list = Arrays.asList(s.split("(?<=\\G.{"+i+"})"));
System.out.println(list);
}
\\G means The end of the previous match
?<= means positive lookbehind
Thanks to positive lookbehind (?<=) it will split on all zero length strings (without cutting off anything from the input string) preceded by where previous match ends (\\G) followed by i signs (.{"+i+"}).
It's really better to completely rewrite your code, but if you want to save your structure(even though it's not correct), just remove 1 loop and do something like this:
private static void input(String s, int I) {
List list = new ArrayList();
for (int position = 0; position < s.length();position += I) {
if (position + I <= s.length()) {
list.add(s.substring(position, position + I));
} else {
list.add(s.substring(position, s.length()));
return;
}
}
}

sort a string in recursion

I have a certain string and I want to sort it in recursion.
My code is error free but the algorithm is not working and I need help
The index will be zero when calling the function.
The main idea is the compare between indexes in the string and creating a new string each time with the new sequence of the letters compared.
each call I send the new string which was created in each run
private static String sort(String s1, int index)
{
String s2="";
if (index == s1.length()-2)
return s1;
else
{
if (s1.charAt(index) > s1.charAt(index+1))
{
for (int i = 0; i < s1.length(); i++)
{
if (index == i)
{
s2 += s1.charAt(index+1);
s2 += s1.charAt(index);
i += 2;
}
s2 += s1.charAt(i);
}
}
else
{
for (int i = 0; i < s1.length(); i++)
{
if (index == i)
{
s2 += s1.charAt(index);
s2 += s1.charAt(index+1);
i += 2;
}
s2 += s1.charAt(i);
}
}
return (sort(s2,++index));
}
}
input : acbacds
output: abaccds
the output should be : aabccds
Each call compares a pair of adjacent characters; if they're out of order, you switch them.
Your recursion simply replaces an outer loop running through the length of the array.
The end of this process guarantees that the largest value will now be at the end of the array. To this extent, it works correctly.
If you expect an array of N elements to get fully sorted, you must repeat this process up to N-1 times. The only reason your given example is so close is that the array you gave it is already very close to sorted.
Try again with something in reverse order, and you'll see the effect. For instance, use "hgfedcba". One pass will get you "gfedcbah", moving the 'h' from the front to the end.
If you want a working bubble sort, try searching here on SO or on the web overall.
Finally, you might look into the Java substring functions; building s2 a character at a time is hard on the eyes; it's also slow, especially in the case where you don't switch characters.

Find all substrings of a string - StringIndexOutOfBoundsException

I created class Word. Word has a constructor that takes a string argument and one method getSubstrings which returns a String containing all substring of word, sorted by length.
For example, if the user provides the input "rum", the method returns a
string that will print like this:
r
u
m
ru
um
rum
I want to concatenate the substrings in a String, separating them with a newline ("\n"). Then return the string.
Code:
public class Word {
String word;
public Word(String word) {
this.word = word;
}
/**
* Gets all the substrings of this Word.
* #return all substrings of this Word separated by newline
*/
public String getSubstrings()
{
String str = "";
int i, j;
for (i = 0; i < word.length(); i++) {
for (j = 0; j < word.length(); j++) {
str = word.substring(i, i + j);
str += "\n";
}
}
return str;
}
But it throws exception:
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1911)
I stuck at this point. Maybe, you have other suggestions according this method signature public String getSubstrings().
How to solve this issue?
Analysis of Exception:
From Java7 Docs of StringIndexOutOfBoundsException
public class StringIndexOutOfBoundsException extends IndexOutOfBoundsException
Thrown by String methods to indicate that an index is either negative or greater than the size of the string.
From Java 7 Docs of substring
public String substring(int beginIndex,int endIndex)
Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex.
I guess this: length of the substring is endIndex-beginIndex comes into String index out of range: -1. I have tested with multiple cases holding my assumption true but appreciate any other proof.
For -1: "rum".substring(2,1); will give you String index out of range: -1
Parameters:
beginIndex - the beginning index, inclusive.
endIndex - the ending index, exclusive.
Cause of StringIndexOutOfBoundsException:
In the given code snippet, substring is trying to fetch string which has endIndex more than the total length of String (i+j will exceed the total length of string):
str = word.substring(i, i + j);
Consider the case when i=2 and j=2 for word "rum"
then str=word.substring(2, 4);
would not be possible
Solution similar to code snippet given in Question:
This should solve the problem:
public String getSubstrings()
{
String str="",substr = "";
for (int i = 0; i < word.length(); i++) {
for (int j = 0; i+j <= word.length(); j++) { //added i+j and equal to comparison
substr = word.substring(j, i + j); //changed word.substring(i, i + j) to word.substring(j, i + j)
if("".equals(substr))continue; //removing empty substrings
str += substr; //added concatenation + operation
str += "\n";
}
}
return str+word;
}
Test Case:
For word="rum", this will give output:
r
u
m
ru
um
rum
Your logic seems convoluted , the source of exception:
str = word.substring(i, i + j);
Consider your i and j both equals word.length()-1 , then the substring() will fail.
You can simply do :
public String getSubstrings(String word){
StringBuilder sub= new StringBuilder();
for( int i = 0 ; i < word.length() ; i++ )
{
for( int j = 1 ; j <= word.length() - i ; j++ )
{
sub .append(word.substring(i, i+j)).append("\n");
}
}
return sub.toString();
}
Note: Consider using StringBuilder instead of String if you will do lots of concatenation on String.
I realize I'm a little late to this party, and I'm a very new programmer, myself -- but I was running into the same error last night while trying to write a similar method.
For me, it helped to rename the counter variables of the nested for loops to names that described what they are keeping track of. For the outer loop, I used int subLength, and for the inner loop, I used int position (starting position). I'm sure there are other ways of doing this, but I was happy with my solution. Here is some pseudocode that I hope will help someone else who looks this question up:
for each possible substring length 1 up to and including the original word length:
generate substrings starting at the 0th position, and then starting at each
proceeding letter up to but not including (word.length() - (subLength - 1))

Categories

Resources