关于对《对于笔试题,如果让你出?你会怎么出?》里面题目的探讨
对于上一篇文章:对于笔试题,如果让你出?你会怎么出?引来了很多同学的讨论,有一些人觉得题目对于笔试来说难了点,有些人这样的题才适合拿来做笔试的交流,其实对于那些题目,我个人觉得:你即使一个题目不会,也不代表你水平差,如果你每个题都能说上点来,说明你是从实际项目中走过来的人,那些题目我是根据实际工作中用到的点做了下归纳总结的,拿出来只是为了让大家讨论下,越多的思路就会有更优的解决方案,因为最近自己的小说网站,自己在摸索尝试些东西,难免对一些问题影响比较深刻,记录下,也是跟大家谈论下,我也是在摸索最优的解决方案。闲话不多说,来看看我是怎么理解这几个问题的。
1、 提取字符串中的数字(返回小写的数字,如果不存在可读数字返回0),字符串的特点:可能有大写的数字,比如一万二千三百六十,返回12360,也可能包含小写的数字,比如14520,直接返回14520,有时候可能因为大意把数字中的0写成了o,比如12021写成了12o21。
这个题是因为小说网站里,一本小说收录于可能10个或者20个小说站点,需要按照更新速度排名,把最新更新的站点排在前面,但是不能根据站点更新该本小说的时间来作为该书的更新速度,因为存在一些站点,昨天更新了,但总章节只有5个,但实际上该书的更新章节已经远远超过了5个,如果按照章节总数来排名,有的站点更新的小说章节里有牵差了非正式章节的章节,后来观察章节名称,基本上正式的章节都会有一个数字说明,比如:“第一千三百二十章 天朝风云”,因为这个章节数字是作者按照章节来的,所以比较有排名的顺序,比如搜索《遮天》这本小说,要把更新的最新章节名称大的放在前面:http://www.tiyma.com/bookList.aspx?k=%u906E%u5929,我是这样来实现的:
/// <summary>
/// 根据最后章节名称获取章节排序数字
/// </summary>
/// <param name="i_last_update_chapter_name"></param>
/// <returns></returns>
private int GetChapterOrderNumber(string i_last_update_chapter_name)
{
string[] t_big_chinese = new string[] { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖", "拾", "佰", "仟", "〇" };
string[] t_small_chinese = new string[] { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "百", "千", "〇" };
string[] t_number = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "", "", "", "0" };
if (string.IsNullOrEmpty(i_last_update_chapter_name))
return 0;
foreach (char t_ch in i_last_update_chapter_name)
{
for (int index = 0; index < t_big_chinese.Length; index++)
{
i_last_update_chapter_name = i_last_update_chapter_name.Replace(t_big_chinese[index], t_number[index]);
i_last_update_chapter_name = i_last_update_chapter_name.Replace(t_small_chinese[index], t_number[index]);
}
}
Match t_mc = Regex.Match(i_last_update_chapter_name, "(\\d+)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
if (t_mc != null && t_mc.Groups.Count > 1)
{
int t_chapter_count = 0;
if (!int.TryParse(t_mc.Groups[1].Value.ToString(), out t_chapter_count))
t_chapter_count = 0;
return t_chapter_count;
}
return 0;
}
2、 数据表中有两个字段,一个是siteid,一个是siteurl,数据如下
Siteid | siteUrl |
1 | Abc.com |
1 | Cde.com |
2 | 2abc.coom |
2 | 2abc.coom |
3 | 3abc.coom |
3 | 3abc.coom |
4 | 4abc.coom |
4 | 4abc.coom |
5 | 5abc.coom |
请把这张表数据读入到一个队列里面Queue<SiteInfo>,需要达到每次从该队列里弹出10个SiteInfo,这10个SiteInfo的SiteId都不相同
这个题是由于收录小说的时候,如果是新书会把小说的信息章节列表页面地址保存到数据库,之后检查该本小说是否有更新章节的时候只需要获取章节列表页面解析章节名称即可,所以从数据库读小说章节列表地址去收录最新章节,每次开启10个线程收录最新章节,希望这10个线程分别从不同的站点收录,如果10个线程都去收录一个站点,会对站点有很大的压力。来看看我的代码实现逻辑:
public Queue<BookInfo> GetUpdateBook()
{
string t_str_sql = "select bookId,siteId,chapterListUrl from tbbook";
//存放站点对应的小说集合,这里的50表示有50个站点,这个值可以从数据库获得
List<BookInfo>[] t_book_list_arr=new List<BookInfo>[50];
//小说信息
BookInfo t_book = null;
//需要返回的小说队列
Queue<BookInfo> t_book_queue = new Queue<BookInfo>();
try
{
//把数据读取到站点对应的小说结合中
using (MySqlDataReader t_reader = DBHelper.ExecuteReader(t_str_sql))
{
t_book = new BookInfo();
t_book.SiteId = Convert.ToInt32(t_reader["siteId"].ToString());
t_book.BookId = Convert.ToInt64(t_reader["bookId"].ToString());
t_book.ChapterListUrl = t_reader["chapterListUrl"].ToString();
//该站点已经读取到小说
if (t_book_list_arr[t_book.SiteId] != null)
{
t_book_list_arr[t_book.SiteId].Add(t_book);
}
else
{
List<BookInfo> t_book_list = new List<BookInfo>();
t_book_list.Add(t_book);
t_book_list_arr[t_book.SiteId] = t_book_list;
}
}
//那个站点小说最多
int t_max_book_list_site = 0;
foreach (List<BookInfo> t_book_list in t_book_list_arr)
{
if (t_book_list != null && t_book_list.Count > t_max_book_list_site)
t_max_book_list_site = t_book_list.Count;
}
//一次从一个站点中取一条数据进队列
for (int index = 0; index < t_max_book_list_site; index++)
{
foreach (List<BookInfo> t_book_list in t_book_list_arr)
{
if (t_book_list != null && t_book_list.Count > index)
{
t_book_queue.Enqueue(t_book_list[index]);
}
}
}
return t_book_queue;
}
catch (Exception ex)
{
throw new DataException("获取需要更新的小说信息失败", ex);
}
}
3、 建一个 windowService 程序,使用50个线程,读取数据库中的一条数据,写到文本文件。每个线程写一个文件,1秒钟一次;每个线程读取的数据不能有交叉;数据库数据条数为100万。
这个题主要是交流的思路,我记得我刚毕业那会儿,碰到一个问题,公司有对自己站点的一个访问统计表,该表数据几十兆,运营部门某一天急需某一天的网站PV和IP,可是这张表在时间那个字段并没有索引,几时有索引,对时间这个字段去做搜索也会是比较长时间的性能损好,那时候我是真没思路,到底怎么去查询这个结果,后来主管给了我一个思路,因为这张表有一个自增字段,该字段是聚集索引,所以利用该字段,select createtime from table where id=10000,看看该记录的创建时间是哪天,如果跟需要统计的时间相差大,可以继续放大或缩小id的值,知道找到一个跟统计时间相同的一个最小Id和最大id,这样两个Id之间的数据就是哪天的数据。所以对于这个题,我觉得是首先确定每个线程的职责分工,我们先检查下该表是否有自增字段,如果没有,创建一个,50个线程读取100W数据,一个线程2W,这样我们可以根据数据库的自增序列,每个线程顺序去读取自己的数据写到自己的文本文件里,比如第一个线程读取Id在1到2W之间的数据写到1.txt文件中,第二个线程读取2W零1到4W之间的数据写到2.txt中,依次类推,每个线程都干自己的事情,完全并发去执行。
4、 在一张页面访问平率非常高的情况下,有什么办法来提供页面的加载速度,分别从HTML反面和服务器端方面来说明。
这个是自由发挥的题目,像文章中某些同学评论所说一样,如果真要深究起来,两个小说说来也不长,对于我来说,只是想说说自己实践的几条
(1)、客户端简化html页面,主要目标是减小页面的大小,比如你浏览一张页面是500k,那么能把该页面减小到400K就算是优化,把css样式表抽离,减小页面中的标签数量,去掉标签几点间的空格(特别是绑定数据列表的地方),抽离js,js最好用事件绑定的方式,对于一张大的页面如果有交互,最好用ajax交互。对js和页面中用到的图片可以先进行压缩等等。
(2)服务器端,如果实时性要求不那么高,可以对页面缓存,也可以对其中的数据块进行缓存,对页面进行gzip方式压缩,目前大部分的浏览器都支持gzip压缩方式。
5、 在一个业务逻辑比较多枚举的情况下,比如在A条件下执行“select * from A“这条SQL语句,在B条件下执行“select * from B”这条SQL语句,但是条件可能有上百中情况,怎么来写这块逻辑代码。
这个题主要考察代码的优雅程度,让代码看上去易读,优雅,美观,我的建议是采用key-value形式来封装这样业务逻辑,即使以后还增加判断逻辑,也只需要往key-value的容器里添加一条数据即可。
6、实现一个英语句子的单词逆转,比如“I am come from ShangHai”,输入ShangHai from come am I,单词与单词之间可能有多个空格。
这种字符串处理应该会经常用到,对于字符串的处理,我觉得正则是最好的选择了,而且这个题不用正则也挺好处理的,以空格分离下字符串,然后从数组的最后项一次输出即可:
private string ParseEnglish(string i_english)
{
if(string.IsNullOrEmpty(i_english))
return string.Empty;
//多个空格算一个
string[] t_english_arr = i_english.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
StringBuilder t_sb = new StringBuilder();
if (t_english_arr != null && t_english_arr.Length > 0)
{
for (int index = t_english_arr.Length-1; index > -1; index--)
{
t_sb.Append(t_english_arr[index]).Append(" ");
}
}
return t_sb.ToString();
}
7、在Asp.net中的一张web页面中,有前台aspx页面和后台.cs类,在aspx代码的<body>标签中写入:我是中国人,跟在.cs的page_load方法中Response.Write(“我是中国人”),两种方式是那个先展现在页面上
这个题主要考察是页面的生命周期,从一个请求开始,到页面的呈现到客户端的一个过程掌握,相信对bs程序开发有点经验或者有点兴趣的同学应该都很清楚,所以这个答案就不攻自破了,我相信只要你对面试官大概讲了下页面的生命周期,不用说答案,面试官也会觉得你很ok。
8、 在一张页面中引用了一张很大的背景图片,用该背景图片中的某一区域来做某个div的背景,用css怎么写?
应该说目前稍微大点得正规的网站都采用这个方式来处理,一张页面就一张很大的背景图片,根据这个背景图片来布局,想查个究竟可以看看淘宝,新浪,京东,右键查看下源代码就知道了。
比如淘宝的彩票页面的一张背景图片:http://a.tbcdn.cn/app/lottery/v2/img/norepeat_bg.png,排版出来的彩票页面多漂亮,速度也快。
9、 JS怎么引用.cs里面的变量,比如说.cs里有个变量是 string t_a=”123”,在js中怎么定义个变量来接受t_a的值。
这个题不知道是我表达有歧义还是用词不够准确,看了评论,某些同学对这个题目抱了很大的抨击力度,其实我想表达的意思是怎么在.cs代码里注册一些信息给.aspx中,让js能够方便的使用,其实方法很多,比如把值绑定在控件上呈现在页面上,页面上js读取控件的值来使用,但是我想代码优雅点,想告诉答题的人用变量接受变量的方式来做,所以我们只需要在.cs里面把t_a声明成pubic,js代码直接用这个public变量,即
Public t_a=”123”;js中 var t_a=”<%=t_a%>”;这样就可以了。
10、一个JS文件里有如下内容:document.write(‘什么东西,这里的内容很长’);页面里在引用该js的地方会输出“什么东西,这里的内容很长”,用什么办法来把“什么东西,这里的内容很长”这个内容动态指定给一个Html控件。
这个题是因为我之前小说章节内容页,我把小说内容保存到txt文件中,该txt文件内容就是document.write(‘章节内容’);这样在页面里需要加载章节内容的地方就直接通过js来声明该txt文件就可以:<script src="/chapter/2/1.txt"></script>,这样输出章节内容,然后回来发现这样输出不是很灵活,要把内容动态指定到某个html控件上,所以我们只需要重写下document.write方法即可:
<script>
function document.write(i_content)
{
//把i_content放在lblContent控件上
document.getElementById("lblContent").innerHTML=i_content;
}
</script>
从我整理的情况来看,貌似这些题真不适合做笔试题目,就我自己整理都花了一个多小时时间,如果让面试的人来做,估计会失去耐心的,不过就像我之前说的,即使你一个题也搭不上来,不代表你真的水平差,能写写思路,谈谈实现逻辑也是可以的,我觉企业要找一个人,更多的会看重他的沟通能力,执行能力,学习能力,而不是简单的做几个题而已。