1、IBM面试题:平面上画1999条直线,最多能将平面分成多少部分?
分析:
没有直线时有一个空间;(1)
1条直线时,这条这些可以将这个空间分成两个;(1+1)
2条直线时,第二条直线可以和第一条直线相交,这样第二条直线可以将两个空间分成四个;(1+1+2)
....
注意到画每条直线时能增加多少个空间,取决于此直线从多少个空间中通过。
而从多少个空间中通过,取决于和多少条直线相交。
例如,如果一条直线和其它5条直线相交,那么最大可以通过6个空间,此直线可以增加6个子空间。
画每条直线时,能相交的直线数为总的已经画过的直线。
所以总的空间数最多为
1+1+2+3+...+1999 = 1999001
2、IBM面试题:使用两根烧1小时的香,确定15分钟的时间
不均匀分布的香,每根香烧完的时间是一个小时,你能用什么方法来确定一段15分钟的时间?
分析:第一根点燃两头,第二根只点一头。
当第一根烧完时,时间过去了30分钟,所以第二根还能烧30分钟。这时点燃第二根的另外一头,第二根香还能烧的时间就是15分钟。
3、IBM面试题:27个人去买矿泉水
有27个人去买矿泉水,商店正好在搞三个空矿泉水瓶可以换一瓶矿泉水的活动,他们至少要买几瓶矿泉水才能每人喝到一瓶矿泉水?
分析:19
4、百度面试题:将多个集合合并成没有交集的集合
给定一个字符串的集合,格式如:{aaa bbb ccc}, {bbb ddd},{eee fff},{ggg},{ddd hhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaa bbb ccc ddd hhh},{eee fff}, {ggg}。
(1)请描述你解决这个问题的思路;
(2)请给出主要的处理流程,算法,以及算法的复杂度
(3)请描述可能的改进。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.regex.Pattern; /*实现思路: 将接受的字符串进行切割存入一个二维的字符串数组,使用二重循环去找出有交集的数组并合并,将被合并的数组置为空; 由于使用二维数组,而数组定义时必须定义大小,给算法的实现带来了不必要的麻烦;原本打算使用二维的list,但是使用起来有错误,原因尚不明确,但是使用 list应该会优于数组; 由于在算法执行的数组合并的过程中是直接将新出现的元素直接插入到数组的尾部,所以最后在输出过滤的时候还要将数组内的元素进行排序。 我使用了冒泡排序和插入排序两种方法。 纯属练手,高手勿喷!o(∩_∩)o 哈哈*/ public class BaiDu_UnionStringSet { static String ReadString() throws IOException { /* 接收输入字符串 */ String s = new String(); BufferedReader stdin = new BufferedReader(new InputStreamReader( System.in)); System.out .println("输入格式如{aaa bbb ccc},{bbb ddd},{eee fff},{ggg hhh},{ddd hhh}的字符串:"); s = stdin.readLine(); stdin.close(); return s; } static String[][] String_to_List(String s) { /* 将输入的数据存入一个二维字符串数组,本来打算使用二维的list,结果老是报错。 */ List list; String ss = new String(); s = s.replace("{", "").replace("}", "");// 去掉{ 和 } list = Arrays.asList(Pattern.compile(",").split(s));// 将字符串以“,”进行切割生成一个数组再转换成一个list(可以直接用数组) String[][] sz = new String[list.size()][3 * list.size()];// 定义一个二维数组,其中有一维的大小不知道,这样是不合适的,这也是为什么我想用list的原因 for (int i = 0; i < list.size(); i++) { ss = (String) list.get(i); sz[i] = Pattern.compile(" ").split(ss); } return sz; } static boolean ComStr(String[] s1, String[] s2) { /* 判断两个字符串数组中是否有交集 */ int i, j; for (i = 0; i < s1.length; i++) for (j = 0; j < s2.length;) { if (s1[i] != null && s2[j] != null && s1[i].equals(s2[j])) { return true; } else j++; } return false; } static boolean belong(String s, String[] s1) { /* 判断字符串s是否出现在s1数组中 */ for (int i = 0; i < s1.length;) { if (s1[i] != null) { if (s.equals(s1[i])) return true; else i++; } else i++; } return false; } static String[] MergeStr(String[] s1, String[] s2) { /* 将两个字符数组去重后融合在一起 */ String[] s = new String[s1.length + s2.length]; int i, j; for (i = 0; i < s1.length; i++) s[i] = s1[i]; for (i = 0, j = 0; j < s2.length; j++) { if (s1 != null && s2[j] != null) { if (!belong(s2[j], s1)) { s[s1.length + i] = s2[j]; i++; } } } return s; } static void findUnion(String[][] s) { /* 找出二维数组s中符合条件的字符串合并,并打印 */ int i, j; for (i = 0; i < s.length; i++) { for (j = 0; j < s.length; j++) { if (s[i] != null && s[j] != null && i != j) { if (ComStr(s[i], s[j])) { s[i] = MergeStr(s[i], s[j]); s[j] = null; } } } } for (int k = 0; k < s.length; k++) { if (s[k] != null) { OutPutString(s[k]); } } } static void OutPutString(String[] str) { System.out.println("使用冒泡排序:"+"\n"+SortString_bubbling(RemoveNull(str))); System.out.println("使用插入排序:"+"\n"+SortString_insert(RemoveNull(str))); } static List RemoveNull(String[] str) {/* 使用List去除null */ List nonull_list = new LinkedList(); for (int i = 0; i < str.length; i++) { if (str[i] != null) { nonull_list.add(str[i]); } } return nonull_list; } static List SortString_bubbling(List list) { /* 冒泡排序 */ String s1 = new String(); String s2 = new String(); for (int i = 0; i < list.size(); i++) { for (int j = i; j < list.size(); j++) { s1 = list.get(i).toString(); s2 = list.get(j).toString(); if (s1.compareTo(s2) > 0) { list.set(i, s2); list.set(j, s1); } } } return list; } static List SortString_insert(List list) { /* 插入排序 */ List sortedlist = new LinkedList(); ListIterator x = list.listIterator(0); String str = new String(); String comstr = new String(); String comstr_a = new String(); int count, moveid, flag; while (x.hasNext()) { str = x.next().toString(); flag = -1;// 用来判断元素是否已经插入新表中 for (count = 0; flag == -1 && count < sortedlist.size(); count++) { if (sortedlist.size() == 0) { sortedlist.set(count, str); flag = 0; } else { comstr = sortedlist.get(count).toString(); if (str.compareTo(comstr) < 0) { for (moveid = sortedlist.size(); moveid > count; moveid--) { comstr_a = sortedlist.get(moveid - 1).toString(); if (moveid == sortedlist.size()) { sortedlist.add(moveid, comstr_a); // 增加并不替换原位置上的元素,原元素后移 } else sortedlist.set(moveid, comstr_a);// 替换原位置元素;但是不能对表尾操作 }// 后移 sortedlist.set(count, str); flag = 0;// 插入元素 } } } if (flag == -1) { sortedlist.add(str);// 插在表尾 flag = 0; } } return sortedlist; } public static void main(String[] args) throws IOException { findUnion(String_to_List(ReadString())); } }
4、网易面试题:new/delete和malloc/free的区别
new/delete和malloc/free的区别,并说说你在什么情况下会自另行建立自己的内存分配。
解析:
new/delete:给定数据类型,new/delete会自动计算内存大小,并进行分配或释放。如果是对类进行操作,new/delete还会自动调用相应的构造函数和析构函数。
malloc/free:没有进行任何数据类型检查,只负责分配和释放给定大小的内存空间。
有些情况下,new/delete和malloc/free都不能满足性能的要求,我们需要自建内存分配来提高效率。比如,如果程序需要动态分配大量很小的对象,我们可以一次分配可以容纳很多小对象的内存,将这些小对象维护在链表中,当程序需要时直接从链表中返回一个。
5、百度面试题:有两个文件,各含50M和500个url,找出共同的url
一个大的含有50M个URL的记录,一个小的含有500个URL的记录,找出两个记录里相同的URL。
解析:
首先使用包含500个url的文件创建一个hash_set。
然后遍历50M的url记录,如果url在hash_set中,则输出此url并从hash_set中删除这个url。
所有输出的url就是两个记录里相同的url。(复杂度为:O(m×n))
AC自动机算法也可以解决。参见:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html
6、微软面试题:删除链表中的重复项
一个没有排序的链表,比如list={a,l,x,b,e,f,f,e,a,g,h,b,m},请去掉重复项,并保留原顺序,以上链表去掉重复项后为newlist={a,l,x,b,e,f,g,h,m},请写出一个高效算法(时间比空间更重要)。
解析:
建立一个hash_map,key为链表中已经遍历的节点内容,开始时为空。
从头开始遍历链表中的节点:
- 如果节点内容已经在hash_map中存在,则删除此节点,继续向后遍历;
- 如果节点内容不在hash_map中,则保留此节点,将节点内容添加到hash_map中,继续向后遍历。
import java.util.HashMap; import java.util.LinkedList; import java.util.Map; public class hashmap_noduplicates { static void removeduplicates(String[] str) { LinkedList list = new LinkedList(); Map hm=new HashMap(); String s=new String(); int flag=0; for (int i = 0; i < str.length; i++) { list.add(str[i]);} for(int counter=0;counter<str.length;counter++){ s=str[counter]; if(!hm.containsKey(s)){hm.put(s, null);} else { list.remove(counter-flag);//list链表remove一个元素过后,它的size也减小了 flag++; } } System.out.println(list); } public static void main(String[] args){ String[] str={"a","l","x","b","e","f","f","e","a","g","h","b","m"}; removeduplicates(str); } }
7、谷歌面试题:找到两个字符串的公共字符,并按照其中一个的排序
写一函数f(a,b),它带有两个字符串参数并返回一串字符,该字符串只包含在两个串中都有的字符并按照在a中的顺序。写一个版本算法复杂度O(N^2)和一个O(N) 。
解析:
O(N^2):
对于a中的每个字符,遍历b中的每个字符,如果相同,则拷贝到新字符串中。
O(N):
首先使用b中的字符建立一个hash_map,对于a中的每个字符,检测hash_map中是否存在,如果存在则拷贝到新字符串中。
import java.util.HashMap; public class find_samechars { static String find_samechars_n2(String s1,String s2){ char[] c1=s1.toCharArray(); char[] c2=s2.toCharArray(); char c; String s=new String(); int i,j,flag; for(i=0;i<c1.length;i++){ c=c1[i]; flag=-1; for(j=0;flag==-1 && j<c2.length;j++){ if(c==c2[j]){flag=0;} } if(flag==0){s=s+c;} } return s; } static String find_samechars_n(String s1,String s2){ HashMap hm=new HashMap(); String s=new String(); char[] c1=s1.toCharArray(); char[] c2=s2.toCharArray(); for(int i=0;i<c2.length;i++){ hm.put(c2[i],null); } for(int j=0;j<c1.length;j++){ if(hm.containsKey(c1[j])){s=s+c1[j];} } return s; } public static void main(String[] args){ String s1="ijklmnabcdefgh"; String s2="azbyixhwgvcn"; System.out.println("s1="+s1); System.out.println("s2="+s2); System.out.println("时间复杂度为N^2:"+find_samechars_n2(s1,s2)); System.out.println("时间复杂度为N:"+find_samechars_n(s1,s2)); } }
8、谷歌面试题:如何尽快找到一个好人
有n个人,其中超过半数是好人,剩下的是坏人。好人只说真话,坏人可能说真话也可能说假话。这n个人互相都知道对方是好人还是坏人。
现在要你从这n个人当中找出一个好人来,只能通过以下方式:
每次挑出两个人,让这两个人互相说出对方的身份,你根据两个人的话进行判断。
问通过何种方法才能最快的找出一个好人来。(要考虑最坏的情况)
解析:
先找一个人A,然后其他所有人评价A
1如果半数说A是好人:A是好人
2如果半数以上说A是坏人:A是坏人
-----
如果A是坏人
去掉说A是好人的人(一定是坏人)
在剩下的人里找一个人重复上面的(这里好人肯定更多于一半)
---
递归进行
最坏情况就是坏人都说实话且每次运气不好都选出的是坏人
这时复杂度是O(n^2)
实际计算时选出好人的几率越来越高的,因为坏人不断的被去掉
(好吧,我承认我的智商太低了)