算法、设计模式、企业应用架构模式、架构模式

<<.NET B/S 架构实践>> 几种概念区别 - 算法、设计模式、企业应用架构模式、架构模式

算法:相信大家对算法肯定不陌生(但其实绝大多数开发人员对这个非常陌生且抗拒),因为从学校没毕业开始就已经被算法折磨了,哈哈

设计模式:爱学习的开发人员对这个也不会陌生,是些到了一定工作阶段必须学的思想以及解决问题的通用方法

企业应用架构模式:Martin Fowler所著,其实从难度上讲,比不上设计模式,只是内容较多,更加实际且更加符合人类的理解

架构模式:最著名的资料是POSA那几本书,讲的是云里雾里,看这本书时,设计模式那点难度根本就不叫难度,哈哈,看起来极其痛苦,但是又非常快乐(哈哈,这就要看看书的人了)

在这些概念当中,个人认为架构模式以及算法是比较难的,如果只能选择一个,我就选算法为最难,所以携程才招了一帮博士搞算法,因为其他的都能慢慢搞懂,唯独算法是需要真正长久专研下去的,能够达到非常深奥。

题外话:像这些概念其实都80、90年代就已经出现了,可惜,我们却刚开始研究人家的东西,悲哀啊。

很多人认为

  1. 算法用不到,所以不用学
  2. 架构模式不就分层嘛,地球人都会

其实不然,memcache是怎么发明的?操作系统的调度算法怎么实现的?为啥这么实现而不是那样实现?有和依据?为什么加了数据库的索引后搜索能飞快?为什么加了这个索引却没有用?为什么大规模文本搜索时要用Lucene来搜索,而不是sql server或者oracle?

这些为什么后面大部分是由算法和架构决定的,绝不是简单的分层架构。

希望广大的开发人员能关注这些,中国的研发需要中国程序员。

 

自省推动进步,视野决定未来。
心怀远大理想。
为了家庭幸福而努力。
A2D科技,服务社会。
A2D Framework(Alpha)
  • 1. Cache System(本地缓存与分布式缓存共存、支持Memcache和Redis、支持贴标签形式(类似Spring 3.x的Cache形式))
  • 2. Event System(本地事件与分布式事件分发)
  • 3. IoC(自动匹配功能,实例数量限制功能)
  • 4. Sql Dispatcher System(支持ADO.NET及EF)
  • 5. Session System(分布式Session系统)
  • 6. 分布式Command Bus(MSMQ实现,解决4M限制,支持Session的读取)
  • 7. 规则引擎
 
分类:  研发管理

LeetCode:Word Ladder I II

其他LeetCode题目欢迎访问:LeetCode结题报告索引

LeetCode:Word Ladder 

Given two words (start and end), and a dictionary, find the length of shortest transformation sequence from start to end, such that:

  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary

For example,

Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.

Note:

    • Return 0 if there is no such transformation sequence.
    • All words have the same length.
    • All words contain only lowercase alphabetic characters.

分析:这种题,肯定是每次改变单词的一个字母,然后逐渐搜索,很多人一开始就想到用dfs,其实像这种求最短路径、树最小深度问题bfs最适合,可以参考我的这篇博客bfs(层序遍历)求二叉树的最小深度。本题bfs要注意的问题:

  • 和当前单词相邻的单词是:对当前单词改变一个字母且在字典中存在的单词
  • 找到一个单词的相邻单词,加入bfs队列后,要从字典中删除,因为不删除的话会造成类似于hog->hot->hog的死循环。而删除对求最短路径没有影响,因为我们第一次找到该单词肯定是最短路径,即使后面其他单词也可能转化得到它,路径肯定不会比当前的路径短(如果要输出所有最短路径,则不能立即从字典中删除,具体见下一题)
  • bfs队列中用NULL来标识层与层的间隔,每次碰到层的结尾,遍历深度+1

我们利用和求二叉树最小深度层序遍历的方法来进行bfs,代码如下:                                                                                                                              本文地址

