锁定老帖子 主题:给大家出道题,算法的
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (17)
|
|
---|---|
作者 | 正文 |
发表时间:2012-02-06
shimmey 写道 個人覺得素數的辦法仍然比較麻煩,而且計算量較大。考慮到整數是32位,只有26個字母。因此在不區分大小寫的情況下可以使用一位二進制位來標記一個字母.如果要區分大小寫,則可以考慮使用整數數組來解決。
具體的做法就是移位,移位的位數可由ASCII編碼來確定。 word_id |= 1 << (letter - 'a') 單詞ID 取或 1 向左移位 單詞中某一字母 字母a的ASCII值 這樣操作之后就可以取得整數類型的單詞ID,這個ID顯然是根據單詞當中所包括的字母確定出來的。 后面的事情就簡單了,下面給出了C的代碼。輸出的只是單詞的ID,并沒有嚴格按照樓主的形式給出輸出。 代碼如下: #include <stdio.h> #include <unistd.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <limits.h> #include <ctype.h> int main(int argc, char *argv[]) { char string[]="hat, top, potter, pot, pier, ripe"; char *p = string; int i; int j; int word[12]; int word_cnt = 0; memset( word, 0, sizeof(word) ); do { if( isalpha(*p) ) word[word_cnt] |= 1 << (*p-'a'); /* 關鍵步驟 */ if( *p == ',' ) word_cnt++; } while( *(++p) ); word_cnt++; printf( "%s\n", string ); for( i = 0; i < word_cnt; i++ ) { printf( "%d ", word[i] ); } printf( "\n" ); return 0; } 輸出結果: hat, top, potter, pot, pier, ripe 524417 573440 704528 573440 164112 164112 結果說明每個單詞已經按照字母分好了組 怎么说呢,我怀疑这样的移位是不是OK bcde对应的移位 是这样的 0001,0002,0003,0004 移位后是这样, 0010 0100 0110 1000然后再与对吧 我不管结果,总之对于2进制来说是1110对不 那么我再来一组 0010 0100 1110 1000 接着看呢,结果还是1110,我有N种变化都对应1110而且 N种不同的字符,所以,我个人认为不可靠! |
|
返回顶楼 | |
发表时间:2012-02-06
个人觉得这个算法有点问题,比如会认为 bottle 和botle是同一组:
shimmey 写道 個人覺得素數的辦法仍然比較麻煩,而且計算量較大。考慮到整數是32位,只有26個字母。因此在不區分大小寫的情況下可以使用一位二進制位來標記一個字母.如果要區分大小寫,則可以考慮使用整數數組來解決。
具體的做法就是移位,移位的位數可由ASCII編碼來確定。 word_id |= 1 << (letter - 'a') 單詞ID 取或 1 向左移位 單詞中某一字母 字母a的ASCII值 這樣操作之后就可以取得整數類型的單詞ID,這個ID顯然是根據單詞當中所包括的字母確定出來的。 后面的事情就簡單了,下面給出了C的代碼。輸出的只是單詞的ID,并沒有嚴格按照樓主的形式給出輸出。 代碼如下: #include <stdio.h> #include <unistd.h> #include <string.h> #include <time.h> #include <stdlib.h> #include <limits.h> #include <ctype.h> int main(int argc, char *argv[]) { char string[]="hat, top, potter, pot, pier, ripe"; char *p = string; int i; int j; int word[12]; int word_cnt = 0; memset( word, 0, sizeof(word) ); do { if( isalpha(*p) ) word[word_cnt] |= 1 << (*p-'a'); /* 關鍵步驟 */ if( *p == ',' ) word_cnt++; } while( *(++p) ); word_cnt++; printf( "%s\n", string ); for( i = 0; i < word_cnt; i++ ) { printf( "%d ", word[i] ); } printf( "\n" ); return 0; } 輸出結果: hat, top, potter, pot, pier, ripe 524417 573440 704528 573440 164112 164112 結果說明每個單詞已經按照字母分好了組 |
|
返回顶楼 | |
发表时间:2012-02-06
最后修改:2012-02-06
cucumber_pain 写道 这个排序是容易的吧,如果是从简单的说,我拿java的来看吧,
首先建立以个map 最后是linkedmap<String, linkedList<String>> 然后和2L说的一样,key使用排序过的每个字母做key,(当然,在这你可以写一个相似度的工具算法 前些天我在论坛上看到的那个算法。这里简单的话,就排序吧。equal,就加入到linkedList里面去吧) 然后遍历map,,遍历map下的linkedList,然后换行 你会发现其实很简单, 但是从难点的说.比如说某某楼说的,首先按照长度分队列,(首先减少了算法的复杂度。),然后再按素数之积做相似度算法,怎么说呢,那就是说把工具丢一边,自己写和这个题目,更加相近的算法,为了兴趣可以去试下啊 但是为了面试,我不得不说,那点点可贵的时间就为了你闭门造车么- - 有点滑稽啊! - - Agree. I think this is the most easiest and efficient algorithm until now. This algorithm takes O(N) time and O(N) space. By the way, Java Arrays.sort() takes O(logN) space and O(NlogN) time. I put the Java code here. public static boolean process(String[] array) { if(array == null) { return false; } if(array.length == 0) { return false; } if (array.length == 1) { System.out.println("Line: " + array[0]); return true; } // Generate fingerprint for each string HashMap hm = new HashMap(); for(String str: array) { String fp_key = getFingerprint(str); if (hm.containsKey(fp_key)) { List list = (List) hm.get(fp_key); list.add(str); } else { List list = new ArrayList(); list.add(str); hm.put(fp_key, list); } } // Print a set of strings which have the same fingerprint Set keys = hm.keySet(); Iterator it = keys.iterator(); while(it.hasNext()) { String fp_key = (String) it.next(); List list = (List) hm.get(fp_key); printWords(list); } return true; } // the way to generate fingerprint for a string really depends public static String getFingerprint(String str) { /* StringBuffer fp = new StringBuffer(); char[] array = str.toCharArray(); Arrays.sort(array); int count = 1; for(int i = 0; i < array.length - 1; i ++) { if (array[i] == array[i + 1]) { count ++; } else { fp.append(array[i]); fp.append(count); count = 1; } } fp.append(array[array.length - 1]); fp.append(count); return fp.toString(); */ char[] array = str.toCharArray(); Arrays.sort(array); String fp = new String(array); return fp; } public static void printWords(List list) { System.out.print("This line: "); Iterator it = list.iterator(); while(it.hasNext()) { System.out.print(it.next() + " "); } System.out.println(); } Please let me know if we can get better big O for both time and space. Thank you guys. |
|
返回顶楼 | |
发表时间:2012-02-06
seismosaurus 写道 利用素数乘积唯一性
import java.util.HashMap; import java.util.Map; public class PrintGroupsWithSameLetters { private static final int[] prime = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101 }; public static void main(String[] args) { String[] sample = { "hat", "top", "potter", "pot", "pier", "ripe" }; PrintGroupsWithSameLetters.PrintGroupsWithSameLetters(sample); } public static void PrintGroupsWithSameLetters(String[] words) { Map map = new HashMap(); for (int index = 0; index < words.length; index++) { PrintGroupsWithSameLetters.insertOrUpdate(map, words[index], getValue(words[index])); } System.out.println(map); } public static void insertOrUpdate(Map lib, String word, int value) { if (!lib.containsKey(value)) { lib.put(value, word); } else { lib.put(value, lib.get(value) + "," + word); } } public static int getValue(String word) { if (word == null || "".equals(word.trim())) { return -1; } word = word.toLowerCase(); int value = 1; char letter[] = word.toCharArray(); for (int index = 0; index < letter.length; index++) { int temp = letter[index] - 'a'; if (temp < 0 || temp > 25) { return -1; } value *= prime[temp]; } return value; } } I think this is pretty new idea for me. Could you please explain the idea in plain text ? Thanks |
|
返回顶楼 | |
发表时间:2012-02-06
给个clojure的代码吧:
user> (vals (group-by #(set %) ["hat","top","potter","pot","pier","ripe"])) (["hat"] ["top" "pot"] ["potter"] ["pier" "ripe"]) |
|
返回顶楼 | |
发表时间:2012-02-06
1.get the value of each word. A word's value is the product of each letter in it.like the value of "hat" is prime['h'-'a']*prime['a'-'a']*prime['t'-'a']
2.if Map already contains the key(it's the product above),then update the corresponding value.Otherwise just put it into Map jimwallet 写道 seismosaurus 写道 利用素数乘积唯一性
import java.util.HashMap; import java.util.Map; public class PrintGroupsWithSameLetters { private static final int[] prime = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101 }; public static void main(String[] args) { String[] sample = { "hat", "top", "potter", "pot", "pier", "ripe" }; PrintGroupsWithSameLetters.PrintGroupsWithSameLetters(sample); } public static void PrintGroupsWithSameLetters(String[] words) { Map map = new HashMap(); for (int index = 0; index < words.length; index++) { PrintGroupsWithSameLetters.insertOrUpdate(map, words[index], getValue(words[index])); } System.out.println(map); } public static void insertOrUpdate(Map lib, String word, int value) { if (!lib.containsKey(value)) { lib.put(value, word); } else { lib.put(value, lib.get(value) + "," + word); } } public static int getValue(String word) { if (word == null || "".equals(word.trim())) { return -1; } word = word.toLowerCase(); int value = 1; char letter[] = word.toCharArray(); for (int index = 0; index < letter.length; index++) { int temp = letter[index] - 'a'; if (temp < 0 || temp > 25) { return -1; } value *= prime[temp]; } return value; } } I think this is pretty new idea for me. Could you please explain the idea in plain text ? Thanks |
|
返回顶楼 | |
发表时间:2012-02-07
引用 每个字母对应一个素数, 然后把所有单词响应的素数相乘,然后把结果做比较,结果相同的,说明这个单词和另一个单词又相同的字母 高人 |
|
返回顶楼 | |
发表时间:2012-02-07
这个问题细分为两个问题:
一、两个字符串是否相同? 算法: 第一步,判断两个字符串长度是否相同? 第二步,计算出每个字符串中所有字符的ascii码值之和,判断两个字符串对应的和是否相同?(大部分情况到这里就能得到结果) 第三步,计算两个字符串包含的字符和对应字符出现次数是否相同?(少部分会到达第三步) 二、怎么为格式化输出准备结果? 顺序遍历字符串数组,与结果Map<String,List<String>>中的key依次比较,如果相同,则在当前key对应的value中添加当前字符串,map中都没有该字符串时,往map中添加一个。 不知道这样描述清楚没~,这个算法,二中的处理可能不够高效。字符串数量多之后就慢了。 |
|
返回顶楼 | |
发表时间:2012-02-08
cucumber_pain 写道 这个排序是容易的吧,如果是从简单的说,我拿java的来看吧,
首先建立以个map 最后是linkedmap<String, linkedList<String>> 然后和2L说的一样,key使用排序过的每个字母做key,(当然,在这你可以写一个相似度的工具算法 前些天我在论坛上看到的那个算法。这里简单的话,就排序吧。equal,就加入到linkedList里面去吧) 然后遍历map,,遍历map下的linkedList,然后换行 你会发现其实很简单, 但是从难点的说.比如说某某楼说的,首先按照长度分队列,(首先减少了算法的复杂度。),然后再按素数之积做相似度算法,怎么说呢,那就是说把工具丢一边,自己写和这个题目,更加相近的算法,为了兴趣可以去试下啊 但是为了面试,我不得不说,那点点可贵的时间就为了你闭门造车么- - 有点滑稽啊! - - 呵呵,我想多了,脑子每天都大数据计算。 把问题复杂化了 |
|
返回顶楼 | |
发表时间:2012-02-09
jdk用的是归并排序,这里有些不合适,效率不高
改用先统计每个字母的数量再组装字符串,效率提高一倍 public static String sort(String s){ //26个字母 short[] t =new short[26]; char c[]=s.toCharArray(); for(short i=0;i<c.length;t[c[i++]-'a']++) ; for(short i=0,j=0;i<26&&j<c.length;i++){ for(short k=1;k<=t[i];k++){ c[j++]=(char)(i+'a'); } } return new String(c); } [\code] 下面有就有个问题了,对于程序来说,字符串是什么,还不是char[],这里我们再思考下,反正都是要比较的,我直接把上面的那个short []t丢出来比较是不是更快 public class Comparable { public short[] t; public Comparable(String s){ t=PP.sort2(s); } @Override public boolean equals(Object paramObject) { if(paramObject==null) return false; if(paramObject instanceof Comparable){ Comparable cast = (Comparable)paramObject; if(cast.t.length!=this.t.length) return false; for(int i=0;i<cast.t.length;i++){ if(cast.t[i]!=this.t[i]) return false; } return true; } return false; } @Override public int hashCode() { int r=0; for(int i=0;i<t.length;i++){ r+=r*31+t[i]; } return r; } } [\code] 完整测试代码 public class PP { public static void main(String[] args) { String s="cccabcfdjfdisojfiosfuqjofjidosjfasofusafus"; double time = System.currentTimeMillis(); for(int i=0;i++<1000000;Arrays.sort(s.toCharArray())); double time2 = System.currentTimeMillis(); System.out.println((time2-time)); for(int i=0;i++<1000000;sort(s)); double time3 = System.currentTimeMillis(); System.out.println(time3-time2); for(int i=0;i++<1000000;sort2(s)); double time4 = System.currentTimeMillis(); System.out.println(time4-time3); String str=new String(s); double time5 = System.currentTimeMillis(); for(int i=0;i++<1000000;s.equals(str)); double time6 =System.currentTimeMillis(); System.out.println(time6-time5); Comparable c1= new Comparable(s); Comparable c2 =new Comparable(s); double time7 = System.currentTimeMillis(); for(int i=0;i++<1000000;c1.equals(c2)); double time8= System.currentTimeMillis(); System.out.println(time8-time7); } public static String sort(String s){ //26个字母 short[] t =new short[26]; char c[]=s.toCharArray(); for(short i=0;i<c.length;t[c[i++]-'a']++) ; for(short i=0,j=0;i<26&&j<c.length;i++){ for(short k=1;k<=t[i];k++){ c[j++]=(char)(i+'a'); } } return new String(c); } public static short[] sort2(String s){ //26个字母 short[] t =new short[26]; char c[]=s.toCharArray(); for(short i=0;i<c.length;t[c[i++]-'a']++) ; return t; } } class Comparable { public short[] t; public Comparable(String s){ t=PP.sort2(s); } @Override public boolean equals(Object paramObject) { if(paramObject==null) return false; if(paramObject instanceof Comparable){ Comparable cast = (Comparable)paramObject; if(cast.t.length!=this.t.length) return false; for(int i=0;i<cast.t.length;i++){ if(cast.t[i]!=this.t[i]) return false; } return true; } return false; } @Override public int hashCode() { int r=0; for(int i=0;i<t.length;i++){ r+=r*31+t[i]; } return r; } } [\code] 结果 1827.0 968.0 410.0 225.0 142.0 (1827+225)/(410+142)≈3.7 差不多比自己写的耗时多3.7倍 不知道大家能不能理解,利用质数方法是不错,但是字符串长度过大的话,BigInteger的性能太差,它内部其实还是数组,依次遍历相乘再进位的算法,很慢 |
|
返回顶楼 | |