python-027-递归-求序列最大值、计算第n个调和数、转换字符到整数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python-027-递归-求序列最大值、计算第n个调和数、转换字符到整数相关的知识,希望对你有一定的参考价值。

参考技术A

递归,emmmmmmm,拥有一种魅力,接近人的立即思维,容易理解,又不容易理解。

递归算法的优点: 它使我们能够简洁地利用重复结构呈现诸多问题。通过使算法描述以递归的方式利用重复结构,我们经常可以避开复杂的案例分析和嵌套循环。这种算法会得出可读性更强的算法描述,而且十分有效。

但是 ,递归的使用要根据相应的成本来看,每次递归python解释器都会给一个空间来记录函数活动状态。但是有时候内存成本很高,有时候将递归算法转为非递归算法是一种好办法。

当然我们可以换解释器、使用堆栈数据结构等方法,来管理递归的自身嵌套,减小储存的活动信息,来减小内存消耗。

最近算法学到了递归这一块,写了三个课后习题:

给一个序列S,其中包含n个元素,用递归查找其最大值。

输出:

调和数:Hn = 1 + 1/2 + 1/3 + ··· + 1/n

输出:

例如:"12345"<class \'str\'> 转换为12345<class \'int\'>

输出:

递归分为线性递归、二路递归、多路递归。

计算机算法 期末复习个人笔记(部分)

可能的填空

算法是什么

算法是求解问题的一系列计算步骤

算法设计要求

  • 正确性
  • 可使用性(用户友好)
  • 可读性
  • 健壮性(容错)
  • 高效率和低存储率

算法特性

  • 有限性
  • 确定性
  • 可行性
  • 输入
  • 输出

程序

程序=数据结构+算法

数据结构

  • 逻辑结构
  • 存储结构
  • 基本操作

数据结构是算法的基础

算法设计步骤

分析求解问题
选择数据结构和算法设计策略
描述算法
证明算法正确性
算法分析

算法分析

时间复杂度

logn

for (int i=1; i<=n; i*=2) 

注意,有2的要注意,大概是logn

空间复杂度

硬件

  • CPU
  • 存储
  • 传输

软件

  • 操作系统
  • 编译器
  • 编程语言

递归

何时使用递归

  • 定义是递归的
  • 数据结构是递归的
  • 求解方法是递归的

递归种类

  • 直接递归
  • 间接递归
  • 尾递归

递归模型的组成*

  • 递归体
  • 递归出口

递归问题的特点

  • 可以转化成一个或者多个子问题
  • 递归调用的次数必须是有限的
  • 必须有结束递归的条件

递归算法设计

  • 问题分析,给出大问题和小问题的定义
  • 确定递归体
  • 确定递归出口
  • 给出算法

例题

阶乘

int jc (int n) 
    if (n == 1) return 1;
    return n * jc(n-1);

斐波那契

int fb (int n) 
    if (n == 1 || n == 2) return 1;
    return fb(n-1) + fb(n-2);

求数组最大值

int maxElem(int i, int j) 
    int mid = (i+j)/2;
    if (i < j) 
        max1 = maxElem(i, mid);
        max2 = maxElme(mid+1,j);
        return max1>max2 ? max1 : max2;
    

int fmax(int i) 
    if (i == 1) return a[0];
    return max(fmax(i-1),a[i-1]);

所有数字之和

vector<int> vi;
int sum = 0;
void sumE(int x) 
    if (x == vi.size()-1) 
    	sum += vi[x];
     else 
        sum += vi[x];
        sumE(x+1);
    

链表销毁

void del(LinkList & node) 
    if (node != null) 
        del(node->next);
        //free(node);
        delete node;
    

二叉树先序中序后序

void xx(LinkList &node) 
    if (node != null) 
        //print node->val
        xx(node->left);
        xx(node->right);
    

void zx(LinkList &node) 
    if (node != null) 
        xx(node->left);
        //print left
        xx(node->right);
    

void hx(LinkList &node) 
    if (node != null) 
        xx(node->left);
        xx(node->right);
        //print right
    

输出每一位(n进制)

int ans = 0;
void rec(int x, int base) 
	if (x > 0) 
		ans += x%base;
		rec(x/base);
	 else 
		return ;
	

汉诺塔

void Hanoi(int n, char x, char y, char z) 
    if (n == 1) 
        //print
     else 
        Hanoi(n-1, x, z, y);
        //print
        Hanoi(n-1, y, x, z);
    

n皇后

一个函数判断该点能不能放place

一个函数放置

void queen (int i, int n) 
    if (i > n) dispasolution(n);
    else 
        for (int j=1; j<=n; j++) //j列合法
            if (place(i,j)) 
                q[i] = j;
                queen(i+1,n);
            
        
    

问四皇后两个解是什么?

第k大

//可以用优先队列priority_queue
//排序然后选出
//二分找

字符串长度

int len = 0;
string s;
void fun (int x) 
	if (s[x] == '\\0') return ;
    len++;
    fun(x+1);

int fun(int x) 
	if (ch[x] == '\\0') return 0;
	return dfs(x+1)+1;

分治

  • 排序(快排,归并)
  • 查找(二分)
  • 组合
  • 乘法