复制代码
 1 class Solution {

 2 public:

 3     int ladderLength(string start, string end, unordered_set<string> &dict) {

 4         // IMPORTANT: Please reset any member data you declared, as

 5         // the same Solution instance will be reused for each test case.

 6         //BFS遍历找到的第一个匹配就是最短转换,空字符串是层与层之间的分隔标志

 7         queue<string> Q;

 8         Q.push(start); Q.push("");

 9         int res = 1;

10         while(Q.empty() == false)

11         {

12             string str = Q.front();

13             Q.pop();

14             if(str != "")

15             {

16                 int strLen = str.length();

17                 for(int i = 0; i < strLen; i++)

18                 {

19                     char tmp = str[i];

20                     for(char c = 'a'; c <= 'z'; c++)

21                     {

22                         if(c == tmp)continue;

23                         str[i] = c;

24                         if(str == end)return res+1;

25                         if(dict.find(str) != dict.end())

26                         {

27                             Q.push(str);

28                             dict.erase(str);

29                         }

30                     }

31                     str[i] = tmp;

32                 }

33             }

34             else if(Q.empty() == false)

35             {//到达当前层的结尾,并且不是最后一层的结尾

36                 res++;

37                 Q.push("");

38             }

39         }

40         return 0;

41     }

42 };
复制代码

 


 

LeetCode:Word Ladder II

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:

  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary

For example,

Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]

Return

  [

    ["hit","hot","dot","dog","cog"],

    ["hit","hot","lot","log","cog"]

  ]

Note:

  • All words have the same length.
  • All words contain only lowercase alphabetic characters.

分析:本题主要的框架和上一题是一样,但是还要解决两个额外的问题:一、 怎样保证求得所有的最短路径;二、 怎样构造这些路径

第一问题:

  • 不能像上一题第二点注意那样,找到一个单词相邻的单词后就立马把它从字典里删除,因为当前层还有其他单词可能和该单词是相邻的,这也是一条最短路径,比如hot->hog->dog->dig和hot->dot->dog->dig,找到hog的相邻dog后不能立马删除,因为和hog同一层的单词dot的相邻也是dog,两者均是一条最短路径。但是为了避免进入死循环,再hog、dot这一层的单词便利完成后dog还是得从字典中删除。即等到当前层所有单词遍历完后,和他们相邻且在字典中的单词要从字典中删除。
  • 如果像上面那样没有立马删除相邻单词,就有可能把同一个单词加入bfs队列中,这样就会有很多的重复计算(比如上面例子提到的dog就会被2次加入队列)。因此我们用一个哈希表来保证加入队列中的单词不会重复,哈希表在每一层遍历完清空(代码中hashtable)。
  • 当某一层的某个单词转换可以得到end单词时,表示已经找到一条最短路径,那么该单词的其他转换就可以跳过。并且遍历完这一层以后就可以跳出循环,因为再往下遍历,肯定会超过最短路径长度

第二个问题:

  • 为了输出最短路径,我们就要在比bfs的过程中保存好前驱节点,比如单词hog通过一次变换可以得到hot,那么hot的前驱节点就包含hog,每个单词的前驱节点有可能不止一个,那么每个单词就需要一个数组来保存前驱节点。为了快速查找因此我们使用哈希表来保存所有单词的前驱路径,哈希表的key是单词,value是单词数组。(代码中的unordered_map<string,vector<string> >prePath)                         
  • 有了上面的前驱路径,可以从目标单词开始递归的构造所有最短路径(代码中的函数 ConstructResult)
复制代码
 1 class Solution {

 2 public:

 3     typedef unordered_set<string>::iterator HashIter;

 4     vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {

 5         // Note: The Solution object is instantiated only once and is reused by each test case.

 6         queue<string> Q;

 7         Q.push(start); Q.push("");

 8         bool hasFound = false;

 9         unordered_map<string,vector<string> >prePath;//前驱路径

10         unordered_set<string> hashtable;//保证bfs时插入队列的元素不存在重复

11         while(Q.empty() == false)

12         {

13             string str = Q.front(), strCopy = str;

14             Q.pop();

15             if(str != "")

16             {

17                 int strLen = str.length();

18                 for(int i = 0; i < strLen; i++)

19                 {

20                     char tmp = str[i];

21                     for(char c = 'a'; c <= 'z'; c++)

22                     {

23                         if(c == tmp)continue;

24                         str[i] = c;

25                         if(str == end)

26                         {

27                             hasFound = true;

28                             prePath[end].push_back(strCopy);

29                             //找到了一条最短路径,当前单词的其它转换就没必要

30                             goto END;

31                         }

32                         if(dict.find(str) != dict.end())

33                         {

34                             prePath[str].push_back(strCopy);

35                             //保证bfs时插入队列的元素不存在重复

36                             if(hashtable.find(str) == hashtable.end())

37                                 {Q.push(str); hashtable.insert(str);}

38                         }

39                     }

40                     str[i] = tmp;

41                 }

42             }

43             else if(Q.empty() == false)//到当前层的结尾,且不是最后一层的结尾

44             {

45                 if(hasFound)break;

46                 //避免进入死循环,把bfs上一层插入队列的元素从字典中删除

47                 for(HashIter ite = hashtable.begin(); ite != hashtable.end(); ite++)

48                     dict.erase(*ite);

49                 hashtable.clear();

50                 Q.push("");

51             }

52         END: ;

53         }

54         vector<vector<string> > res;

55         if(prePath.find(end) == prePath.end())return res;

56         vector<string> tmpres;

57         tmpres.push_back(end);

58         ConstructResult(prePath, res, tmpres, start, end);

59         return res;

60     }

61     

62 private:

63     //从前驱路径中回溯构造path

64     void ConstructResult(unordered_map<string,vector<string> > &prePath, 

65         vector<vector<string> > &res, vector<string> &tmpres, 

66         string &start, string &end)

67     {

68         if(start == end)

69         {

70             reverse(tmpres.begin(), tmpres.end());

71             res.push_back(tmpres);

72             reverse(tmpres.begin(), tmpres.end());

73             return;

74         }

75         vector<string> &pre = prePath[end];

76         for(int i = 0; i < pre.size(); i++)

77         {

78             tmpres.push_back(pre[i]);

79             ConstructResult(prePath, res, tmpres, start, pre[i]);

80             tmpres.pop_back();

81         }

82         

83     }

84 };
复制代码

