本周看了十篇思维,搜索看了二十多篇(其中包括许多篇回溯和剪枝),七八篇用到类的题以及这两天刚看了五篇链表和一些其余的都沾了几篇(二分、贪心、STL、排序各看了两三篇),然后分别在周四和周日参加了一场比赛(周四的CF从头坚持到了最后,周日的只做了不到两个小时)
在我看的思维题中,发现了许多值得记录的做题的某些思维和小技巧。比如将许多数字排顺序变成能整除一个几百的数,(全排序很可能超时)可以把数x拆成几个数的乘积,(只要这些数都能被整除则符合),特殊的数字有3(所有位上的数字相加能否除尽3)、125(只要末尾三个数是“000,500,250,750,125,375,625,875其中的一种就可”.)。map数组真的很有用,经常在题解中能看到它的身影,可以有效记录某个数字有几个。还有一个令我印象深刻的题是求一组数中包含多少给定的子序列(子序列可相互交叉但顺序不能错),在输入数组然后用另一个数组计数每个数字出现几次时,要注意只有当前一个数的数量大于后一个数的数量时,才可计数。(保证顺序无误,这一点开始没看明白,想了好长时间又在纸上写了几组数字才恍然大悟);还有一种常见的是翻面问题,在一维中(有n张牌需要翻面,如果翻i那么[i−k,i+k],[i−k,i+k]全部都要翻面,问最少翻多少次可以把n张牌全部翻面)用到了贪心,肯定要尽可能多的让每一次都翻最多个(2k+1个)如果n%(2k+1)==0,则正好n/(2k+1)次,如果不能整除,则加一次就是总次数(因为剩下的一定比k小所以翻最边上那个一定能把剩下的全部一次翻面)。其实这些思维题都有个共同点便是透过复杂的题意看透他的本质,关键就是如何把它拆成简单问题的组合,大化小(不能再小化了了,小就可以写代码了)。
PS:1<<10含义:00000000001把1向左移10位,即10000000000(2^10)
这周刚接触到“类”这个概念,还有点迷糊没太搞清楚。用官方语言说类就是对某一类具有共同特征的事物的抽象描述。我的理解类就是自己定义的一种数据类型,而且还需要自己定义了对象才能让这种自己定义的数据类型有了“主人”。和结构体相似,结构体也是自己定义的。唯一的区别就是类的封装性,这应该就是类的独特之处,会将数据隐蔽起来,外部不能直接访问,把成员函数作为和外界的联系,通过成员函数访问数据。也可利用构造函数创造对象,值得注意的是若定义了带参的构造函数,一定要再定义一个无参的构造函数(没有带参数的构造函数时才会自动带着无参的构造函数,不用单独定义)。
链表也是这两天刚开始看的,最先是从算法笔记上看的,现在只了解了一些皮毛还没有真正的实战。如果要更好地理解链表的话那就和数组比较。数组是申请了一段连续的内存而链表则是申请了一段不连续的内存,更方便多次插入或删除元素,还不会扰乱其他的元素。不连续的结点之间是用指针连起来的,通过指针能得到下一个元素的地址。而且指针指向的类型也容易出错,如果要构造一个int类型的链表,那么一个节点中就需要包含当前节点所保存的值和指向下一个节点的指针,如果这个结点类型是node,那么这个指针就是 node *next而不能写int *next。
这周使我收获颇多的也就是和搜索有关的了吧,往往涉及到深度优先算法(DFS)和广度优先算法(BFS),其中还会用到回溯法和剪枝算法来优化代码,降低复杂度。DFS,关键词“深度”,往往是选择一条路往下走,碰到岔路口便选择一条路,如果遇到死胡同就退回到上一条路然后再从这个点选择一条别的路径。BFS,关键词“广度”,是先依次访问从该岔路口能直接到达的所有结点,然后再按这些结点被访问的顺序去一次访问他们能直接到达的所有结点;一般用队列,(队列元素也可以是结构体)。在DFS中往往能用到回溯算法,回溯就是走不通时返回上一个岔路。若这个路径解可行,则继续,若不可行,删除此选择,假设为an,然后加入an的另一种可能,若an这条路已经遍历完,则回溯进行a(n-1)的下一个可能,在代码中一般是在DFS函数中再次用DFS()搜索下一层的下一行进行还原,并清除标记。若ak的可能已经遍历完,回溯并寻找ak-1的下一个,可能剪枝也往往与此结合,当用深搜遍历全部路径后,很可能会TLE超时,这时往往要用到剪枝,剪枝的思想就是就是通过某种判断,避免一些不必要的遍历过程,就是如果发现这条路径不可行,就立刻回溯。从看博客的许多题中,我目前就遇到总结了四种剪枝(可能有相似差不多的):①有一个题是在m*n矩阵(有起点、终点、墙)中,给定t步判断是否能恰好从起点到终点,我从中学到了一个奇偶剪枝,设起点(sx,sy),终点(ex,ey),若 t-[abs(ex-sx)+abs(ey-sy)] 结果为奇数,则无法在t步恰好到达,返回false;(也是在优快云上搜索看了几篇大佬的详细说明才懂原理的)只有答案是偶数才可能在t步到达,很容易看出1是最短路径,而2路不管再怎么拐弯,和1路相减后永远是偶数。
②在搜索的时候,发现搜到一半已经不符合题目要求了,就可以提前终止退出了③在找成立的最小值时,发现现在的值已经大于目前的最优解,也可以提前终止退出了④在背包问题中,发现目前的价值加上剩下所有价值都达不到目前的最优解,那么这条路也没有意义;提前终止,而不是最后遍历完才发现不合适,这就体现了“剪”。
其实做题中也发现有许多题DFS和BFS都能解答,各有各的好处,就是看哪个更方便适合。DFS适合搜索全部的解,在记录路径的时候也会简单一点,而BFS用来搜索最短径路的解比较好,当求最少步数或者最少干什么的次数时用BFS更方便。因为BFS搜索过程中遇到的解一定是离最初位置最近的,所以当找到解时一般就是最优解不用再像DFS那样搜全部还需要记录许多其他的位置。
PS一点:n皇后问题 (DFS+回溯):map[a]=b能记录一个皇后在第a行b列;用map时判断两皇后是否在同一对角线上就容易多了:abs(map[v]-map[i])==abs(v-i);row[i]=true则代表这一行被占用,在进行下一次搜索后,(回溯)row[i]=false还原这一行未被占用。迷宫问题:有起点和终点的迷宫,一般要先在main主函数里输入数据的时候找到起点和终点(可用STL的map[a][b]='A'代表第a行b列是A )
虽然看的篇数不是很少但是看懂的也不多,大部分题解都是只有代码没有解释的,剩下的就要靠自己参透,要完全读懂题意才有可能看懂题解。也是第一次尝试一天看十篇,有几天没有够数也是通过周末补回来的,几乎看每一篇博客都是困难的,从理解题意再到理解代码,往往很难理解到核心代码的意思,除了几个很简单的一看就懂的题,别的我每一篇都要花很长时间才能理解,还有好多篇我最终也没看懂什么意思,也还没能做到费老说的看不懂的过五遍必懂,不懂就再看,大概还是因为对算法的原理理解的不够透彻吧。希望能继续锻炼我看博客以及写代码的能力,还要更好的抓住我的空闲时间,争取下周能看透更多的博客,如果真的能够努力坚持下去这些天,哪天回头看一眼就会发现自己会从中学到了很多,总之,坚持就是胜利!本周的总结就这些了,加油
!