I'm trying to find a word from a dictonary list. The letters can be in any order, but any letter can be used only once. I already developed an algorithm in java on Android, but it doesn't really work.
--> all words in the dict list are already lowercased in my cause
Here is my existing code, but it won't show me the matching words as output, the returned list is always empty.
private int matches = 0;
private ArrayList<String> words;
private ArrayList<String> check(String charArr0) {
String charArr = charArr0.toLowerCase();
char[] cs0 = charArr.toCharArray();
ArrayList<Character> cs = new ArrayList<>();
for(char c : cs0)
cs.add(c);
all = words.size();
ArrayList<String> out = new ArrayList<>();
for(String w0 : words) {
String w = w0.toLowerCase();
int len = w.length();
if(len >= 2) {
//only if len is 2++
matches = 0;
checkNext(cs, 0, w, len);
//if matches are as high as words lenght, it is fully avaivable
if(matches >= len)
out.add(w);
}
}
return out;
}
private void checkNext(ArrayList<Character> cs, int pos, String w, int len) {
if(pos < len) {
char twc = w.charAt(pos);
boolean cont = false;
int cIdx = -1, curi = 0;
for(char c : cs) {
if(c == twc){
cont = true;
cIdx = curi;
break;
}
curi += 1;
}
if(cont) {
matches += 1;
cs.remove(cIdx);
checkNext(cs, pos + 1, w, len);
}
}
}
The question is, what the error in this code is and how could I possibly get a word from the list in a char array given (any char only used once, order doesn't matter)?
Because you define this rules :
//- The letters can be in any order
//- any letter can be used only once
I would like to sort the character of each word and check if they are equals or not :
List<String> dictionaryWords = ...;
String word = "word";
char[] wordChars = word.toCharArray();
Arrays.sort(wordChars);
List<String> foundWords = new ArrayList<>();
for(String w : dictionaryWords){
if(dictionaryWords.length() != wordChars.length)
continue;
char[] wordDictionaryChars = w.toCharArray();
Arrays.sort(wordDictionaryChars);
if(Arrays.equals(wordChars, wordDictionaryChars)){
foundWords.add(w);
}
}
Consider you have :
List<String> dictionaryWords = new ArrayList<>(Arrays.asList("drow", "hello"));
This will return :
[drow]
because when you order both word and drow it will gives you [d, o, r, w]
Related
So, I've been trying to get this program to pass both test cases. I'm supposed to make a list that contains the character that follows each non-tail occurrence of a pattern in a text.
Here is the code...
public static ArrayList<Character> getCharsThatFollowPattern (String text, String pattern)
{
ArrayList<Character> character = new ArrayList<Character>();
int i = 0;
while (i <= text.length())
{
int index = text.indexOf(pattern, i);
if (index + pattern.length() < text.length())
{
character.add(text.charAt(index + pattern.length()));
}
i = i + text.indexOf(pattern, index) + pattern.length();
}
return character;
}
Here are the test cases:
a) For this one, I get [b], but I'm supposed to get [b, b]
#Test(timeout = 2000)
public void testGetCharsThatFollowPattern ()
{
ArrayList<Character> list = new ArrayList<Character>();
list.add('b');
list.add('b');
ArrayList<Character> chars = PS5Library.getCharsThatFollowPattern("abababa", "aba");
assertEquals(list, chars);
}
b) For this one, I get [c, d] but I'm supposed to get [c, d, c]
#Test(timeout = 2000)
public void testGetCharsThatFollowPattern2 ()
{
ArrayList<Character> list = new ArrayList<Character>();
list.add('c');
list.add('d');
list.add('c');
ArrayList<Character> chars = PS5Library.getCharsThatFollowPattern("abcabdabcab", "ab");
assertEquals(list, chars);
}
Change your loop as follows:
public static ArrayList<Character> getCharsThatFollowPattern (String text, String pattern) {
ArrayList<Character> characters = new ArrayList<Character>();
int index = text.indexOf(pattern);
while (index >= 0) {
if (index + pattern.length() < text.length()) {
characters.add(text.charAt(index + pattern.length()));
}
index = text.indexOf(pattern, index + 1);
}
return characters;
}
index will return -1 when the pattern is not found any more, so you could use that as your check to exit the loop.
The second indexOf() is only doing + 1 due to the overlap you are expecting for abababawith pattern aba to return b,b.
The problem is that your code finds all separate occurrences (which is normally what would be desired) but what you actually want is to find all occurrences including those that overlap. To do this, you need to make sure that you only move by one character on each iteration instead of moving by the length of the match.
public static ArrayList<Character> getCharsThatFollowPattern (String text, String pattern) {
List<Character> characters = new ArrayList<>();
for (int i = 0; i < text.length(); i++) {
i = text.indexOf(pattern, i);
if (i < 0) break;
int charIndex = i + pattern.length();
if (charIndex >= text.length()) break;
characters.add(text.charAt(charIndex));
}
return characters;
}
I m trying to make a function that prints the number of characters common in given n strings. (note that characters may be used multiple times)
I am struggling to perform this operation on n strings However I did it for 2 strings without any characters repeated more than once.
I have posted my code.
public class CommonChars {
public static void main(String[] args) {
String str1 = "abcd";
String str2 = "bcde";
StringBuffer sb = new StringBuffer();
// get unique chars from both the strings
str1 = uniqueChar(str1);
str2 = uniqueChar(str2);
int count = 0;
int str1Len = str1.length();
int str2Len = str2.length();
for (int i = 0; i < str1Len; i++) {
for (int j = 0; j < str2Len; j++) {
// found match stop the loop
if (str1.charAt(i) == str2.charAt(j)) {
count++;
sb.append(str1.charAt(i));
break;
}
}
}
System.out.println("Common Chars Count : " + count + "\nCommon Chars :" +
sb.toString());
}
public static String uniqueChar(String inputString) {
String outputstr="",temp="";
for(int i=0;i<inputstr.length();i++) {
if(temp.indexOf(inputstr.charAt(i))<0) {
temp+=inputstr.charAt(i);
}
}
System.out.println("completed");
return temp;
}
}
3
abcaa
bcbd
bgc
3
their may be chances that a same character can be present multiple times in
a string and you are not supposed to eliminate those characters instead
check the no. of times they are repeated in other strings. for eg
3
abacd
aaxyz
aatre
output should be 2
it will be better if i get solution in java
You have to convert all Strings to Set of Characters and retain all from the first one. Below solution has many places which could be optimised but you should understand general idea.
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
List<String> input = Arrays.asList("jonas", "ton", "bonny");
System.out.println(findCommonCharsFor(input));
}
public static Collection<Character> findCommonCharsFor(List<String> strings) {
if (strings == null || strings.isEmpty()) {
return Collections.emptyList();
}
Set<Character> commonChars = convertStringToSetOfChars(strings.get(0));
strings.stream().skip(1).forEach(s -> commonChars.retainAll(convertStringToSetOfChars(s)));
return commonChars;
}
private static Set<Character> convertStringToSetOfChars(String string) {
if (string == null || string.isEmpty()) {
return Collections.emptySet();
}
Set<Character> set = new HashSet<>(string.length() + 10);
for (char c : string.toCharArray()) {
set.add(c);
}
return set;
}
}
Above code prints:
[n, o]
A better strategy for your problem is to use this method:
public int[] countChars(String s){
int[] count = new int[26];
for(char c: s.toCharArray()){
count[c-'a']++;
}
return count;
}
Now if you have n Strings (String[] strings) just find the min of common chars for each letter:
int[][] result = new int[n][26]
for(int i = 0; i<strings.length;i++){
result[i] = countChars(s);
}
// now if you sum the min common chars for each counter you are ready
int commonChars = 0;
for(int i = 0; i< 26;i++){
int min = result[0][i];
for(int i = 1; i< n;i++){
if(min>result[j][i]){
min = result[j][i];
}
}
commonChars+=min;
}
Get list of characters for each string:
List<Character> chars1 = s1.chars() // list of chars for first string
.mapToObj(c -> (char) c)
.collect(Collectors.toList());
List<Character> chars2 = s2.chars() // list of chars for second string
.mapToObj(c -> (char) c)
.collect(Collectors.toList());
Then use retainAll method:
chars1.retainAll(chars2); // retain in chars1 only the chars that are contained in the chars2 also
System.out.println(chars1.size());
If you want to get number of unique chars just use Collectors.toSet() instead of toList()
Well if one goes for hashing:
public static int uniqueChars(String first, String second) {
boolean[] hash = new boolean[26];
int count = 0;
//reduce first string to unique letters
for (char c : first.toLowerCase().toCharArray()) {
hash[c - 'a'] = true;
}
//reduce to unique letters in both strings
for(char c : second.toLowerCase().toCharArray()){
if(hash[c - 'a']){
count++;
hash[c - 'a'] = false;
}
}
return count;
}
This is using bucketsort which gives a n+m complexity but needs the 26 buckets(the "hash" array).
Imo one can't do better in regards of complexity as you need to look at every letter at least once which sums up to n+m.
Insitu the best you can get is imho somewhere in the range of O(n log(n) ) .
Your aproach is somewhere in the league of O(n²)
Addon: if you need the characters as a String(in essence the same as above with count is the length of the String returned):
public static String uniqueChars(String first, String second) {
boolean[] hash = new boolean[26];
StringBuilder sb = new StringBuilder();
for (char c : first.toLowerCase().toCharArray()) {
hash[c - 'a'] = true;
}
for(char c : second.toLowerCase().toCharArray()){
if(hash[c - 'a']){
sb.append(c);
hash[c - 'a'] = false;
}
}
return sb.toString();
}
public static String getCommonCharacters(String... words) {
if (words == null || words.length == 0)
return "";
Set<Character> unique = words[0].chars().mapToObj(ch -> (char)ch).collect(Collectors.toCollection(TreeSet::new));
for (String word : words)
unique.retainAll(word.chars().mapToObj(ch -> (char)ch).collect(Collectors.toSet()));
return unique.stream().map(String::valueOf).collect(Collectors.joining());
}
Another variant without creating temporary Set and using Character.
public static String getCommonCharacters(String... words) {
if (words == null || words.length == 0)
return "";
int[] arr = new int[26];
boolean[] tmp = new boolean[26];
for (String word : words) {
Arrays.fill(tmp, false);
for (int i = 0; i < word.length(); i++) {
int pos = Character.toLowerCase(word.charAt(i)) - 'a';
if (tmp[pos])
continue;
tmp[pos] = true;
arr[pos]++;
}
}
StringBuilder buf = new StringBuilder(26);
for (int i = 0; i < arr.length; i++)
if (arr[i] == words.length)
buf.append((char)('a' + i));
return buf.toString();
}
Demo
System.out.println(getCommonCharacters("abcd", "bcde")); // bcd
I have written this code that replaces the characters in a string with a custom supplied alphabet:
//Replaces characters in string with custom alphabet.
public static String getStringWithCustomAlphabet(String string, String customAlphabet){
String shiftedString = "";
//Loop through every character in #plainText
for (int i = 0; i < string.length(); i++) {
//Store current character of loop in #charToAdd
char charToAdd = string.charAt(i);
int index = getAlphabet().indexOf(charToAdd);
//If index is valid
if (index != -1) charToAdd = customAlphabet.charAt(index);
//Add the character to #cipherText
shiftedString += charToAdd;
}
return shiftedString;
}
public static String getAlphabet() {
return "abcdefghijklmnopqrstuvwxyz ";
}
This code works. However, I want to be able to use not only a String alphabet but an integer alphabet. So, for example:
int[] numberArray {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26};
getStringWithCustomAlphabet("abcxyz", numberArray); //Should return 0,1,2,23,24,25
Maybe there is some way to simply this code and not use a for loop?
Strategy pattern may save you a lot of time and give you maximum flexibility. Suppose that we define an AlphabetConverter interface, as:
#FunctionalInterface
interface AlphabetConverter {
String convert(char ch);
}
Then, define the convertAlphabet method accepting an AlphabetConverter, as:
public String convertAlphabet(String actual, AlphabetConverter converter) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < actual.length(); i++) {
sb.append(converter.convert(actual.charAt(i)));
}
return sb.ToString();
}
Now, you can implement AlphabetConverter, one for replacement with String alphabet, and one for int array, or even use a lambda function.
For lower case use this :
String str = "abcdef";
char[] ch = str.toCharArray();
for (char c : ch) {
int temp = (int) c;
int temp_integer = 96; //for lower case
if (temp <= 122 & temp >= 97)
System.out.print(temp-temp_integer);
}
Output will be -:123456
For Upper case :
String str = "DEFGHI";
char[] ch = str.toCharArray();
for (char c : ch) {
int temp = (int) c;
int temp_integer = 64; //for upper case
if (temp <= 90 & temp >= 65)
System.out.print(temp-temp_integer);
}
Output Will be -:456789
I wrote that code and it's working. But I need to refactor it. I can use only simple methods for solving the problem, for example: "for" loops and simple array.
public class Anagram {
public static void main(String[] args) throws IOException {
Anagram anagrama = new Anagram();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));) {
System.out.println("Enter word or phrase: ");
String userText = reader.readLine();
String resultAnagrama = anagrama.makeAnagram(userText);
System.out.println("Result of Anagrama : " + resultAnagrama);
}
}
This method take user's text and make anagram, but all non-letters should stay on the same places
/**
* #param text
* #return reversed text and all non-letter symbols stay on the same places
*/
public String makeAnagram(String text) {
HashMap<Integer, Character> mapNonLetters;
String[] textFragments = text.split(" ");
StringBuilder stringBuilder = new StringBuilder();
//Check each elements of array for availability symbols and make reverse of elements
for (int i = 0; i < textFragments.length; i++) {
char[] arrayCharacters = textFragments[i].toCharArray();
mapNonLetters = saerchNonLetters(arrayCharacters); // search symbols
StringBuilder builderAnagramString = new StringBuilder(textFragments[i]);
//Delete all non-letters from element of array
int reindexing = 0;
for (HashMap.Entry<Integer, Character> entry : mapNonLetters.entrySet()) {
int key = entry.getKey();
builderAnagramString.deleteCharAt(key - reindexing);
reindexing ++;
}
builderAnagramString.reverse();
//Insert all non-letters in the same places where ones stood
for (HashMap.Entry<Integer, Character> entry : mapNonLetters.entrySet()) {
int key = entry.getKey();
char value = entry.getValue();
builderAnagramString.insert(key, value);
}
textFragments[i] = builderAnagramString.toString();
stringBuilder.append(textFragments[i]);
if (i != (textFragments.length - 1)) {
stringBuilder.append(" ");
}
mapNonLetters.clear();
}
return stringBuilder.toString();
}
This method search all non-letters from each worв of user's text
/**
* Method search symbols
* #param arrayCharacters
* #return HashMap with symbols found from elements of array
*/
public HashMap<Integer, Character> saerchNonLetters(char[] arrayCharacters) {
HashMap<Integer, Character> mapFoundNonLetters = new HashMap<Integer, Character>();
for (int j = 0; j < arrayCharacters.length; j++) {
//Letters lay in scope 65-90 (A-Z) and 97-122 (a-z) therefore other value is non-letter
if (arrayCharacters[j] < 65 || (arrayCharacters[j] > 90 && arrayCharacters[j] < 97) ||
arrayCharacters[j] > 122) {
mapFoundNonLetters.put(j, arrayCharacters[j]);
}
}
return mapFoundNonLetters;
}
}
public class Anagram {
public static void main(String[] args) {
String text = "!Hello123 ";
char[] chars = text.toCharArray();
int left = 0;
int right = text.length() - 1;
while (left < right) {
boolean isLeftLetter = Character.isLetter(chars[left]);
boolean isRightLetter = Character.isLetter(chars[right]);
if (isLeftLetter && isRightLetter) {
swap(chars, left, right);
left++;
right--;
} else {
if (!isLeftLetter) {
left++;
}
if (!isRightLetter) {
right--;
}
}
}
String anagram = new String(chars);
System.out.println(anagram);
}
private static void swap(char[] chars, int index1, int index2) {
char c = chars[index1];
chars[index1] = chars[index2];
chars[index2] = c;
}
}
If I understand correctly and you need only 1 anagram, this should work:
String originalString = "This is 1 sentence with 2 numbers!";
System.out.println("original: "+originalString);
// make a mask to keep track of where the non letters are
char[] mask = originalString.toCharArray();
for(int i=0; i<mask.length; i++)
mask[i] = Character.isLetter(mask[i]) ? '.' : mask[i];
System.out.println("mask: "+ new String(mask));
// remove non letters from the string
StringBuilder sb = new StringBuilder();
for(int i=0; i< originalString.length(); i++) {
if(mask[i] == '.')
sb.append(originalString.charAt(i));
}
// find an anagram
String lettersOnlyAnagram = sb.reverse().toString();
// reinsert the non letters at their place
int letterIndex = 0;
for(int i=0; i<mask.length; i++) {
if(mask[i] == '.') {
mask[i] = lettersOnlyAnagram.charAt(letterIndex);
letterIndex++;
}
}
String anagram = new String(mask);
System.out.println("anagram: "+ anagram);
It prints out:
original: This is 1 sentence with 2 numbers!
mask: .... .. 1 ........ .... 2 .......!
anagram: sreb mu 1 nhtiwecn etne 2 ssisihT!
I have 2 strings :
first= "BSNLP"
second = "PBN" (or anything that user enters).
Requirement is , O/P should return me the string with only those characters in first but not in second.
Eg. in this case O/P is SL
Eg2.
first = "ASDR"
second = "MRT"
, o/p = "ASD"
For this, the coding I have developed:
String one = "pnlm";
String two ="bsnl";
String fin = "";
for(int i =0; i<one.length();i++)
{
for(int j=0;j<two.length();j++)
{
//System.out.print(" "+two.charAt(j));
if(one.charAt(i) == two.charAt(j))
{
fin+=one.charAt(i);
}
}
}
ch=removeDuplicates(fin);
System.out.print(" Ret ::"+fin);
System.out.println("\n Val ::"+ch);
CH gives me the string with equal characters, but using this logic i cant get the unequal characters.
Can anyone please help?
You can use the Set interface to add all the second array of character so you can check it there later.
sample:
String one = "ASDR";
String two ="MRT";
StringBuilder s = new StringBuilder();
Set<Character> set = new HashSet<>();
for(char c : two.toCharArray())
set.add(c); //add all second string character to set
for(char c : one.toCharArray())
{
if(!set.contains(c)) //check if the character is not one of the character of second string
s.append(c); //append the current character to the pool
}
System.out.println(s);
result:
ASD
I have simple exchange your logic, see:
String one = "pnlm";
String two = "bsnl";
String fin = "";
int cnt;
for (int i = 0; i < one.length(); i++) {
cnt = 0; // zero for no character equal
for (int j = 0; j < two.length(); j++) {
// System.out.print(" "+two.charAt(j));
if (one.charAt(i) == two.charAt(j)) {
cnt = 1; // ont for character equal
}
}
if (cnt == 0) {
fin += one.charAt(i);
}
}
System.out.print(" Ret ::" + fin);
o/p: Ret ::pm.
public static void main(String[] args)
{
String one = "ASDR";
String two ="MRT";
String fin = unique(one, two);
System.out.println(fin);
}
private static String unique(final String one,
final String two)
{
final List<Character> base;
final Set<Character> toRemove;
final StringBuilder remaining;
base = new ArrayList<>(one.length());
toRemove = new HashSet<>();
for(final char c : one.toCharArray())
{
base.add(c);
}
for(final char c : two.toCharArray())
{
toRemove.add(c);
}
base.removeAll(toRemove);
remaining = new StringBuilder(base.size());
for(final char c : base)
{
remaining.append(c);
}
return (remaining.toString());
}
Iterate over the first string
For each character, check if the second string contains it
If it doesn't, add the caracter to a StringBuilder
Return stringBuilder.toString()