Reduce String.charAt to one loop during String comparison - java

I need to compare two strings that are of varying length and as such I have written two conditional loops depending on which String is longest:
boolean compare(String first, String second)
{
boolean firstLongest = first.length() > second.length();
if(firstLongest)
{
for(int i = 0; i < first.length(); i++)
//charAt code here
}
else{
for(int i = 0; i < second.length();i++)
//charAt code here
}
}
I decided to re-write it as so:
boolean compare(String first, String second)
{
int lengthDifference = first.length() - second.length();
for(int i = 0; i < first.length() + lengthDifference;i++)
//charAt code here
}
I want to avoid having 1) two loops and 2) out of bounds exceptions. My question is does the above implementation have a corner case that I am missing or should this work for all possible inputs.

Your revised version will break if the second string is longer.
Use:
int combinedLength = Math.min(first.length(), second.length());
then your condition only needs to be:
i < combinedLength

Simply use the lowest one:
//Maybe knowing what the length diff is interesting to achieve your goal:
int lenDiff = Math.abs(first.length() - second.length());
// The loop, taking the length of the shortest one as limit
for (int i = 0; i < Math.min(first.length(), second.length()); ++i)
{
// Char code here
}

Related

Java for loop i++ as a string

Let's say we have a for loop
for(int i = 0; i < 10; i++) {
...
}
What format is the i++ in?
I have a String increment = "i++" which tells me how much to increment i by.
But when I just directly try and put the increment string as an incrementor it doesn't work. I tried the below but it doesn't work.
for(int i = 0; i < 10; increment) {
...
}
How can I make this work?
The increment need to be an direct attribution,
you can't use a String to define this, is impossible
One solution to change dynamically how much will be the increment, it's using a variable
int j=1;
for(int i=0;i<10;i+=j)
the += operator it's used for the increment, for example:
int x = 0;
x += 1; //x is 1
x += 3; //x is 4
x += 2; //x is 6
x++; //x is 7
But in the most cases you don't need to use this in a for loop, what you need to do?
Hugs
You could parse the increment string to an int then use that as your increment in your loop:
String increment = "i+2"; // Will also work for "i++" or "i+n" (n = a number)
String num = increment.replaceAll("i\\+*", "");
int incValue = 1;
if(!num.isEmpty())
incValue = Integer.parseInt(num);
for(int i = 0; i < 10 ; i+=incValue)
{
System.out.println(i);
}
So for this, you cannot use a string as a expression.
There will be quite a few ways to map a String to expression.
One of the ways is you can use switch case:
String increment = "i++";
int i = 0;
while(i < 10)
{
//your logic here
switch (increment){
case "i++":
i++;
break;
case "i=i+2":
i = i + 2;
break;
}
}
You can also use Regex or parse the String to convert to int
You can simply get increment count in a string if you want to do increment dynamically, instead of whole increment statement. Here is an example:
String inc = "2";
String max = "10";
for(int i = 0; i < Integer.valueOf(max); i=i+Integer.valueOf(inc)) {
System.out.println(i);
}
i++ is just code : it's not a string as you thought.
Here's an analogy to demonstrate your assumption:
String someString =
"public static void doStuff()
{
System.out.println("this is working");
}";
Now if you refer to the String someString in a separate method, do you think that the doStuff() method will be called? Of course not, because String is just text that the interpreter doesn't go through. The interpreter can only go through executable code, which includes the i++ in question.

Algorithm for combinatorics (6 choose 2)

