小白进阶之动态规划-矩阵链乘法

本文介绍了一种通过动态规划算法解决矩阵链乘法问题的方法,旨在寻找矩阵相乘顺序的最佳方案以减少不必要的计算开销。文章提供了完整的C++实现代码,并展示了如何计算最小乘法次数及对应的乘法顺序。

问题描述:

给定一个n个矩阵的序列(A1,A2,A3,...,An),希望计算它们的乘积的花销最小。用序列p= (p0,p1,p2,...,pn)表示矩阵序列的规模,m[i,j]表示计算矩阵Ai,j所需的标量乘法次数的最小值,s[i,j]记录最优值 m[i,j]对应的分割点k。

下面是源码;

matrixChain.h

#include<stdio.h>
#include<stdlib.h>
#include<limits.h>
int matrixChainOrder(int *p,int n,int **s);//动态规划-自底向上的矩阵链乘法
void printOptimalParens(int **s,int i,int j);//打印矩阵链
int memorizedMatrixChain(int *p,int n,int **t);//带备份的递归版本的矩阵链乘法
int lookUpChain(int **m,int **t,int *p,int i,int j);//寻找最短矩阵链的子函数

matrixChain.cpp

#include"matrixChain.h"
int matrixChainOrder(int *p,int n,int **s){
	int **m,i;
	m=(int **)malloc(sizeof(int *)*n);
	for(i=0;i<n;i++)
		m[i]=(int *)malloc(sizeof(int)*n);
	for(i=0;i<n;i++){
		m[i][i]=0;
		s[n-1][i]=0;
		s[i][0]=0;
	}
	int l;
	for(l=2;l<=n;l++){
		for(i=0;i<=n-l;i++){
			int j=i+l-1;
			m[i][j]=INT_MAX;
			int k,q;
			for(k=i;k<j;k++){
				q=m[i][k]+m[k+1][j]+p[i]*p[k+1]*p[j+1];
				if(q<m[i][j]){
					m[i][j]=q;
					s[i][j]=k;
				}
			}
		}
	}
	return m[0][n-1];
}
void printOptimalParens(int **s,int i,int j){
	if(i==j)
		printf("A[%d]",i);
	else{
		printf("(");
		printOptimalParens(s,i,s[i][j]);
		printOptimalParens(s,s[i][j]+1,j);
		printf(")");
	}
}
int memorizedMatrixChain(int *p,int n,int **t){
	int **m,i,j;
	m=(int **)malloc(sizeof(int *)*n);
	for(i=0;i<n;i++)
		m[i]=(int *)malloc(sizeof(int)*n);
	for(i=0;i<n;i++)
		for(j=i;j<n;j++)
			m[i][j]=INT_MAX;
	return lookUpChain(m,t,p,0,n-1);
}
int lookUpChain(int **m,int **t,int *p,int i,int j){
	if(m[i][j]<INT_MAX)
		return m[i][j];
	if(i==j)
		m[i][j]=0;
	else{
		int k,q;
		for(k=i;k<j;k++){
			q=lookUpChain(m,t,p,i,k)+lookUpChain(m,t,p,k+1,j)+p[i]*p[k+1]*p[j+1];
			if(q<m[i][j]){
				m[i][j]=q;
				t[i][j]=k;
			}
		}
	}
	return m[i][j];
}

main.cpp


#include"matrixChain.h"
int main(){
	int *p,**s,**t,n,i;
	printf("Please input the number of the matrixes:\n");
	scanf("%d",&n);
	p=(int *)malloc(sizeof(int)*(n+1));
	s=(int **)malloc(sizeof(int *)*n);
	t=(int **)malloc(sizeof(int *)*n);
	printf("Please input the size of the matrixes:\n");
	for(i=0;i<n+1;i++){
		scanf("%d",&p[i]);
	}
	for(i=0;i<n;i++){
		s[i]=(int *)malloc(sizeof(int)*n);
	}
	for(i=0;i<n;i++){
		t[i]=(int *)malloc(sizeof(int)*n);
	}
	int min1=matrixChainOrder(p,n,s);
	printf("The minimum times is:%d\n",min1);
	printf("The sequence is:\n");
	printOptimalParens(s,0,n-1);
	int min2=memorizedMatrixChain(p,n,t);
	printf("\nThe minimum times is:%d\n",min2);
	printf("The sequence is:\n");
	printOptimalParens(t,0,n-1);
	system("pause");
	return 0;
}

