单词"未售出" &安培; "筒仓"是"阴险地"这个词的子字谜。也就是说,它们可以使用来自"阴险地"的字母拼写。显然还有更多,这个概念是在澳大利亚'中发现的文字游戏的基础。报纸。
我试图编写一个带有两个参数的程序 - 一个单词,另一个可能是这个单词的子字形,如果是,则返回true。到目前为止,这就是我所拥有的:
public boolean isAnswer(String word, String base)
ArrayList<Character> characters = new ArrayList<>();
for(char x : base.toCharArray)
{
characters.add(x)
}
for(char y : word.toCharArray)
{
if(characters.contains(x))
{
characters.remove(x)
}
else
{
return false;
}
return true;
}
它确实有效,但是如果我循环浏览英语词典中的每个单词,这将对内存产生极大的负担。如何在不创建ArrayList局部变量的情况下执行此操作?
答案 0 :(得分:0)
如果您想更好地考虑现有节目,请考虑使用 SET 而不是 LIST
修改强>
然而,这种优化可能不适用于其中一条评论指出的条件。
EX - 当base
只有&#34; ab&#34; &安培; word
有&#34; aab&#34;
答案 1 :(得分:0)
您可以直接替换base
。这不是很有效并创建了很多String
个对象,但它很容易阅读:
public boolean isAnswer(String word, String base)
{
for (char ch : word.toCharArray())
{
base = base.replaceFirst("" + ch, "");
}
return base.trim().length() == 0;
}
答案 2 :(得分:0)
您的代码错过了许多 {} ,; ,(),它无法清楚地编译和工作^^,以及我改变了&#34;的顺序,如果&#34;以及如何添加所有base
public boolean isAnswer(String word, String base) {
ArrayList<Character> characters = new ArrayList<>();
characters.addAll(Arrays.asList(base.toCharArray()));
for (char y : word.toCharArray()) {
if (!characters.contains(y)) {
return false;
}
characters.remove(y);
}
return true;
}
答案 3 :(得分:0)
我相信这将是应该快速运行并消耗最少内存的解决方案:
public class Snippet {
public static void main(String[] args) {
System.out.println(isAnswer("unsold", "insidiously"));
System.out.println(isAnswer("silo", "insidiously"));
System.out.println(isAnswer("silk", "insidiously"));
}
public static boolean isAnswer(String word, String base) {
char[] baseCharArr = base.toCharArray();
for (int wi = 0; wi < word.length(); wi++) {
boolean contains = false;
char wchar = word.charAt(wi);
for (int bi = 0; bi < baseCharArr.length; bi++) {
if (baseCharArr[bi]==wchar) {
baseCharArr[bi]='_'; // to not use this letter anymore we delete it using some sign that is non valid to from a word.
contains=true;
break;
}
}
if (!contains) {
return false;
}
}
return true;
}
}
答案 4 :(得分:0)
我建议你去java.util.Set以避免不必要的迭代。请找到以下代码:
private static boolean isSubAnagram() {
String str = "insidiously";
String anagram = "siloy";
Set<Character> set = new HashSet<Character>();
for(int i = 0 ; i < str.length() ; ++i){
set.add(new Character(str.charAt(i)));
}
int count = 0;
for(int i = 0 ; i < anagram.length() ; ++i){
if(set.contains(anagram.charAt(i))){
++count;
}
}
return count == anagram.length();
}
如果基本字符串中的字母数和所谓的字anagram需要相同,那么请转到:
private static boolean isSubAnagram() {
String str = "insidiously";
String anagram = "siloyl";
List<Character> list = new ArrayList<Character>();
for(int i = 0 ; i < str.length() ; ++i){
list.add(new Character(str.charAt(i)));
}
for(int i = 0 ; i < anagram.length() ; ++i){
char curChar = anagram.charAt(i);
if(list.contains(curChar)){
list.remove(new Character(curChar));
continue;
}else{
return false;
}
}
return true;
}
答案 5 :(得分:0)
一个优化可能是首先确保单词不长于基数。
public boolean isAnswer(String word, String base)
{
if (word.length() > base.length()) return false;
//...
}
我怀疑这些单词的长度是否完全相同there may be a faster way than comparing all of the characters:
public boolean isAnswer(String word, String base)
{
if (word.length() > base.length()) {
return false;
}
else if (word.length() == base.length()) {
return isFullAnagram(); // I'll leave the implementation of this up to you
}
//...
}
优化此功能的下一步是确保您不天真地尝试字典中的每个单词:
// Don't do this
public static void main(String... args)
{
String base = "something";
for (final String word : dictionary)
{
if (isAnswer(word, base)) // do something
}
}
// Don't do this
你有一个很大的优势,任何值得盐的字典文本文件都会被预先排序。一个基本的优化是将你的字典分成26个文件 - 一个用于以每个字母开头的单词 - 并跳过任何不可能匹配的文件。
public static void main(String... args)
{
String base = "something";
Set<Characters> characters = // populate with chars from base
for (final Section section : dictionary)
{
if (characters.contains(section.getChar())
{
for (final String word : section)
{
if (isAnswer(word, base)) // do something
}
}
}
}
接下来我要做的是看看这个过程的并行化。一个基本的方法是在自己的线程上运行每个部分(因此,对于大多数常见的英语单词,您最多可以查看大约12个线程)。
public static void main(String... args)
{
String base = "something";
Set<Characters> characters = // populate with chars from base
for (final Section section : dictionary)
{
if (characters.contains(section.getChar())
{
startMyThread(section, base);
}
}
}
你可以让线程返回Future
,你可以在最后检查。我会把这个细节留给你。
像CUDA这样的库允许您通过将计算推送到GPU来使用非常高的并发性。您可以同时运行数百个线程。在这种情况下,我不确定一个好的策略会是什么样子。
我正在假设你只需要处理罗马字母的26个字母。我在报纸上看到的每一个这样的游戏都避免了带有变音符号的词:咖啡馆,未婚妻,幼稚等。
答案 6 :(得分:0)
有很多答案,但没有一个是非常有效的。
对于子字谜候选人中的每个字母,我们搜索列表并删除字母。一次搜索需要线性时间。由于我们必须搜索每个字母,我们最终会得到二次时间复杂度。
有人建议使用集合而不是列表。在集合中搜索需要恒定的时间,因此我们最终会得到线性时间。但是,当同一个字母多次出现时,set方法会失败。
由于速度因素恒定,所提出的解决方案也很慢。当我们使用List<Character>
或Set<Character>
时,字符串的char
必须在Character
个对象中加框。创建和处理这些对象要比使用原始char
类型慢得多。
我们可以使用 multiset (也称为 bag )来表示单词中的字母。对于每个单词,我们创建一个多字节的字母,并检查该多重集是否是基本单词的字母multiset的子集。
示例强>
基础词"Food"
具有多组{f, o, o, d}
Word "do"
具有多组{d, o}
Word "dod"
具有多组{d, d, o}
。
{d, o}
是{f, o, o, d}
==&gt;的子集do
是food
的子字谜
{d, o, d}
不是{f, o, o, d}
==&gt;的子集dod
不是food
的子字谜。
由于我们知道,只有'a'
到'z'
的字符出现,我们使用int
数组来表示多集。 array[0]
的值是'a'
s的数量; array[1]
的值是'b'
的数量,依此类推。
array[1]
也可以写为array['b' - 'a']
示例强>
带有多集"Food"
的单词{f, o, o, d}
由数组
// Entry for: a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z
int[] multiSet = {0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0};
a
是b
的子集,当且仅当a[i] <= b[i]
适用于所有i
。
当我们在计算多集a
时进行子集测试时,我们不必检查所有26个数组条目,而只检查设置为大于零的值的条目。
我们要检查一个基本单词的很多单词。我们可以重复使用multiset作为基本单词,而不必一遍又一遍地计算它。
我们编写的方法不是编写返回true
或false
的方法,而是返回给定基本单词和给定字典(要检查的单词列表)的所有子字符的列表。
如果一个单词比基本单词长,则它不能是一个小圆形。在这种情况下,我们不必为该单词计算多重集。
public static List<String> subAnagrams(String base, List<String> dictionary) {
char[] usableChars = new char['z' - 'a'];
base = base.toLowerCase();
for (int i = 0; i < base.length(); ++i) {
++usableChars[base.charAt(i) - 'a'];
}
List<String> subAnagrams = new ArrayList<>();
for (String candidate : dictionary) {
boolean isSubAnagram = candidate.length() <= base.length();
candidate = candidate.toLowerCase();
char[] usedChars = new char['z' - 'a'];
for (int i = 0; isSubAnagram && i < candidate.length(); ++i) {
int charIndex = candidate.charAt(i) - 'a';
isSubAnagram = ++usedChars[charIndex] <= usableChars[charIndex];
}
if (isSubAnagram) {
subAnagrams.add(candidate);
}
}
return subAnagrams;
}
public static void main(String[] args) {
List<String> dict = new ArrayList<>();
dict.add("Do");
dict.add("Odd");
dict.add("Good");
dict.add("World");
dict.add("Foo");
System.out.println(subAnagrams("Food", dict));
}
打印[do, foo]