Following this question, I want to now code "6 choose 2" times "4 choose 2." By that I mean, lets say I have 6 characters "A B C D E F." The first time I choose any two characters to delete. The 2nd time I want to choose 2 different letters to delete and then I append the results of these two trials. Hence, I will receive 90("6 choose 2" times "4 choose 2") eight character strings. The characters in the pattern are from the same pattern {1,2,3,4,5, 6}. All the characters are unique and no repetition.
Here is what I have so far.
public String[] genDelPatterns(String design){
char[] data = design.toCharArray();
String[] deletionPatterns = new String[15];
int x = 0;
StringBuilder sb = new StringBuilder("");
int index = 0;
for(int i = 0; i < (6-1); i++){
for(int j = i+1; j < 6; j++){
for(int k= 0; k < 6; k++){
if((k != j) && (k != i))
sb.append(String.valueOf(data[k]));
}
deletionPatterns[x++] = sb.toString();
sb = new StringBuilder("");
}
}
return deletionPatterns;
}
public String[] gen8String(String[] pattern1, String[] pattern2){
String[] combinedPatterns = new String[225];
int k = 0;
for(int i = 0; i < 15; i++)
{
for(int j = 0; j < 15; j++)
combinedPatterns[k++] = pattern1[i] + pattern2[j];
}
return combinedPatterns;
}
I will be calling the methods like this:
gen8String(genDelPatterns("143256"), genDelPatterns("254316"));
Currently, I am generating all the possible 8 letter strings. But I want to only generate the 8 character strings according to the aforementioned specifications. I am really stuck on how I can elegantly do this multiplication. The only way I can think of is to make another method that does "4 choose 2" and then combine the 2 string arrays. But this seems very roundabout.
EDIT: An example of an 8 character string would be something like "14322516", given the inputs I have already entered when calling gen8String, (143256,254316). Note that the first 4 characters are derived from 143256 with the 5 and 6 deleted. But since I deleted 5 and 6 in the first trail, I am no longer allowed to delete the same things in the 2nd pattern. Hence, I deleted the 3 and 4 from the 2nd pattern.
you have a chain of methods , each one called a variation itself.
For so, my advice is to use a recursive method!
to achieve your goal you have to have a little experience with this solution.
A simple example of a method that exploits the recursion:
public static long factorial(int n) {
if (n == 1) return 1;
return n * factorial(n-1);
}
I can also suggest you to pass objects (constructed to perfection) for the method parameter, if is too complex to pass simple variables
This is the heart of this solution in my opinion.
While what you tried to do is definitely working, it seems you are looking for other way to implement it. Here is the skeleton of what I would do given the small constrains.
// Very pseudo code
// FOR(x,y,z) := for(int x=y; x<z;x++)
string removeCharacter(string s, int banA, int banB){
string ret = "";
FOR(i,1,7){
if(i != banA && i != banB){
ret += s[i];
}
}
return ret;
}
List<string> Generate(s1,s2){
List<string> ret = new List<string>();
FOR(i,1,7) FOR(j,i+1,7) FOR(m,1,7) FOR(n,m+1,7){
if(m != i && m != j && n != i && n != j){
string firstHalf = removeCharacter(s1,i,j);
string secondHalf = removeCharacter(s2,m,n);
ret.Add(firstHalf + secondHalf);
}
}
return ret;
}
This should generate all possible 8-characters string.
Here is the solution I came up with. Doesn't really take "mathematical" approach, I guess. But it does the job.
//generating a subset of 90 eight character strings (unique deletion patterns)
public static String[] gen8String(String[] pattern1, String[] pattern2){
String[] combinedSubset = new String[90]; //emty array for the subset of 90 strings
String combinedString = ""; //string holder for each combined string
int index = 0; //used for combinedSubset array
int present = 0; //used to check if all 6 characters are present
for(int i = 0; i < 15; i++){
for(int j = 0; j < 15; j++){
combinedString = pattern1[i] + pattern2[j]; //combine both 4 letter strings into 8 char length string
char[] parsedString = combinedString.toCharArray(); //parse into array
//check if all 6 characters are present
for(int k = 1; k <= 6; k++)
{
if(new String(parsedString).contains(k+"")) {
present++;
}
else
break;
//if all 6 are present, then add it to combined subset
if(present == 6)
combinedSubset[index++] = combinedString;
}
present = 0;
}
}
return combinedSubset;
}

Check if two strings contain a similar substring

I am trying to write a program and part of that program is finding a similarity between two strings. You ask the user how many similar letters should be with in the strings.
For example:
string1 = aghilfamjijasrnlklk;
string2 = dfdfkkjhklkfnajnvfo;
user types 3,
program prints:
klk is similar in both
starts at index 16, ends at 19 in string 1
starts at index 8, ends at 11 in string 2
What I have tried:
for (int i = 0; i <= search; i++) {
if (string1.regionMatches(i, string2, 0, substringlength)) {
found = true;
System.out.print("Match found!");
break;
}
}
I would have done more but I am at a complete stand still and do not know what to do; I am fairly new at coding.
I am guessing the way to do this is to use the LCS algorithm (Longest Common subsequence) and at the end just take the first X amount of Chars the algorithm gives you. (ofcourse this isn't the most computational fastest but the algorithm is almost completely written by others)
As an example LCS(computer , uouthgr) will give you a string value of "outr" if the user wanted only 3 chars give him the subString of "out".
Here is the LCS code I found on the net (it need modifications to serve your purpose):
public class LCS {
public static void main(String[] args) {
String x = StdIn.readString();
String y = StdIn.readString();
int M = x.length();
int N = y.length();
// opt[i][j] = length of LCS of x[i..M] and y[j..N]
int[][] opt = new int[M+1][N+1];
// compute length of LCS and all subproblems via dynamic programming
for (int i = M-1; i >= 0; i--) {
for (int j = N-1; j >= 0; j--) {
if (x.charAt(i) == y.charAt(j))
opt[i][j] = opt[i+1][j+1] + 1;
else
opt[i][j] = Math.max(opt[i+1][j], opt[i][j+1]);
}
}
// recover LCS itself and print it to standard output
int i = 0, j = 0;
while(i < M && j < N) {
if (x.charAt(i) == y.charAt(j)) {
System.out.print(x.charAt(i));
i++;
j++;
}
else if (opt[i+1][j] >= opt[i][j+1]) i++;
else j++;
}
System.out.println();
}
}
for more detail I recommend to read:
https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
but if you are like me I will recommend more to look for a video on the subject in youtube!

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

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);

