算法学习(四)

一、迭代加深搜索(Iterative Deepening DFS,IDDFS)

迭代加深搜索结合了BFS和DFS的思想。当我们遇到一个搜索问题是,它的搜索树非常特别,深度极深,宽度极广,使用DFS递归过长,使用BFS会使得队列爆炸。因此我们可以使用IDDFS解决这个问题。它的思想是:先假定一个搜索深度为1,然后用DFS搜索到第一层停止,在这个过程中,每一层的广度上采用BFS搜索。如果没有找到,则向深度为2的第二层搜索,依次递归。逐步扩大搜索的深度,直到找到答案。

下面用埃及分数的例子加以说明。

(*埃及分数:例如19/45 = 1/3+1/12+1/180,也可以写成19/45 = 1/5+1/6+1/18,即把一个分数拆分成数个1/n的和,且加数中全不相同,要求:加数的个数尽可能小,同时最小的分数越大越好。)

这个问题有几个难点:

  1. 在埃及分数计算时,如何不让分数被化为小数从而损失精度?
  2. DFS搜索时如何剪枝?
  3. 如何保证最优解?

4.找到下一个最大的埃及分数后该如何处理?

对于第一个问题,我们可以这样解决:

 

这样我们就解决了第一个问题。这个过程用GCD( )求取最大公约数。注意在b/a-1/k后需要约分。

接下来解决关于剪枝的问题。下图很好的解释了这个问题:

 

以及代码的复现:

    

 

二、并查集(Disjoint Set)

 

   并查集是指:将编号1-n的n个对象划分为不相交集合,在每个集合中,选择某个元素代表所在的集合。并查集主要用于处理一些不相交集合的合并问题。

并查集操作的简单原理用一个简单的例子加以说明。假设:有n个人一起吃饭,有人相互认识。认识的人想跟认识的人坐在一张桌子上,那么给出认识的人的关系,求解桌子的数量。现在我们先用图来表示一下我们的思路:

假设有1,2,3,4,5分别代表五个集合,A,B,C,D,E分别代表五个人。先假设他们有如下关系:

1 2 3 4 5

A B C D E

即对应的人是对应集合中的元素。若A认识B,那么可以把A并入到集合2中,即把节点1的集合1改成节点2的集合2。示意图如下:

 

注意初始化是用元素表示它的集合s[i],例如元素1的集合s[1] = 1。

附上代码的复现:

当然这个算法可以继续优化,简单说一下路径压缩。在查询元素i所属集合需要搜索路径找到根节点,若在返回时把所属的集合改成根节点,下次搜索该元素的时候就能一常数时间内得到结果。

 

三、二叉树

用深度优先搜索二叉树,有以下方式:

  1. 先序遍历,即按照父节点,左儿子,右儿子的顺序进行遍历。
  2. 中序遍历,即按照左,父,右的顺序遍历。
  3. 后序遍历,按照左,右,父的顺序遍历。

需要注意的是,如果某刻二叉树已知“中序遍历+先序”或者“中序+后序”,都能确定唯一的一棵二叉树。但如果只知道“先序+后序”,则不能唯一确定一棵树。

二叉树的第n层最多有2^(n-1)个节点,如果每一层的节点数都是满的,称为满二叉树。如果满二叉树只在最后一层有缺失,那么称为完全二叉树。

 

  • 二叉搜索树(Binary Search Tree,BST)

BST有如下特征:

  1. 每个元素有唯一的键值。通常把键值存放在BST的节点上。
  2. 任意一个节点的值,比它左子树的所有节点的键值大,比它右子树的所有节点键值小。
  3. BST排序和快速排序十分类似,它们实质上是做了相同的比较,只是比较的顺序不同。对于一个随机化的BST来说,它的树结点的平均深度是log n的。利用Jenson不等式证明,即F[E(x)] ≤ E[F(x)]。

一般而言,我们更希望一个数是平衡二叉树,而非链表一样的二叉树。这里补充说明一下平衡二叉树(AVL):

平衡二叉树满足:

1. 是「二叉排序树」(即所有左子树的值小于根节点,右子树的值大于根节点)

2. 任何一个节点的左子树或者右子树都是「平衡二叉树」(左右高度差小于等于 1)

这样就避免了二叉树成为一个链表一样的排列,这个时候查找的效率是最差情况(the worst case),它是O(n)的复杂度。

这个问题需要动态的调整使得二叉树保持平衡。BST的算法有AVL树,红黑树,Splay树等,可以优化树的结构。

 

总结:

这个星期阅读了有关搜索技术和一些高级数据结构内容。个人感觉有关二叉树的问题比较难,在网上也找了一些相关的网课,如MIT的算法导论,里面讲解的有关平衡二叉树的数学性质感觉没怎么听明白。然后有关红黑树,Treap树也看了一些,感觉关于树的动态调整还是理解不够。下个星期在进行详细的学习。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python算法学习是指掌握使用Python语言来解决各种问题的方法和技巧。在学习过程中,有几个重要的方面需要注意。 首先,了解基本的算法概念是必不可少的。例如,了解常见的排序算法(如冒泡排序、快速排序)和查找算法(如二分查找)等。这有助于我们理解算法的原理和思想。 其次,学习Python中的内置数据结构和函数,如列表、字典和字符串等。熟悉这些数据结构和函数的使用方法,可以帮助我们更好地解决问题,并编写出高效的算法。 第三,了解常用的算法设计技巧。例如,贪心算法、动态规划和分治法等。这些算法设计技巧可以应用于不同类型的问题,帮助我们找到解决问题的最佳方法。 第,编写和调试算法代码是学习过程中的关键步骤。我们可以通过编写小型的算法程序来练习和巩固所学的知识。同时,调试是解决代码错误和优化算法的重要环节,需要耐心和细心。 最后,不断练习和实践是提高算法能力的关键。我们可以通过刷题、参加编程比赛和项目实践等方式来提高自己的算法水平。与其他程序员交流和分享经验也是相互学习的好机会。 总之,Python算法学习是一个渐进的过程,需要不断学习、实践和提高。通过合理的学习方法和坚持不懈的努力,我们可以不断提高自己的算法能力,并运用它来解决实际问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值