求解过程*

  • 分解原问题
  • 求解子问题
  • 合并子问题

例题

归并

nlogn

把数组一直划分到剩下两个数字,然后针对每个组进行内部的排序,最开始组内只有1个数字,然后两个组两个组进行合并,再次进行排序,以此类推,最后从n个组,合并成1个组,即完成排序

void merge(int l, int r) 
	int mid = (l + r) >> 1;
	int i = l, j = mid + 1;
	int cnt = l;
	while (i <= mid && j <= r) //只要两个组里面都还有数字那就继续
		if (arr[i] < arr[j]) 
			temp[cnt++] = arr[i++];
		 else 
			temp[cnt++] = arr[j++];
		
	
	while (i <= mid) temp[cnt++] = arr[i++];//如果左边的组里还有,那就全部弄到temp数组里
	while (j <= r) temp[cnt++] = arr[j++];//右边同上
	for (int k=l; k<=r; k++) //最后将临时数组temp的值传给arr
		arr[k] = temp[k];
	


void quick(int l, int r) 
	if (l < r) 
		int mid = (l + r) >> 1;
		quick(l, mid);//划分左右两个组
		quick(mid+1, r);
		merge(l, r);//划分完之后进行合并
	

快排

nlogn

  • 从数字中挑出一个基准数字
  • 把基准数字左边和右边的数字进行划分,即比基准数字小的数字放基准数字左边,大的放右边
  • 然后分治处理,在每一个基准分出的左边和右边都进行这样的操作
void quick_sort(int q[], int l, int r) //y总模板
    if (l >= r) return;

    int x = q[l + r >> 1], i = l - 1, j = r + 1; 
    while (i < j) 
        do i ++ ; while (q[i] < x);
        do j -- ; while (q[j] > x);
        if (i < j) swap(q[i], q[j]);
    

    quick_sort(q, l, j);
    quick_sort(q, j + 1, r);


求最大元素和次大元素

//二分

二分查找!!!

第k小元素

二分

最大连续子序列和(组合问题)!!!

棋盘覆盖!!!

大整数乘法(分治)

矩阵相乘(矩阵快速幂)

蛮力

例题

完全数

各因子加起来等于本身6=1+2+3

字符串匹配!!!

选择排序

挑最小元素到最前面

插入排序

无序插入有序

最大连续子序列和!!!

有题

幂集

给定正整数,求1-n构成的集合的所有子集

例如:1,2,3的幂集是,1,2,3,1,2,1,3,2,3,(1,2,3)

2 n 2^n 2n

转化为二进制串求解

写法:共有 2 n 2^n 2n的数量

那么遍历从1到 2 n 2^n 2n(也可以用数组来存),再判断单个位数即可

全排列(任务分配)

123,132,312,213,231,321

时间复杂度 n 2 n^2 n2

增量法

用vector的insert解决,语法:insert(vi.begin(),i)

组合 递归

图的遍历

dfs,遍历即可,注意限制条件

bfs,注意标记,限制条件以及访问相邻结点

回溯

名词解释

一个问题的解可以表示成解向量

解空间:所有取值的组合构成问题的解向量空间,成为解空间

解空间树:解空间一般组织成树形结构,因此被成为解空间树

入队形成活结点,拿出形成拓展结点,死结点就是不在拓展

回溯和dfs的异同*

  • 访问次序不同

dfs目的是遍历,回溯目的是回溯

  • 访问次数不同

dfs对访问的结点不再访问,回溯访问过的可能会再访问

  • 剪枝不同

dfs不含剪枝,很多回溯有剪枝

例题

装载问题

和01背包差不多,就是等于

子集和

还是差不多,就是递归结束特判一下

分枝限界

分枝限界和回溯的异同*

  • 在解空间树搜索问题的解
  • 两种算法均能找到一个解,所有解和最优解

区别于回溯法,搜索方式不同:回溯是dfs,分枝限界是bfs

目标不同:

  • 回溯:找出所有解
  • 分枝限界:找出一个可行解或者某种意义上最优解

都属于穷举法,最坏情况下时间复杂度都说指数阶

实现和队列实现

分枝限界的优点和缺点

可以更快的找到一个解或者最优解,缺点是要存储结点的限界值,占用内存较多

求解效率由限界函数决定,极端情况下和穷举无大区别

动态规划

动态规划和分治法的区别

分治:子问题是独立的,自顶向下

dp:子问题重叠,自底向上

名字解释

描述决策过程当前特征的量称就是状态

决策就是决策者在过程中处于某一阶段的某一状态时对面下一阶段的决定或者选择

某一状态以及该状态下的策略,与下一状态之间指标函数的关系,被称为状态转移方程

01背包专题

蛮力法

和幂集一样把可能列出来,然后所有情况都计算

以上是关于python-027-递归-求序列最大值、计算第n个调和数、转换字符到整数的主要内容,如果未能解决你的问题,请参考以下文章

用递归求菲波拉契序列第N项的值

java 求最大子序列和问题递归求解报越界异常

求两个数的最大公约数&求N个数的最大公约数

17-求连续数组和最大的序列

巧用递归解决矩阵最大序列和问题

长度为n的整数序列,把序列中的最小值与第一个数交换,最大值与最后一个数交换