I am a beginner in Java and I will like to know if there's a way to compare characters in a char Array with other characters in another char Array in order to see if they have characters that match. Not to see if they contain exactly the same characters in the same sequence as most examples explain.
For instance:
char [] word1= {'a','c','f','b','e'};
char[] word2= {'a','b','c','d','e','h','j','f','i','m'};
and using maybe if statements to say that word1 contains the characters in word2 so it is correct. Else it is incorrect if word2 is missing at least one character that word1 has.
Try this. It will report if either array contains all the characters of the other. I used strings and converted them to arrays to facilitate the coding.
String[][] testData =
{ {"axyzx","xxyzaa"},
{"aaxyz","aaax"},
{"axa","a"},
{"arrs","asrrrs"},
{"acfbe","abcdehjfim"}};
for (String[] words : testData) {
boolean result = contains(words[0].toCharArray(), words[1].toCharArray());
String output = String.format("%s contains all %s","'"+words[0]+"'","'"+words[1]+"'");
System.out.printf("%34s - %b%n", output, result);
output = String.format("%s contains all %s","'"+words[1]+"'","'"+words[0]+"'");
result = contains(words[1].toCharArray(), words[0].toCharArray());
System.out.printf("%34s - %b%n%n", output, result);
}
Prints
'axyzx' contains all 'xxyzaa' - false
'xxyzaa' contains all 'axyzx' - true
'aaxyz' contains all 'aaax' - false
'aaax' contains all 'aaxyz' - false
'axa' contains all 'a' - true
'a' contains all 'axa' - false
'arrs' contains all 'asrrrs' - false
'asrrrs' contains all 'arrs' - true
'acfbe' contains all 'abcdehjfim' - false
'abcdehjfim' contains all 'acfbe' - true
Using a map, do a frequency count of the characters in the second array.
Now iterate thru the map using the first array, decrementing the character count when the character is found. When the count reaches 0, assign null to the value.
if map is now "empty", the first array contains all characters of second array.
// see if first array contains all of second array,
// regardless of order of the characters
public static boolean contains(char[] ch1, char[] ch2) {
// a smaller array cannot possible contain the same
// characters as a larger array
if (ch1.length < ch2.length) {
return false;
}
Map<Character,Integer> map = new HashMap<>();
// Do a frequency count
for(char c : ch2) {
map.compute(c, (k,v)->v == null ? 1 : v+1);
}
// now decrement count for each occurrence
// of character in first array, setting value to
// null when count reaches 0.
for(char c : ch1) {
map.computeIfPresent(c, (k,v)-> v <= 1 ? null : v-1);
}
return map.isEmpty();
}
I created a little snippet and think it is what you are looking for:
public class Main {
public static void main(String[] args) {
char[] word1= {'a','c','f','b','e'};
char[] word2= {'a','b','c','d','e','h','j','f','i','m'};
System.out.println(Contains(word1, word2));
}
private static boolean Contains(char[] arr1, char[] arr2) {
for (int i = 0; i < arr1.length; i++) {
boolean containsChar = false;
for (int j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) containsChar = true;
}
if (!containsChar) return false; // arr2 does not contain arr1[i]
}
return true;
}
}
Related
I want the user to input a string, then I want to check if each charachter in this string exists in an array of charachters I created. Even if it's not in the correct order.
The way I go about it is initialise the array of chars then through using the scanner have a String input from the user.
public static char[]aa={'A','C','D','E','F','G','H','I','K','L','M','N','P','Q','R','S','T','V','W','Y','U','O','B','J','Z','X'};
I created a function
private static void isValidSequence(String sequence, char[] k) {
outter :for (int j = 0; j < sequence.length(); j++) {
for (int i = 0; i < k.length; i++) {
if(sequence.charAt(j) == k[i]){
break;
} else {
System.out.println("invalid");
break outter;
}
}
}
}
What happens is that if for example the first letter of the the string doesn't match the first input of array it gives me an 'invalid' input. How can I go around that? and make it iterate through the whole array of characters before giving the invalid output.
An approach would be to sort your array, and then use the Binary Search Algorithm (BSA):
// sort the array once
Arrays.sort(aa);
// iterate over the input string
for(int i = 0, length = sequence.length(); i < length; i++) {
// the java implementation of the BSA returns negative numbers for not found elements
if(Arrays.binarySearch(aa, sequence.charAt(i)) < 0) {
// char was not found, break loop
return;
}
}
Note: If the array is not sorted / can not be sorted, then the BSA is useless and will produce undefined results.
Note 2: The BSA is faster (O(log n)) than simple iteration (O(n))
This can also be done as below :
char[]aa={'A','C','D','E','F','G','H','I','K','L','M','N','P','Q','R','S','T','V','W','Y','U','O','B','J','Z','X'};
String s = "aStrinG";
for (char c : s.toCharArray()) {
for (char c2 : aa) {
if (c2 == c) {
System.out.println("String char " + c + " exists in char array");
}
}
}
It produces :
String char S exists in char array
String char G exists in char array
Best way is to use SET instead of an Array. A set contains no duplicate elements and then simply you can use it using the method contains()
Using Java 9 (Unmodifiable Sets)
Set<Character> alphabetSet = Set.of('A', 'B', 'C');
//Another way
//Set<Character> alphabetSet = new HashSet<>(Arrays.asList('A', 'B', 'C'));
for(char c: sequence)
{
if(alphabetSet.contains(c)){
//do something
}
else{
//do something
}
}
Read more about Set:
https://docs.oracle.com/javase/7/docs/api/java/util/Set.html
To directly answer your question:
Solution 1:
Use continue instead of break this will print "invalid" each time a character is not in k.
Solution 2:
You can use a counter and increment it every time you have a character not in k, then outside the loop you will have visibility on how many invalid characters you have.
Solution 3:
If you want even more detail you can have a list of characters and add each invalid character to this list. This will give you visibility on exactly what characters are invalid.
I am not sure what you are trying to do so I don't know which method is better for you, you can also use an altogether approach using streams for example.
If you start using the Collection provided, you could use a Set to do your checks.
First, convert the array into the Set :
char[] array = "abcdefghijklmnopqrstuvwxyz".toCharArray();
Set<Character> setAllowed = new TreeSet<>();
for(char c : array){
setAllowed.add(c);
}
Then, you just have to iterate and check for each character. I would add another Set to retrieve every characters not allowed, giving a better output.
Set<Character> setError = new TreeSet<>();
for(char c : s.toCharArray()){
if(setAllowed.contains(c)){
setError.add(c);
}
}
Test :
public static void main(String[] args) {
String s = "foobar123";
char[] array = "abcdefghijklmnopqrstuvwxyz".toCharArray();
//INIT
Set<Character> setAllowed = new TreeSet<>();
Set<Character> setError = new TreeSet<>();
for(char c : array){
setAllowed .add(c);
}
//RESEARCH
for(char c : s.toCharArray()){
if(setAllowed.contains(c)){
setError.add(c);
}
}
//OUTPUT
System.out.println(setError);
}
[1, 2, 3]
I have the following two DNA strings "AACAGTTACC" and "TA-AGGT-CA", I would like to print a corresponding string of numbers, where two elements of two strings indicate a match (0), two elements indicate a mismatch (1) and one element indicates a gap (2).
For example the above two string would produce “10220010201”
I tried a loop through one of the string and check if string.charAt(i).contains("-") but it does not work.
String numbers = "";
for(int k = 0; k<adnX.length();k++) {
// I would like to append numbers to the numbers string
StdOut.printf("%s %s\n", adnX.charAt(k),adnY.charAt(k));
}
Two methods are presented here:
the main method and an auxiliary method.
The auxiliary checks if a given character is a valid DNA character.
The main method has two main parts.
Firstly, it initialises s1 and s2 with the required DNA strings and creates s3 which is an empty string. s3 will be used to store the corresponding numbers in case of a match, miss-match or gap. It assumes that both s1 and s2 have the same length.
In the first part it checks if the character at i-th position in s1 and s2 is a valid DNA character, if it's not it appends a 2 to s3.
In the second part (i.e., of the if statement, the else), it checks if the character at i-th position in s1 is the same as character at i-th position in s2. If it is then it appends a 0, otherwise it appends a 1.
The result is printed at the end.
public class DNACheck {
public static boolean isDNA(char c) {
String dna = "ATGC";
boolean inSequence = false;
for (int i = 0; i < dna.length() && !inSequence;i++) {
if (dna.charAt(i) == c) inSequence = true;
}
return inSequence;
}
public static void main(String[] args) {
String s1 = "AACAGTTACC";
String s2 = "TA-AGGT-CA";
String s3 = "";
for(int k = 0;k< s1.length();k++) {
// I would like to append numbers to the numbers string
if (!isDNA(s1.charAt(k)) || !isDNA(s2.charAt(k))) {
s3 = s3 + '2';
}
else {
if (s1.charAt(k) == s2.charAt(k)) {
s3 = s3 + '0';
}
else {
s3 = s3 + '1';
}
}
}
System.out.println(s3);
}
}
Assuming that inputs always have the same length and two gaps should result in a match:
String adnX = "AACAGTTACC";
String adnY = "TA-AGGT-CA";
StringBuilder numbers = new StringBuilder();
for (int i = 0; i < adnX.length(); i++) {
if (adnX.charAt(i) == adnY.charAt(i)) {
numbers.append(0);
} else if (adnX.charAt(i) == '-' || adnY.charAt(i) == '-') {
numbers.append(2);
} else {
numbers.append(1);
}
}
System.out.println(adnX);
System.out.println(adnY);
System.out.println(numbers);
Will output:
AACAGTTACC
TA-AGGT-CA
1020010201
I have a strange issue to print the first non repeated character from String.
If I put for example "sasso" as String it gives me back correctly: 'a'
but if I try with "sassa" I wonder why it gives me back: "s"
public class FirstChar {
public char findFirst(String s) {
boolean[] letters = new boolean[26];
char[] firstLetter = new char[26];
for (int i = 0; i < s.length(); i++) {
if (letters[s.charAt(i) - 97] &&
(firstLetter[0] != (s.charAt(i)))) {
System.out.println( firstLetter[0]);
return firstLetter[0];
}
letters[s.charAt(i) - 97] = true;
char c = (char) (s.charAt(i));
firstLetter[i] = c;
}
System.out.println(firstLetter[1]);
return firstLetter[1];
}
public static void main(String args[]) {
FirstChar obj = new FirstChar();
obj.findFirst("sassa");
}
}
You need to ensure that firstLetter acts as a queue of non repeating characters and remove from it, the moment repeated character is encountered. You are always returning character at 0th or 1st position without overwriting firstLetter array elements.
In case is sassa, when last character a is encountered, conditions in first if evaluate to true and thus return s which is the first character stored in the firstLetter array.
You need HashMap and Queue to achieve this
For example:
If you have a String "magikarp", and you tested it against "karma", this would be true, because all of the letters that make up "karma" can be found in "magikarp".
"kipp" would return false, because there is only one "p" in "magikarp."
This is the attempt that I have right now, but I don't think it's very efficient, and it doesn't return correctly for cases when there are multiple occurrences of one letter.
private boolean containsHelper(String word, String word2){
for (int i = 0; i < word2.length(); i ++){
if (!word.contains(String.valueOf(word2.charAt(i)))){
return false;
}
}
return true;
}
I don't write the program here, but let you know how to do. There are 2 ways to do this considering complexity:
1) If you are sure that you would be getting only a-z/A-Z characters in the string, then take a array of size 26. Loop thorough the first string and place the count of the character appeared in the respective index. Say for example you have String "aabcc". Now array would look like [2,1,2,0,...0]. Now loop through the second String, and at each character, subtract the 1 from the array at the respective character position and check the resultant value. If value is less than 0, then return false. For example you have "aacd". When you are at d, you would be doing (0-1), resulting -1 which is less than 0, hence return false.
2) Sort the characters in the each String, and then compare.
Since you are only checking for characters, it would be more efficient to use indexOf and to check if it return -1 as contains itself call indexOf but with some other trims...
However, I think it would be simplier to convert the String to an array of char and to remove them if they are found which would also handle the case of multiple occurences.
So you're algorithm woud look something like this :
private final boolean containsHelper(final String word, final String word2)
{
char[] secondWordAsCharArray = word2.toCharArray();
char[] firstWordAsCharArray = word.toCharArray();
Arrays.sort(firstWordAsCharArray);//Make sure to sort so we can use binary search.
int index = 0;
for(int i = 0; i++ < secondWordAsCharArray.length;)
{
index = Arrays.binarySearch(firstWordAsCharArray, secondWordAsCharArray[i]);//Binary search is a very performant search algorithm
if(index == -1)
return false;
else
firstWordAsCharArray[index] = ''; //A SENTINEL value, set the char a value you are sure that will never be in word2.
}
}
Basically, what I do is :
Convert both word to char array to make it easier.
Sort the char array of the word we inspect so we can use binary search.
Loop over all characters of the second word.
retrieve the index using the binary search algorithm (a very performant algorithm on char, the best from my knowledge).
if index is -1, it was not found so we can return false.
else make sure we unset the character.
You need to ensure that for any character c that appears in the second string, the number of times that c appears in the second string is no greater than the number of times that c appears in the first string.
One efficient way to tackle this is to use a hashmap to store the count of the characters of the first string, and then loop through the characters in the second string to check whether their total count is no greater than that in the first string. The time and space complexity are O(n) in the worst case, where n is the length of the input strings.
Here is the sample code for your reference:
import java.util.HashMap;
import java.util.Map;
public class HashExample {
public static void main(String[] args) {
System.out.println(containsHelper("magikarp", "karma")); // true
System.out.println(containsHelper("magikarp", "kipp")); // false
}
private static boolean containsHelper(String word, String word2) {
Map<Character, Integer> hm = new HashMap<>();
for (int i = 0; i < word.length(); i++) {
Character key = word.charAt(i);
int count = 0;
if (hm.containsKey(key)) {
count = hm.get(key);
}
hm.put(key, ++count);
}
for (int i = 0; i < word2.length(); i++) {
Character key = word2.charAt(i);
if (hm.containsKey(key)) {
int count = hm.get(key);
if (count > 0) {
hm.put(key, --count);
} else {
return false;
}
} else {
return false;
}
}
return true;
}
}
On possible algorithm is to remove all letters from your second word that don't occur in the first, sort both and then compare them.
Here is a reasonable way to achieve that in Java 8:
List<Integer> wordChars = word.chars().sorted().collect(Collectors.toList());
List<Integer> searchChars = search.chars()
.filter(wordChars::contains).sorted().collect(Collectors.toList());
return wordChars.equals(searchChars);
Given a List of Strings and an array of characters, return the longest String that contains only characters in the array.
I'm pretty sure I hosed it up. My first instinct was to use a regular expression but I don't think anybody gets those right the first time and without looking anything up.
Is there a tricky way of doing this using bitwise operators or something?
One idea would be to convert the char[] to a Set<Character> for O(1) containment tests, then simply loop over the list of strings and check if each particular string has only characters contained in the aforementioned set, keeping track of the longest string you find with this property.
If you have more information, you could make more optimizations. For example, if the strings themselves are very long but the list isn't, it might be beneficial to sort the list by length first, then start processing the strings longest first.
Is there a tricky way of doing this using bitwise operators or something?
If you have some sort of (small-ish) limit on the range of character that can be included in the char[], then you could potentially encode the whole thing in a single int/long, which would be a substitute for the Set<Character> I mentioned above. For example, let's say that only the characters from 'a' to 'z' will be included, then we can perform the encoding as follows:
long charset = 0;
for (char c : chars) {
charset |= (1 << (c - 'a'));
}
Now, to check if some character c was contained in the original char[], we can simply use:
if ((charset & (1 << (c - 'a'))) != 0) {
// c was in the original char[]
}
The following code uses binary search on a sorted char array to efficiently check, if all characters of the string exist in the char[]. Note that binary search on an array is pretty fast due to cache locality.
public String longest(char[] chars, List<String> strings) {
char[] sorted = Arrays.copyOf(chars, chars.length);
Arrays.sort(sorted);
String result = null;
for (String string : strings) {
if (containsAll(sorted, string)
&& (result == null || string.length() > result.length())) {
result = string;
}
}
return result;
}
public boolean containsAll(char[] sorted, String string) {
int length = string.length();
for (int i = 0; i < length; ++i) {
if (Arrays.binarySearch(sorted, string.charAt(i)) < 0) {
return false;
}
}
return true;
}
arshajii's first solution implementation:
/**
* #param list List of Strings.
* #param array Array of characters.
* #return The longest String from list that contains only characters in the array.
* If there is no such String, "" will be returned.
*/
private static String getLongest(List<String> list, Character[] array) {
String longest = "";
if (list == null || list.isEmpty() || array == null
|| array.length == 0) {
return longest;
}
Set<Character> set = new HashSet<Character>(Arrays.asList(array));
for (String word : list) {
boolean valid = true;
for (Character c : word.toCharArray()) {
if (!set.contains(c)) {
valid = false;
break;
}
}
if (valid && longest.length() < word.length()) {
longest = word;
}
}
return longest;
}
In case you are allowed to use Java 8:
public static Optional<String> longestValidWord(List<String> words, char[] validCharacters){
String allValidCharacters = new String(validCharacters);
return words.stream()
.filter(word -> word.chars().allMatch(c -> allValidCharacters.indexOf(c) > -1))
.max((s1, s2) -> Integer.compare(s1.length(), s2.length()));
}