I am writing a function that compares the number of vowels in the first half of a string and compares it with the second half, and returns a boolean based on if the number is equal.
Example:
Input: "book"
Output: true
because bo | ok, numVowels = 1, one 'o' in both halves.
My code that works is here
class Solution {
public boolean halvesAreAlike(String s) {
Set<Character> set = new HashSet<>(Arrays.asList('a','e','i','o','u','A','E','I','O','U'));
int vowelCount = 0, length = (s.length()%2 == 0) ? s.length()/2 : s.length()/2+1;
boolean pastHalf = false;
for (int i = 0; i < s.length(); i++) {
if (i == length) pastHalf = true;
if (pastHalf && set.contains(s.charAt(i))) vowelCount--;
else if (!pastHalf && set.contains(s.charAt(i))) vowelCount++;
}
return vowelCount == 0;
}
}
In the if (i == length) pastHalf = true; line, I am checking to see if I have hit the middle of the String. This is a simple boolean. I changed it to this ternary pastHalf = (i == length) ? true : false; and the output was wrong for the test case Ieai. Does anyone know why? I believe that the statements are equivalent.
if (i == length) pastHalf = true;
is most definitely NOT the same as
pastHalf = (i == length) ? true : false
In the first case, pastHalf is changed only when i is exactly equal to length, so as you iterate beyond length, pastHalf remains true.
In the second, at each iteration pastHalf is reset, so pastHalf is true only when i is exactly equal to length.
Other improvements:
length = (s.length()+1) % 2; // Think about this one carefully
and
if (set.contains(s.charAt(i)))
vowelCount += pastHalf ? -1 : +1;
Related
I have to write a method which returns true if three 3s are present in an integer array(provided they are not consecutive).
I have written this code here: However, it is returning true (which it should not do). Can someone point out my mistake?
arr[]={{4,3,5,2,3,3};
Also, this is a linear algorithm. Can it be done better?
public static boolean consecutiveThree(int[] arr) {
int x=0;
for(int i=0;i<arr.length-1;i++) {
if((arr[i]!=3 && arr[i+1]==3) || (arr[i]==3 && arr[i+1]!=3)) {
x++;
//continue;
}
if(x==3)
return true;
}
return false;
}
You said:
returns true if three 3s are present in an integer array(provided they are not consecutive)
I interpret that as having at least three 3s, and no two 3s are adjacent.
public static boolean hasThreeNonconsecutiveThrees(int... values) {
int count = 0, streak = 0;
for (int value : values) {
if (value != 3)
streak = 0;
else if (++streak == 2)
return false; // Found two consecutive (adjacent) 3s
else
count++;
}
return (count >= 3);
}
Test
System.out.println(hasThreeNonconsecutiveThrees(4,3,5,2,3,3)); // false
System.out.println(hasThreeNonconsecutiveThrees(4,3,5,3,2,3)); // true
System.out.println(hasThreeNonconsecutiveThrees(1,2,3,4,3)); // false
System.out.println(hasThreeNonconsecutiveThrees(4,3,5,3,3,3)); // false
Output
false
true
false
false
At worst case the correct array will end with ... 3 3 X 3. Unless the array is somewhat sorted or somewhat special you will have to look at every single element to reach the last three 3s. If the array is random, you need linear complexity since you have to review every single element in the array.
Your algorithm is not checking the whether arr[i-1] is '3'. That is your algorithm's mistake.
Try this:-
public static boolean consecutiveThree(int[] arr) {
int x = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 3) {
if (i == 0) { // zero 'th element do not have arr[i-1].
if(arr[i + 1] != 3) {
x++;
}
} else if (i == arr.length - 1) { // last element do not have arr[i+1].
if((arr[i - 1] != 3)) {
x++;
}
} else if ((arr[i + 1] != 3) && (arr[i - 1] != 3)) {
x++;
}
}
if (x == 3) // may be x >= 3
return true;
}
return false;
}
How does this particular recursion works
return (X.charAt(m-1) == Y.charAt(n-1) ? count(X, Y, m-1, n-1) : 0) + count(X, Y, m-1, n)
in the below code?
The below code will return the count of number of times the pattern appears in a given string as a subsequence.
class Subsequence {
public static int count(String X, String Y, int m, int n) {
if (m == 1 && n == 1)
return X.charAt(0) == Y.charAt(0) ? 1 : 0;
if (m == 0)
return 0;
if (n == 0)
return 1;
if (n > m)
return 0;
return (X.charAt(m - 1) == Y.charAt(n - 1) ? count(X, Y, m - 1, n - 1) : 0) + count(X, Y, m - 1, n);
}
public static void main(String[] args) {
String X = "subsequence";//input String
String Y = "sue";// pattern
System.out.print(count(X, Y, X.length(), Y.length()));
}
}
It works as below:
if(X.charAt(m-1) == Y.charAt(n-1))
return count(X, Y, m - 1, n - 1);
else
return 0; //since no match found here
Now, the above code is breakage of the first line of your return statement that uses ternary operator. Don't think that this is the complete break down of this code.
So, once you got this statement, the next step would be call this function again to find any matching characters starting from m- in first string and from n in the pattern string since we need to still match the whole pattern right from the start. However, if we find a match, we are just proceeding to match remaining available characters in both pattern and the string.
But to be honest, there are many better ways to code the pattern matching algorithm as compared to this approach.
You will often find that renaming your variables properly and adding some clarification comments works wonders.
public static int count(String string, String pattern, int stringLength, int patternLength) {
if (stringLength == 1 && patternLength == 1) {
// Two length=1 strings -> if they are equal then they match - obviously.
return (string.charAt(0) == pattern.charAt(0)) ? 1 : 0;
}
if (stringLength == 0) {
// No more string to search - no-match.
return 0;
}
if (patternLength == 0) {
// No more pattern to search - MATCH!
return 1;
}
if (patternLength > stringLength) {
// Can never find a pattern longer than the string.
return 0;
}
return ((string.charAt(stringLength - 1) == pattern.charAt(patternLength - 1)) ?
// Both end with same character - recurse to keep matching.
count(string, pattern, stringLength - 1, patternLength - 1)
// Not match.
: 0)
// ADD any matches further down the string.
+ count(string, pattern, stringLength - 1, patternLength);
}
Sadly the code is wrong somewhere - searching for sue in subsequence prints 7.
I believe it is called a "Ternary Operator", it is another way to do IF statements in a more compact way (ie if you do a load of them at the same time for readability). It has to have somewhere to give the return value (a variable or return statement for example)
As an example it can look like this
boolean test = (condition) ? true : false;
Which is the same as writing
boolean test;
if (condition) {
test = true;
} else {
test = false;
}
CodeHunter's answer is a good example of how the sample code you gave is turned back into an if statement.
What it is doing is:
(Psuedo)
function recursiveCount(stringStart, stringEnd, startLocation, endLocation) {
/* pre-checks */
// Total will be how many times it loops (1 + 1 + 1 + 1 + 1 basically what it is doing)
// If there is no more occurances of that string it adds 0 instead of 1, and the recursion breaks.
return (total + recursiveCount(stringStart, stringEnd, nextStartLocation, nextEndLocation)
}
Example:
I have a boolean array with N boolean inside. Which is the most efficient way to determine there are more than continuous M true flags, in the array?
Write some thing like (bA=booleanArray, for M=3)
(bA[0] && bA[1] && bA[2]) || (bA[1] && bA[2] && bA[3]) || ...
is really ugly.
And this can not be done with a VERY-LONG dynamic length array with dynamic least true flags to meet need. And maybe inefficient with few and scattered true?
Use a loop and a counter:
int count = 0;
for (boolean x: theArray){
if (x) {
count++;
if (count >= n) return true; // n is the count we are looking for
} else { count = 0; }
}
return false;
This is one approach, that allows for adjusting the number of consecutive entries, and the array is not fixed in length. The method hasConsecutiveTrue will loop over the array, looking for a value of true. If found, it increments the counter, otherwise sets it to 0. If the counter matches the expected amount, it returns true. Otherwise, it will return false. EDIT: based upon a comment, make so it will throw an IllegalArgumentException for an attempt to find <= 0 consecutive numbers, or if the input array is null/empty.
public static void main(String[] args)
{
int consecutive = 3;
boolean[] ba = new boolean[] { true, false, true, true, true, false};
System.out.println("found: " + hasConsecutiveTrue(ba, consecutive));
}
private static boolean hasConsecutiveTrue(boolean[] ba, int consecutive) throws IllegalArgumentException
{
// we will not attempt to process if the input <= 0; if 0 should return
// true, then modify the conditional statement as appropriate
if (consecutive <= 0) {
throw new IllegalArgumentException("Invalid input for consecutive: " +
consecutive);
}
if (ba == null || ba.length < 1) {
throw new IllegalArgumentException("No array to check!");
}
int count = 0;
boolean found = false;
for (boolean b : ba) {
count = ( b ? count + 1 : 0);
if (count == consecutive) {
found = true;
break;
}
}
return found;
}
Here's one using BitSet: if you're able to start with a BitSet, it will almost certainly be more efficient. If you have to convert from a boolean[] or byte[], it might not be.
// BitSet bits = BitSet.valueOf(bA);
int i = bits.nextSetBit(0);
while (i > -1 && i < bits.length()) {
int nextFalse = bits.nextClearBit(i);
if (nextFalse - nextTrue > N) return true;
i = bits.nextSetBit(nextFalse) + 1;
}
return false;
One option is to use a string with T + F in the location to determine the true/false setting of your array. Then use contains.
Example:
String booleanArray = "TTFFTFTFTFTTTFFT";
if ( !booleanArray.contains("TTT") ) // Pattern was found.
I'm new to java.
Can anybody tell me that is the easiest way to compare two string except one character?
like:
'test' 'text' //only one character different
should return true
==============================
like input:
'test' 'txxt' //two character different return false
should return false
I know we can compare with a for loop. Is there any other way to do that?
Thx for your help. : )
Assuming the Strings are the same size, here is a solution. This solution will need to be altered slightly for uneven String lengths
boolean compareStrings(String str1, String str2) {
if (str1.length() != str2.length())
return false;
int differences = 0;
for (int i = 0; i < str1.length(); i++) {
if(str1.charAt(i) != str2.charAt(i))
if(++differences > 1)
return false;
}
//if the execution is here, then there are 0, or 1 differences, so return true
return true;
}
Try this method.
It should work for every string combination but, depending on usage, maybe a performance tuning is needed.
public static boolean compare(String s1, String s2) {
if((s1 != null && s2==null) || (s1 == null && s2!=null)){
//exact one is null
return false;
}
if((s1 == null && s2==null) || s1.equals(s2)){
//both are null or equal
return true;
}
if(Math.abs(s1.length() - s2.length()) > 1){
//A different length of more than one is more than one difference, right ?
return false;
}
//Here you have two different strings. Maybe one is a character larger than the other.
if(s1.length() != s2.length()) {
//They differ in length, so they must be equal in the first minLen charcaters.
int minLen = Math.min(s1.length(), s2.length());
return s1.substring(0,minLen).equals(s2.substring(0,minLen));
}
//Here you have two different strings of the same length.
int diff = 0;
for(int i = 0; i < s1.length() && diff < 2; i++){
if(s1.charAt(i) != s2.charAt(i)){
diff++;
}
}
return diff < 2;
}
Im trying to write a method that takes in an ID of the form "xxxx-xxxx" (x being any number 1-9) and checks to see if the ID entered is valid. For example, 1111-1111 would be valid, but 111p-1111 or 11111-1111 would not be. However, after I have written this method, it comes out as true even when the ID is of the form 111p-1111.
public static boolean idCheck(String ID){
char[] idChar = ID.toCharArray();
boolean firstHalf = false;
boolean secHalf = false;
for (int i = 0; i < 5; ++i){//Check first half
if ((idChar[i] > 47 && idChar[i] < 58)){//Checks ascii vals to see if valid ID
firstHalf = true;
}
}
for (int i = 5; i < idChar.length; ++i){//Check second half
if ((idChar[i] > 47 && idChar[i] < 58)){//Checks ascii vals to see if valid ID
secHalf = true;
}
}
//If all values are valid, returns true.
if (firstHalf == true && secHalf == true && idChar[4] == '-' && ID.length() == 9){
return true;
}
return false;
}
Using a regular expression would be much simpler in this case:
\d{4}-\d{4}
In Java:
static boolean idCheck(String id) {
return id.matches("\\d{4}-\\d{4}");
}
If you're unfamiliar with regular expressions, here's an explanation:
\d Match a digit 0-9
{4} Repeat last token 4 times (matches 4 digits)
- Match a hyphen literally
\d Match a digit 0-9
{4} Repeat last token 4 times (matches 4 digits)
Your if statements only look at one number to determine if it sets the boolean to true. So if any of the numbers in each half are valid, the boolean will be set to true.
You are probably better off using regular expressions. regexr.com is a great resource to get started! :)
Something like:
[1-9]{4}-[1-9]{4} (You can also use \d)
You only check if there is at least one character that matches, not if any of the input characters are failing.
To have a quick solution that is easy to understand for any Java developer after you you could use a Regex and check if your input matches:
public static boolean idCheck(String id){
return Pattern.matches("\\d{4}-\\d{4}", id);
}
If you want to keep your way of checking you should start with true booleans and check if they stay true.
boolean firstHalf = true;
boolean secHalf = true;
and therefrom use firstHalf &= true for your updates and use a else{ firstHalf = false; } branch.
To keep your method I would prefer to always back out fast if you know the result:
public static boolean idCheck(String id)
{
//check length
if (id.length() != 9)
return false;
char[] idChar = id.toCharArray();
//check for dash
if (idChar[4] != '-')
return false;
//check first half
for (int i = 0; i < 5; ++i)
{
if (!(idChar[i] > 47 && idChar[i] < 58))
return false;
}
//check second half
for (int i = 5; i <= 10; ++i)
{
if (!(idChar[i] > 47 && idChar[i] < 58))
return false;
}
}