I'm working on a homework assignment that requires me to compare two strings and determine if they're in alphabetical order.
I plan to write a method that will take two strings as arguments, (String a, String b) and return either 1, 0, or -1 (so, an int) signalling whether a > b, a < b, or otherwise (the 0 case).
For example, comparing ("boogie", "orange") would return a -1. since, boogie < orange.
My code so far is
public static int compare(String a, String b) {
for (int i = 0; i < a.length(); i++) {
for (int j = 0; j < b.length(); j++) {
char cha = a.charAt(i);
char chb = b.charAt(j);
if (cha < chb) {
return -1;
} else if (cha > chb) {
return 1;
}
}
return 0;
}
}
However, I am encountering numerous errors and cannot find fixes for the bugs. I'm also having difficulty finding a code for measuring if one word is longer than another (which affects alphabetical order) Can someone help me debug the code and point me in the right direction?
Many thanks in advance.
You don't need a nestd loop, since you don't want to compare every character of one String to every character of the other String.
You only need a single loop:
public static int compare(String a, String b)
{
int len = Math.min (a.length(),b.length());
for (int i = 0; i<len; i++) {
char cha = a.charAt(i);
char chb = b.charAt(i);
if (cha < chb) {
return -1;
} else if (cha > chb) {
return 1;
}
}
if (a.length() < b.length())
return -1;
else if (a.length() > b.length())
return 1;
else
return 0;
}
As for handling Strings of different lengths, if you find that the shorter of the 2 Strings is equal to the prefix of the longer String, you return -1 if a is the shorter String and 1 if b is shorter (since the shorter String should come before the longer one).
You can compare two char by using '-' operator rather than the '>'.
For example below.
public static int compare(String a, String b) {
return a.charAt(0) - b.charAt(0);
}
In your case, something like this.
public static int compare(char cha, char chb) {
if (cha-chb < 0) {
return -1;
} else if(chb - cha > 0){
return 1;
} else if(chb - cha == 0){
return 0;
}
return 0;
}
Related
Given two strings s and t , write a function to determine if t is an anagram of s.
Example 1:
Input: s = "anagram", t = "nagaram"
Output: true
Example 2:
Input: s = "rat", t = "car"
Output: false
example 3
"aad"
"cab"
Output
true
Expected
false
my 3 test case is giving output true why?
class Solution {
public boolean isAnagram(String s, String t) {
if (s.isEmpty() && t.isEmpty()) {
return true;
}
if (s.length() != t.length()) {
return false;
}
char[] a = s.toCharArray();
char[] b = t.toCharArray();
Arrays.sort(a);
Arrays.sort(b);
for (int i = 0; i <= a.length; i++) {
for (int j = 0; j <= b.length; j++) {
if (a[i] == b[j]) {
return true;
}
}
}
return false;
}
}
By using a nested for loop, you will iterate over every possible pair (i, j) with i and j an in idex in a and b respectively. Furthermore you use i++ and j++ twice, and thus you will skip the even indices. You can not return true from the moment a[i++] == b[j++] matches. In order to know if something is an anagram, you need to iterate over all elements. You can return false from the moment a[i] != b[i] however. Finally the bound should be i < a.length, not i <= a.length.
You thus need one for loop where you make a single increment and compare a[i] with b[i]:
public boolean isAnagram(String s, String t) {
if(s.length() != t.length()){
return false;
}
char[] a = s.toCharArray();
char[] b = t.toCharArray();
Arrays.sort(a);
Arrays.sort(b);
for(int i = 0; i < a.length; i++) {
if(a[i] != b[i]) {
return false;
}
}
return true;
}
You are just comparing the first letter of cab and rat which is a, and returning True, actually you need to check all letters.
Hence make the condition negative and swap the returns.
if(a[i++] !=b[j++]){
return false;
}
return true;
The above code will return false, when characters aren’t equal, hence the last line is reached only when all chars are equal.
Question Summary:
Given two String arrays, return an integer representing how many matches are between them (ignore duplicates).
Real Answer:
http://www.javaproblems.com/2013/11/java-ap-1-commontwo-codingbat-solution.html
My Code
public int commonTwo(String[] a, String[] b) {
int count = 0;
boolean done = false;
for (int i = 0; i<a.length-1; i++){
if(a[i].equals(a[i+1])){
i++;
for (String j:b)
if (a[i].equals(j) && !done){
done = true;
count++;
}
}
else{
for (String j:b)
if(a[i].equals(j) && !done){
done = true;
count++;
}
}
done = false;
if(i == a.length-2)
for (String j:b)
if (a[i+1].equals(j) && !done){
done = true;
count++;
}
}
return count;
}
Image of output: [1]: http://i.stack.imgur.com/0esjC.png
So what it was intended to do was to go through all of the array a,if it equals the next one then go to that index, then add to count if there's a match between the arrays. The done boolean was used to make it so it doesn't add to count if there're duplicates of b that matches a and to end it once a match is found.
Lastly,
if(i == a.length-2)
was intended to make it so if it's the second before the last index number (as the last index number won't be checked in some cases), and not the same as the last index number, then it would check for matches for the last index number after checking the one before the last essentially. I understand why both errors occur and was wondering what could be done to fix it, particularly for the second one/comments on the code. Also, a third issue I notice would be (["a"], ["a"]) → 1 but the code will result in 0.
This question can be done is linear time O(N) that is a single traversal of both arrays a and b.
You should increment i as long as same string appears.So
if(a[i].equals(a[i+1]))
i++;
should be replaced by
while(i+1<a.length&&a[i].equals(a[i+1])){
i++;}
Also you do not need to go through entire array b for a single string of array a since both are in alphabetical order.You should only compare the string from the array b as long there is no match.Once a match is found then you should remember that index and next time matching should continue from that index onwards for the array b
Also you don't need the boolean variable done.
Keeping these things in mind the correct code is:
public static int commonTwo(String[] a, String[] b) {
int count = 0;
int j=0,i;
for (i = 0; i<a.length-1&&j<b.length-1;){
//SKIP DUPLICATES FOR ARRAY a
while(i+1<a.length&&a[i].equals(a[i+1])){
i++;}
//SKIP DUPLICATES FOR ARRAY b
while(j+1<b.length&&b[j].equals(b[j+1])){
j++;}
//MATCH THE STRINGS FROM ARRAY a AND ARRAY b
while(i<a.length&&j<b.length&&a[i].compareTo(b[j])!=0)
{
//INCREMENT I IF STRING IN ARRAY a IS LESS THAN STRING IN ARRAY b
if(a[i].compareTo(b[j])<0)
++i;
//INCREMENT J IF STRING IN ARRAY b IS LESS THAN STRING IN ARRAY a
else ++j;
}
//IF ABOVE LOOP BREAKS BECAUSE OF MATCH
if(i<a.length&&j<b.length)
{count++; ++j; ++i;}
}
//IF THE LAST ELEMENT OF ARRAY a IS LEFT FOR COMPARISON
if(i==a.length-1)
{
while(j<b.length)
{
//SKIP DUPLICATES OF ARRAY b
while(j+1<b.length&&b[j].equals(b[j+1]))
++j;
if(a[i].equals(b[j]))
{++count;}
++j;
}
}
//IF THE LAST ELEMENT OF ARRAY b IS LEFT FOR COMPARISON
if(j==b.length-1)
{
while(i<a.length)
{
//SKIP DUPLICATES OF ARRAY a
while(i+1<a.length&&a[i].equals(a[i+1]))
++j;
if(a[i].equals(b[j]))
++count;
++i;
}
}
return count;
}
This is the simplest solution i could come up with that uses only one loop.
public int commonTwo(String[] a, String[] b) {
int count = 0;
int i = 0;
int j = 0;
String s = "";
while (i < a.length && j < b.length) {
if (a[i].compareTo(b[j]) < 0)
i++;
else if (a[i].equals(b[j]) && a[i] != s) {
s = a[i];
count++;
i++;
j++;
}
else j++;
}
return count;
}
public int commonTwo(String[] a, String[] b) {
int ctr = 0;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < b.length; j++) {
if (i > 0 && a[i] == b[j] && a[i] != a[i - 1]) {
ctr++;
break;
} else if (i == 0 && a[i] == b[j]) {
ctr++;
break;
}
}
}
return ctr;
}
In the following code the problem I am facing is how to make the inner loop start from a given index instead of 0 every time.
LOGIC:
substr = rohan;
mainstr = herohanda
The code first check the first character of substr i.e 'r' with every character of mainstr till it finds a match. When a match is found the program return to the outer loop and increments i to check if the 2nd charcater of substr (i.e o) matches the next character(the character next to the index where a match for 'r' was found) of the mainStr. The problem is how to start the inner loop from that next character. Here it is starting with the initial index (0) each time .
CODE:
public class SubstringInString {
public static void isSubstring(String subStr, String mainStr){
int flag = 0;
int counter = 0;
OUTER: for(int i = flag; i<subStr.length(); i = i+flag){
INNER: for(int j = 0; j< mainStr.length(); j=counter ){
if(subStr.charAt(i) == mainStr.charAt(j)){
counter++;
flag++;
continue OUTER;
}
else
{
if((mainStr.length() - i) >= subStr.length()){
counter ++;
flag = 0;
continue INNER;
}
else{
System.out.println("Main String does not contain the substring");
}
}
}
}
// System.out.println("Match found at " + j-subStr.length());
}
}
Please tell me what how to solve this and also if there is any better way to do the same.
Thanks in advance
Suppose we want to find out if s2 is a substring of s1.
There are 2 base cases:
length of s2 is 0: In this case, we can return true.
length of s2 is more than that of s1: We can return false.
The general approach is as follows: Iterate through each character of s1 and see if it matches with the first character of s2. If it does, then check if rest of the characters of s1 match with rest of the characters of s2. If so, return true. If the s1 is entirely explored with no matches found, return false.
Here is how it would look like in Java:
static boolean isSubstring(String s1, String s2){
int n1 = s1.length();
int n2 = s2.length();
if(n2 == 0) // Base Case 1
return true;
if(n2 > n1) // Base Case 2
return false;
for(int i = 0; i < s1.length(); i++)
if(s1.charAt(i) == s2.charAt(0)) // if first char matches
if(isRestMatch(i+1, s1, s2)) // check if rest match
return true;
return false;
}
static boolean isRestMatch(int start, String s1, String s2){
int n = s2.length();
for(int i = start, x = 1; i < n; i++, x++)
if(s1.charAt(i) != s2.charAt(x))
return false;
return true;
}
Technically, this solves the problem:
public static void isSubstring(String subStr, String mainStr){
return mainStr.matches(".*\\Q" + subStr + "\\E.*");
}
I've found this Java implementation
public String strStr(String haystack, String needle) {
int needleLen = needle.length();
int haystackLen = haystack.length();
if (needleLen == haystackLen && needleLen == 0)
return "";
if (needleLen == 0)
return haystack;
for (int i = 0; i < haystackLen; i++) {
// make sure in boundary of needle
if (haystackLen - i + 1 < needleLen)
return null;
int k = i;
int j = 0;
while (j < needleLen && k < haystackLen && needle.charAt(j) == haystack.charAt(k)) {
j++;
k++;
if (j == needleLen)
return haystack.substring(i);
}
}
return null;
}
I read solutions to the problem of generating all the permutations of a string (solution).
Can anyone explain how perm2 is different from perm1? (I feel the only difference is that perm1 tries to put each element in the first position while perm2 in the last one)
// print N! permutation of the characters of the string s (in order)
public static void perm1(String s) { perm1("", s); }
private static void perm1(String prefix, String s) {
int N = s.length();
if (N == 0) System.out.println(prefix);
else {
for (int i = 0; i < N; i++)
perm1(prefix + s.charAt(i), s.substring(0, i) + s.substring(i+1, N));
}
}
// print N! permutation of the elements of array a (not in order)
public static void perm2(String s) {
int N = s.length();
char[] a = new char[N];
for (int i = 0; i < N; i++)
a[i] = s.charAt(i);
perm2(a, N);
}
private static void perm2(char[] a, int n) {
if (n == 1) {
System.out.println(a);
return;
}
for (int i = 0; i < n; i++) {
swap(a, i, n-1);
perm2(a, n-1);
swap(a, i, n-1);
}
}
Also, if some letters are the same in the string, then some permutations will be the same? The only way I can think of to prevent this is to save the result in a hashset so as to keep only one instance of a permutation. Is there a better solution?
I expect that the justification for the second solution is efficiency. It uses character arrays rather than String objects and swaps characters at each step rather than creating a new String via concatenation.
In terms of functionality the only difference between the two solutions is the order in which the results will be output.
You are correct that this does not guarantee unique solutions if there are some duplicate characters in the input. Storing the results and checking uniqueness (by using a Set or directly via contains) would be the easiest way to avoid this if required.
An alternative, in the second solution, would be to check if a character has already been handled. This would avoid the overhead of storing a result set (which could be significant for long strings).
In second perm2 function:
if (n == 1) {
System.out.println(a);
return;
}
for (int i = n; i < a.length; i++) {
if (a[i] == a[n-1])
return;
}
for (int i = 0; i < n; i++) {
boolean duplicate = false;
for (int j = 0; !duplicate && j < i; j++)
duplicate = a[i] == a[j];
if (!duplicate) {
swap(a, i, n-1);
perm2(a, n-1);
swap(a, i, n-1);
}
}
I am writing a program with multiple methods, and one of them asks to find the index where the second strings starts in the rightmost area of the first string.
The method accepts two strings as parameters and returns the character index of the position where the second string begins in the rightmost area of the first.
For example:
IN: mississippi, ss
OUT: 5
The catch of this method is that I can only use charAt, substring and length from the String class, and no other class methods.
With the help of some users from this site, we came up with this:
public static int findInStr1(String s1, String s2) {
for (int i = 0; i < s1.length() - s2.length(); i++) {
boolean found = true;
for (int j = 0; j < s2.length(); j++) {
if (s1.charAt(i) != s2.charAt(j)) {
found = false;
break;
}
}
if (found) {
return i;
}
}
return -1;
}
The above method gives me the index where string 2 starts in string 1, but I am trying to code a method that gives me the index of where string 2 starts in the rightmost area of string 1.
You can adjust your method to scan the first String from the right to the left :
public static int findInStr1(String s1, String s2) {
for (int i = s1.length() - 1; i >= s2.length() - 1; i--) {
boolean found = true;
for (int j = s2.length() - 1; j >= 0; j--) {
if (s1.charAt(i-(s2.length()-1-j)) != s2.charAt(j)) {
found = false;
break;
}
}
if (found) {
return i-s2.length()+1;
}
}
return -1;
}