Java - Repeat Function for Specific Numbers

I am exceptionally new to programming, but I am working on improving my skills as a programmer. Recently, I gave myself the challenge to determine what multiples of a given number are made up of distinct digits. I have gotten most of it to work, but I still need to make the code apply for every number that is a multiple of the input one. The code I have working so far is as follows:
Integer numberA = 432143;
Integer numberB = numberA;
Integer[] digitArray = new Integer[numberA.toString().length()];
int index;
for (index = 0; index < digitArray.length; index++) {
digitArray[index] = (numberA % 10);
numberA /= 10;
}
int repeats = 0;
for (int i = 0; i < digitArray.length; i++) {
for (int j = 0; j < digitArray.length; j++) {
if ((i != j) && (digitArray[i]==digitArray[j])) repeats = repeats + 1;
}
}
if (repeats == 0) {
System.out.println(numberB);
}
This will determine if the number is made up of distinct digits, and, if it is, print it out. I have spent quite a bit of time trying to make the rest of the code work, and this is what I've come up with:
Integer number = 1953824;
Integer numberA = number;
Integer numberB = numberA;
for (Integer numberC = number; numberC.toString().length() < 11;
numberC = numberC + number) {
Integer[] digitArray = new Integer[numberA.toString().length()];
int index;
for (index = 0; index < digitArray.length; index++) {
digitArray[index] = (numberA % 10);
numberA /= 10;
}
int repeats = 0;
for (int i = 0; i < digitArray.length; i++) {
for (int j = 0; j < digitArray.length; j++) {
if ((i != j) && (digitArray[i]==digitArray[j])) repeats = repeats + 1;
}
}
if (repeats == 0) {
System.out.println(numberB);
}
}
I can't figure out why, but his just prints whatever the number is a bunch of times if it is made up of distinct digits, and leaves it blank if it is not. If anyone could tell me why this is occurring, or even tell me what I need to do to fix it, that would be superb. Remember, I am very new to programming, so please give a short explanation for any terms you use that are at all out of the ordinary. I am eager to learn, but I currently know very little. Thank you for your time, and I greatly appreciate any and all help you can give me.
You assign the value of numberA to numberB (which is the value of number) right before the for loop. After that, numberB is never modified or assigned to a new value, so for every pass through the for loop, you're simply printing the value of numberB, which is always 1953824 in this case.
There are several corrections that can be made to achieve the result you desire, while cleaning up the code a little. The first thing is to change the print statement to print the correct number:
System.out.println(numberC);
Since numberC is the variable that is being updated by the for loop, that's what you'll want to conditionally print out if there are no repeat digits. Since we've replaced numberB with numberC, that means numberB is not longer needed, you can delete the declaration for it.
Now, the next issue is when you're defining the digital array - you should use the length of numberC, not numberA. Also, inside the for loop, you should assign numberA the value of numberC, or else eventually nothing but 0s will be stored in your digitArray. Overall, here's what it should look like.
Integer number = 1953824;
Integer numberA = number;
for (Integer numberC = number; numberC.toString().length() < 11;
numberC = numberC + number) {
Integer[] digitArray = new Integer[numberC.toString().length()];
numberA = numberC;
int index;
for (index = 0; index < digitArray.length; index++) {
digitArray[index] = (numberA % 10);
numberA /= 10;
}
int repeats = 0;
for (int i = 0; i < digitArray.length; i++) {
for (int j = 0; j < digitArray.length; j++) {
if ((i != j) && (digitArray[i] == digitArray[j]))
repeats = repeats + 1;
}
}
if (repeats == 0) {
System.out.println(numberC);
}
}
This should produce the desired result. It seems to work on my machine :)
If you want, you can take Jeffrey's suggestion and change the Integer to the primitive int to avoid the overhead of boxing. However, you still need to use the Integer class to use the toString() method, but you can accomplish that using Integer.valueOf():
Integer.valueOf(numberC).toString()
So if I understand correctly you are trying to find out if certain multiple exists within your number. Instead of constantly dividing by 10 instead use the modulus symbol. You can even embed it in conditional statements.
For example:
if(numberOne % 2 == 0)
Then we know that numberOne divided by 2 has a remainder of zero and is thus a multiple of 2

Categories

Resources