至此,动态规划算法的四个经典问题就全部完成了。个人感觉动态规划算法套路深深,按照套路来就可以正确利用动态规划算法解决问题了。



<think>嗯,用户想了解如何从小白成长为面试高手,特别是程序员面试的技巧和经验。首先,我需要整理已有的引用资料,看看里面有没有相关的信息。引用[1]提到了18个面试技巧,包括展示技术能力、思维过程、问题解决能力和合作态度,持续学习和实践是关键。引用[2]强调了沟通和协作技能的重要性,以及应对策略。引用[3]则分享了7个技巧,提到了技能和技巧的双管齐下,尤其是在疫情下竞争力更紧张的情况下。 接下来,我需要将这些信息结构化。可能分为几个阶段:准备阶段、实战阶段和复盘阶段。准备阶段需要技术准备和软技能,比如刷题、项目经验、沟通练习。实战阶段要注意面试中的表现,比如表达思路、遇到难题的处理方法。复盘阶段则是面试后的总结和调整。 还要注意用户是“小白”,所以可能需要从基础开始讲起,比如如何积累项目经验,如何准备基础知识。同时,结合引用中的内容,比如引用[1]提到的持续学习,引用[3]提到的疫情期间的竞争力,可以建议用户多参与开源项目或者自己做一些小项目来积累经验。 另外,用户可能不仅想知道技术方面的准备,还有软技能,比如沟通和协作,这部分引用[2]有提到,需要深入分析沟通与协作的问题,并提供策略。比如如何清晰表达自己的思路,如何展示团队合作的经验。 可能还需要考虑面试中的常见问题,比如算法题、系统设计、行为面试等,每个部分如何准备。引用[1]中的Java面试总结可能涉及到这些方面,可以借鉴。 最后,相关问题部分要生成几个相关的问题,引导用户进一步学习,比如如何准备技术面试、如何回答行为问题、如何谈薪资等。</think>### 如何从小白成长为面试高手?分阶段提升策略 #### 一、准备阶段:夯实基础与针对性训练 1. **技术能力积累** - **算法与数据结构**:优先掌握高频题型(如链表、二叉树、动态规划),使用LeetCode或《剑指Offer》刷题,注重时间复杂度分析。例如,快速排序的时间复杂度为$O(n \log n)$,但最坏情况下退化为$O(n^2)$[^1]。 - **项目经验提炼**:选择1-2个完整项目深度复盘,明确技术选型原因(如为什么用Redis而不是Memcached),突出解决问题的思路。可参考开源项目代码实现。 - **计算机基础**:重点复习操作系统(进程/线程)、网络(TCP三次握手)、数据库(索引原理)等核心概念。 2. **软技能准备** - **沟通表达训练**:使用STAR法则(Situation-Task-Action-Result)描述项目经历,例如:“在电商促销系统开发中(情境),我负责优化库存查询接口(任务),通过引入二级缓存(行动),将响应时间从200ms降低到20ms(结果)”[^2]。 - **模拟面试**:使用Pramp等平台进行实战模拟,录制回答过程并分析语言流畅度、眼神交流等细节。 #### 二、实战阶段:面试中的关键技巧 1. **技术面试应对策略** - **白板编码**:先复述题目要求确认理解,例如:“您需要我实现一个支持重复元素的二分查找对吗?”编码时持续解释思路,如:“这里使用左右指针可以避免死循环”。 - **系统设计题**:采用分层分析法,从需求分析(QPS估算)到架构设计(CDN+负载均衡+数据库分库),最后讨论容灾方案。 2. **行为面试技巧** - **冲突处理案例**:准备技术分歧的解决案例,例如:“在代码评审中同事坚持某种实现方式,我通过性能测试数据对比说服对方”。 - **学习能力证明**:展示学习曲线,如:“三个月从零掌握Kubernetes,完成了公司服务迁移”。 #### 三、复盘阶段:持续优化 1. **建立错题档案**:分类记录算法题中的错误点(如边界条件处理),系统设计中的盲区(如未考虑数据一致性)。 2. **跟踪技术趋势**:每周阅读2-3篇行业技术文章(如ArchSummit会议资料),更新知识库。 ``` # 技术栈深度掌握自查表(示例) def check_tech_stack(skill): levels = { 'Java': {'基础': '集合类原理', '进阶': 'JVM调优', '高阶': '字节码增强'}, '分布式': {'基础': 'CAP理论', '进阶': '分布式事务实现', '高阶': '一致性算法推导'} } return levels.get(skill, {}) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值