数据结构初体验-迭代与递归、动态规划

数组求和-迭代

**时间复杂度一知半解,继续学习 **

int Sum(int A[],int n){
	int sum=0;  //O(1)
	for(int i = 0;i < n; i++){   //O(n)
		sum += A[i];    //O(1)
	}
	return sum;   //O(1)
}

时间复杂度:O(n)
空间复杂度:计算除输入外,循环中需要的空间,在此包括累加器sum和内部循环的控制变量i,所以空间复杂度为O(2)

减而治之策略

思想:将n看作迭代的规模,循环每经过一次迭代,尚未参与统计的元素个数,即剩余的有效问题的规模就递减一个元素,这种不断蚕食,削弱有效问题规模的大小,称为减而治之策略
在这里插入图片描述

数组求和-线性递归 / 递归跟踪

int Sum(int A[],int n){
	return n < 1 ? 0 : Sum(A,n-1) + A[n-1];
	//A[n-1]为平凡的问题,sum(A,n-1)为更小规模的问题
}

每一个递归实例只会生成一个递归实例,可以组成线性次序,称为线性递归
时间复杂度:递归实例sum(A,n-1)可以忽视掉,因为本身消耗为O(1),可以归纳到它所调用的递归实例中。所以计算其复杂度,即O(1) * (n + 1);也就是渐近的O(n);

每一个递归实例只会生成一个递归实例,可以组成线性次序,称为线性递归。简单直观,只适用于简单的递归模式。
递归基”是递归函数的一种平凡情况,只有有递归基,递归才不会一直进行下去。

递归方程:
在这里插入图片描述
在这里插入图片描述
将规模为n的问题,划分为规模为n-1的缩减问题,与O(1)的平凡问题之和。

数组倒置-递归

void reserve( int * A ; int lo ; int hi){
	if( lo < hi){
		 swap( A[lo] , A[hi] );
  		reserve(A; lo + 1; hi -1);
	}
	else {
		
	} 	
}

思想:
在这里插入图片描述
-迭代原始版:

void reserve( int * A ; int lo ; int hi){
	 if( lo < hi){  //判断递归基
   		swap( A[lo] , A[hi] );
    		lo++;
    		hi--;
		goto next;
 }
 else {
  
 }  
}

-迭代精简版:

while(lo < hi){
	swap(A[lo ++] ;A[hi--]);
}

分而治之策略

在这里插入图片描述
数组求和-二分递归

int Sum(int A[],int lo; int hi){
 	if(lo = hi)
 	{
 		return A[lo];
 	}
 	int mid = (lo + hi) >> 1;
 	return Sum(A. lo, mid) + Sum(A, mid + 1; hi);
}

时间复杂度:T(n) = O(1)*n = O(n)
在这里插入图片描述
数组中最大的两个整数值,要求元素比较的次数尽可能少

双指针思想
指定两个指针存储最大值及次大值索引,迭代数组,先于次大值x2比较,再与最大值x1比较
比较次数:最好情况 1+(n-2)*1 = n-1
最坏情况 1+(n-2)*2 = 2n-3
在这里插入图片描述

public int[] max2(int A[],int lo,int hi)
{
  	int x1 = lo,x2 = lo +1;  //初始化x1,x2;x1存储最大值,x2存储次大值
  	if(A[x1 = lo] < A[x2 = lo +1])
  	{
   		int i = x1;
  	 	x1 =x2 ;
   		x2 = i;
  	}  
  //从lo+2即第三个元素开始比较,先与x2次大值比较,在于最大值比较  
  	for(int i=lo + 2;i < hi;i++)
  	{
   		if(A[i] > A[x2]) {    
    			x2 = i;    
    			if(A[i]>A[x1])
    			{
     				x1 = i;
    			}
   		}
  	}    
  	int [] Res = {A[x1],A[x2]};
  	return A[x2];
 }

递归的分而治之策略求两个最大值
在这里插入图片描述
将数组分为左右部分,分别求出最大值和次大值,再将两个最大值进行比较求出整体最大值,将次大值与较小最大值比较得出次大值。
在这里插入图片描述

动态规划

在效率上讲,递归并不总是能让我们满意。
动态规划:通过递归找到问题的本质,并给出初步的解之后,再将其等效的转化为迭代的形式。

Fib()函数

1、递归思想
在这里插入图片描述
在这里插入图片描述
当计算不超过100项时,计算时间就已经超过了三生三世,所以算法虽然在逻辑上没有问题,但是在计算时间上存在问题。

分析低效率原因:各递归实例被重复多次的调用
在这里插入图片描述
2、解决思路:令每一个递归实例只计算一次,先检查是否已经对此进行过计算,若计算过则直接取值,从而减少计算次数。
在这里插入图片描述
解决方法A(记忆):将已计算过结果的实例制表备查;空间复杂度为O(n)
解决方法B(动态规划):颠倒计算方向,由自顶而下递归改为自下而上迭代。
在这里插入图片描述

int g = 1, f = o;   //f(1)和f(0)
while(o < n--)
{
	g = g + f;
	f = g - f;
}
return g;

复杂度分析:时间复杂度与n有关,为O(n);空间复杂度只占用了g和f两个存储空间,即两个常数复杂度O(1)

最长公共子序列LCS

两个序列公共子序列中的最长者

递归求解:
在这里插入图片描述
1、通过序列长度确定递归基;
2、减而治之策略:首先对末端字符比较,若相等,则去除末端,变成更小规模的子问题与平凡问题。
在这里插入图片描述
3、分而治之策略:若末端字符不相等,则分为两种情况,去除任一序列的末端字符与另一完整序列继续比较。
复杂度分析:每经过一次对比,原问题规模减一,即至少一个序列的长度减一。
最好的情况是只出现减而治之,则复杂度为O(n+m)
最坏情况如下,出现大量重复的子问题,复杂度为O(2n)

在这里插入图片描述
引入动态规划:消除重复计算,提高效率
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值