另外这一题如果不用队列来进行bfs,可能会更加方便,使用两个哈希表来模拟队列,这样还可以避免前面提到的同一个元素加入队列多次的问题,具体可以参考这篇博客

【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3443512.html

 
 
标签:  leetcode

前言:

先说说大伙关心的工作上的事,在上家公司任了一个多月的技术经理后,和公司中止了合作关系。

主要原因在于一开始的待遇没谈的太清楚: 

1:没有合同,没有公积金,连社保也没交。

2:工资的30%变成了绩效(对我还实行特例,按季度或按项目发,而且绩效只有按期完成(发)与没完成(不发))

3:税后的问题,要自己去弄发票来填。

只能说缘来的太快,份走的也太快。

 

对于工作上的事,一个多月的时间,从需求文档到概要文档到详细文档,到产品原型到系统架构,基本上已经走完了。

项目成员也招聘完成,开发的按我的计划稳定的进行着,所有的技术难点,我都提前解决了。 

虽然人走,但后续剩下点的任务也安排好了,剩下的开发有种没了我依然一切如旧的悲凉感觉。

 

交待完前事,下面进入技术正题。 

1:ASP.NET的模板引擎(也称视图引擎):ASPX和Razor 简单介绍

如图有两种视图引擎:

 

微软视图引擎的基本原理:

加载模板(aspx、cshtml)-》调用引擎解析成(语法树)-》生成CS代码-》动态编绎-》返回最终模板。

算法、设计模式、企业应用架构模式、架构模式 

相对来说,这种模板引擎,性能相对来说会下降一些,但是搭载VS IED的智能提示,和大伙多年的开发习惯,已经占据了主流。

 

对于Razor有兴趣研究的,想深入的可以下载源码去慢慢慢慢研究,Razor 的源码(取自mvc5源码的razor项目):点击下载

这里也有篇Razor的原理基础文章,可供参考:  http://www.cnblogs.com/JamesLi2015/p/3213642.html

源码目录截图:

算法、设计模式、企业应用架构模式、架构模式 

2:CYQ.Data 模板引擎:XHtmlAction:

XHtmlAction模板引擎的基本原理:

算法、设计模式、企业应用架构模式、架构模式 

和ASP.NET自带的模板引擎比较,这里没有语法树、生成代码和动态编绎过程,因此可以得到高性能的体验。

另外相对来说,对Xml及XPath语法的操作进行了封装,简化了很多后台开发代码。

当然相对缺点就是不能在模板里混合写后台代码了,换个说法是没有强大的IDE智能提示(若换个角度看,也成优点,模板和后台代码真正分离了)。 

XHtmlAction实现也相当的轻量级,一共就6个文件,老少皆宜,有兴趣研究的可以看 CYQ.Data V4.55的源码:

算法、设计模式、企业应用架构模式、架构模式 

曾经也写过两篇相关的文章:

1:多语言的(MutilLanguage),可以让你很轻松的编写多语言网站:实战篇-简单多语言的实现

2:XHmlAction的使用(以前类名叫XmlHelper,用法是一样的):CYQ.Data.Xml XmlHelper 助你更方便快捷的操作Xml/Html

 

除了介绍的(XmlHelper)用法,最近V5版本增加了“CMS标签替换”功能,下面介绍。

 

3:XHtmlAction CMS标签替换功能介绍:

3.1 这里用CYQ.Data的文本数据库来演示:

先写个函数,创建文本数据库和添加数据:

复制代码
  // 创建文件数据库,并添加50条数据。
     void TxtDBCreate()
    {
        MDataTable.CreateSchema( " demo.txt "falsenew  string[] {  " Name "" CreateTime " },  new SqlDbType[] { SqlDbType.NVarChar, SqlDbType.DateTime });
         using (MAction action =  new MAction( " demo "))
        {
             for ( int i =  0; i <  50; i++)
            {
                action.Set( " Name "" Name_ " + i.ToString());
                action.Set( " CreateTime ", DateTime.Now.AddSeconds(i));
                action.Insert();
            }
        }
    }
复制代码

该代码执行后,生成两个文件:demo.ts(表结构)demo.txt(json格式的表数据)

算法、设计模式、企业应用架构模式、架构模式 

文本里的Json数据:

算法、设计模式、企业应用架构模式、架构模式 

文本数据库相当于创建好了,配置里添加一行数据库链接请求:

< connectionStrings >
         < add  name ="Conn"  connectionString ="txt path={0}" />
     </ connectionStrings >

3.2 项目示例代码:

弄好数据库,可以写代码了,单条数据的标签替换:

复制代码
  protected  void Page_Load( object sender, EventArgs e)
    {
       
         using (XHtmlAction xml =  new XHtmlAction( true))
        {
            xml.Load(Server.MapPath( " demo.html ")); // 加载html模板。
             using (MAction action =  new MAction( " demo "))  // 数据库操作,操作demo表。
            {
                 if (action.Fill( 1)) // 查询id=1的数据
                {
                    xml.LoadData(action.Data,  " txt ");//将查询的数据行赋给XHtmlAction,并指定CMS前缀
                }
                 // xml.LoadData(action.Select());
                
// xml.SetForeach("divFor", SetType.InnerXml);
            }
            Response.Write(xml.OutXml); // 输出模板
        }
    }
复制代码

代码解答: 

代码的关键就在于方法:LoadData(MDataRow,autoSetValuePre)
只要把数据行赋给模板,加一个任意前缀,之后就可以在html中任意使用:{$txt#Name} 或{$txt-CreateTime}或{$txt#ID}来代表数据的值。
'#','-'是默认的前缀分隔符号,任意使用其一都可。
{$字段名} 这个是因为大多数的模板引擎都采用这种,故采用这种通用方式。
上面的代码中,有两行是注释的,是多行数据的(表循环),方法是:LoadData(MDataTable); 

如果把上面的代码注释放开,Html如下:

复制代码
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html  xmlns ="http://www.w3.org/1999/xhtml"   >
< head >
     < title >{$txt#Name} </ title >
</ head >
< body >
< div  title ="单条数据"   >
单条数据:{$txt#Name} - {$txt-CreateTime}
</ div >
< hr  />
< div  id ="divFor"  title ="多条数据"   >
{$Name} - {$CreateTime} < br  />
</ div >
</ body ></html>
复制代码

最终效果输出如下图:

算法、设计模式、企业应用架构模式、架构模式 

 

本Demo源码下载: 点击下载

4:XHtmlAction 关键点

1:字段前缀:

对于一个html,可能涉及到相同的字段名(同表的不同行数据,不同表的数据)需要标签替换,因此LoadData(数据行,前缀)方法需要前缀来区分。

同时前缀也可以传空"",不使用前缀(但要注释避免和其它的冲突)。

对于行的数据,是在获取xml.OutXml属性的时候才处理,因为对于标签,可以存在任意地方,因此不能以节点来处理,只能在最终输的时候,拿到html,再用正则替换。

 

2:表格输出:

对于表格的输出,需要获取某个节点,以对节点下的内容,进行克隆复制循环输出,由于已经存在节点,所以在xml.SetForeach的时候就处理了。

如果涉及到字段格式化,仍按SetForeach的事件处理即可。

 

3:示例说明:

本文及示例介绍的是标签替换的功能,节点替换的操作方式,仍和以前的操作方式一致。

 

总结:

对于Web开发框架,主打关键就三块:URL重写(路由)、模板引擎(视图引擎)、数据层框架(ORM)。

如果你能掌控或自由实现这三模块,你的开发方式选择就自由化很多,如果不能,你只能局域于微软给你的WebForm和MVC。

对于框架,有时候研究的再深,也不如自己写一个浅的。 

你可能感兴趣的:(LeetCode,CYQ.Data,点击下载,点击下载,实战篇-简单多语言的实现)