算法在计算中的作用
1.1 算法
非形式的说,算法就是任何良定义的计算过程。
所以,在这句话里,我们可以这样理解: 算法本质上是一个计算过程,然后是什么的计算过程呢?它是任何良定义的计算过程。既然是个计算过程,那么就肯定有输入和输出(结果),因此,我们把这个计算过程中某个值或者值的集合作为输入,对应的,我们把输入之后产生的某个值或者值的集合作为输出。
就像上面的图所示,算法可以理解为:就是把输入转换成输出的计算步骤的一个序列。
除了上面这个把算法视为计算过程的角度之外,还有一个角度,那就是把算法视为一种工具,一种用于求解良说明的计算问题的工具。
一般来说,问题陈述说明了期望的输入/输出关系。 而算法则描述一个特定的计算过程,来实现该输入/输出关系。
什么意思呢,我们通过力扣上的算法题来理解这一句话。
图片上的是一道算法题,红色框框中的就是问题陈述部分,它描述了我们所期望的输入与输出的关系,什么关系呢?根据题目我们可以知道,输出的两个数组下标在数组中对应的元素的值相加之后会等于target的值,这就是这道题目中输入与输出的期望关系。
在上面这道题目中,我们将每一个输入序列称为该问题的一个实例。 一般而言,每个问题都会有很多个实例,但是并不是所有输入都可以称为是这个问题的实例的。
一般来说,问题的实例由该问题解所必须的(满足问题陈述中强加的各种约束)输入组成。
也就是说,像下面的这种输入是不能称为该问题的实例的:
nums = 1, target = 9
nums = [1,2,3,4], target = 3.14
nums = ['apple', 'orange', 'pine'], target = 'gaga'
因为上面的这些输入都没有满足问题陈述中强加的各种约束(nums必须为整数数组,target必须为整数)。
如果在力扣上刷过题应该都知道,某一道题的算法是会分对错的,当然,这个对错指的是某个算法是否能解决当前问题,能解决我们说这个算法是对的,反之则说这个算法对这个问题而言是不对的。 注意到了吗,这里是加了限制条件的,因为同一个算法,对不同的问题所能达到的效果是可能不一样的,所以算法的对错只针对它所要解决的问题而言。
如果有一个算法,对问题的每个输入实例,这个算法都会给出正确的输出停机,那么我们称该算法是正确的,并称正确的算法解决了给定的问题。
不正确的算法一定没用吗?其实也不是的,不正确的算法只要其错误率可控有时候可能还是有用的。
算法的描述形式有很多种,比如说你可以将算法用英文来说明,也可以将算法写成一个计算机程序,或者你甚至可以用硬件设计来描述它也行,对算法的描述的样式是多种多样的,但是要求只有一个,那就是这个描述方式必须可以精确的描述算法所要遵循的计算过程。
数据结构
数据结构是一种存储和组织数据的方式,旨在便于访问和修改。不存在一种通用或者说适用于所有用途的单一数据结构。
也就是说,每种数据结构都有其优势和其局限性,所以我们要根据我们所需要解决的问题去选择适合的数据结构。
NP完全和NP不完全问题
我们对算法的关注点一般都是算法的效率的高低,而我们对效率的量度一般是速度,也就是说,我们关心的一般是一个算法需要花费多长时间才能产生结果。
但是,有一些问题,目前还不知道有效的解法。这种问题被我们称为是NP完全的。
NP完全问题有以下几点特性:
- 至今为止,不曾找到一个对NP完全问题的有效算法,但是,也没人能证明NP完全问题确实不存在有效解法。
- 如果任何一个NP完全问题存在有效解法,那么所有的NP完全问题都存在有效解法。
- 有几个NP完全问题类似于一些存在着已知有效算法的问题。
我们关注NP完全问题的意义在于,当我们在实际应用中遇到的时候,避免花费许多时间在可能毫无结果的探寻中寻找有效解法,如果我们能证明这个问题是NP完全的,那么我们可以选择开发一个有效的算法,这个算法给出的是好的解,但不必一定是最好的解。
而想这种给出好的解的有效算法,存在一个有效算法给出的解离最小可能解不太远,我们称这个算法为近似算法。