【算法与数据结构复习】| 算法笔试中输入输出的处理AND递归理解master公式

        今天跟着左程云算法课019和020,学习了【算法笔试中输入输出的处理】和【递归及master公式】。两节课都是偏重理论,简单总结一下。

一、算法笔试中的输入输出

(1)填函数风格

        填函数风格是最简单的,之前几节算法课上使用的力扣测试链接就是填函数风格回答。在后台运行的时候一般是A.B.func(a,b)这样的形式,A和B的类名以及func的函数名不可以改变。这种风格不用管测试数据和输入和输出问题,只需要把功能函数写出来就行。

(2)acm风格

        acm相比于填函数风格更加复杂一些,需要自己在main函数中处理输入和输出数据。

        那么关于输入输出数据的处理,输入数据一般使用BufferedReader(而不使用Scanner),原因在于Scanner会频繁的进行文件IO,涉及到磁盘与内存和CPU之间的IO,速度会比较慢;用BufferedReader的话是开辟一块内存一次性把文件给读进来,这样涉及文件IO的次数会减少很多,速度会更快一些。输出数据也是同样的道理,使用PrintWriter而不使用System.out。具体的代码如下(求矩阵的最大子集和,解题代码不贴,只贴main中输入输出数据的处理):

	public static void main(String[] args) throws IOException {
		
		// 把文件里的内容,load进来,保存在内存里,很高效,很经济,托管的很好
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		// 一个一个读数字
		StreamTokenizer in = new StreamTokenizer(br);
		// 提交答案的时候用的,也是一个内存托管区
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		
		while (in.nextToken() != StreamTokenizer.TT_EOF) { // 文件没有结束就继续
			// n,二维数组的行
			int n = (int) in.nval;
			in.nextToken();
			// m,二维数组的列
			int m = (int) in.nval;
			// 装数字的矩阵,临时动态生成
			int[][] mat = new int[n][m];
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < m; j++) {
					in.nextToken();
					mat[i][j] = (int) in.nval;
				}
			}
			out.println(maxSumSubmatrix(mat, n, m));
		}
		out.flush();
		br.close();
		out.close();
	}
(3)不推荐使用临时空间,推荐使用全局静态空间

        acm在计算空间的时候,不会管你前面开创的临时数组空间是否已经销毁,只要开辟了就算。假如在一个while循环里开辟临时数组arr[m][n],这个循环跑N次,那么acm计算的空间使用量就是N*m*n;所以在最前头开辟一个静态数组空间,可以反复利用。代码如下:

	// 题目给定的行的最大数据量
	public static int MAXN = 201;

	// 题目给定的列的最大数据量
	public static int MAXM = 201;

	// 申请这么大的矩阵空间,一定够用了
	// 静态的空间,不停复用
	public static int[][] mat = new int[MAXN][MAXM];

	// 需要的所有辅助空间也提前生成
	// 静态的空间,不停复用
	public static int[] arr = new int[MAXM];

	// 当前测试数据行的数量是n
	// 当前测试数据列的数量是m
	// 这两个变量可以把代码运行的边界规定下来
	public static int n, m;
	

	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StreamTokenizer in = new StreamTokenizer(br);
		PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
		while (in.nextToken() != StreamTokenizer.TT_EOF) {
			n = (int) in.nval;
			in.nextToken();
			m = (int) in.nval;
			for (int i = 0; i < n; i++) {
				for (int j = 0; j < m; j++) {
					in.nextToken();
					mat[i][j] = (int) in.nval;
				}
			}
			out.println(maxSumSubmatrix());
		}
		out.flush();
		br.close();
		out.close();

	}
	
	// 求子矩阵的最大累加和,后面的课会讲
	public static int maxSumSubmatrix() {
		int max = Integer.MIN_VALUE;
		for (int i = 0; i < n; i++) {
			// 因为之前的过程可能用过辅助数组
			// 为了让之前结果不干扰到这次运行,需要自己清空辅助数组需要用到的部分
			//arr数组0到m-1的位置填充0
			Arrays.fill(arr, 0, m, 0);
			for (int j = i; j < n; j++) {
				for (int k = 0; k < m; k++) {
					arr[k] += mat[j][k];
				}
				max = Math.max(max, maxSumSubarray());
			}
		}
		return max;
	}
(4)按行读取

        在(2)中的StreamTokenizer是一个数一个数的读,如果碰到需要一行一行读的数据(比如要计算每一行数的和,但是每一行数据的个数并不一致),StramTokenizer并不能识别/n,那就需要一行一行的读出来然后按空格split。代码如下:

	public static void main(String[] args) throws IOException {
		BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
		PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
		
		line=in.readLine();
		while(line!=null) {
			parts=line.split(" ");
			sum=0;
			for(String num:parts) {
				sum=sum+Integer.valueOf(num);
			}
			out.println(sum);
			line=in.readLine();
		}
		out.flush();
		in.close();
		out.close();
	}

二、递归和master公式

(1)理解递归

        从思想上理解递归,想不明白的时候画递归调用图是非常重要的,有利于分析递归。

        从底层上理解递归,递归是通过系统栈来实现的;比如说f(0,3)要分解成f(0,1)和f(2,3),要进入f(0,1),先把f(0,3)压入系统栈中,f(0,1)运行结束返回f(0,3)时,再从系统栈中把f(0,3)出栈恢复重建现场。

        任何递归都可以改成非递归,可以自己创造一个栈,模仿系统栈的入栈出栈过程。自己创造栈的话可能会更加优化一些,因为系统栈是把所用的信息一起压入栈中,而自己用内存空间来实现递归的话,可能入栈出栈的是一些关键信息,可以比系统栈更加简单快速一些。

(2)递归改成非递归的必要性

        首先工程中是一定要改的,除非数据量再大递归层数也一定不深,比如归并排序,快速排序,线段树和平衡树等。举个例子,归并排序就是二分之后使左边有序,右边有序,然后整合一下左右(整合这个动作是非递归的)。其递归的层数为O(log2 N),也就是说假如有2^64个数据归并排序的话,递归的层数也就是64层。

        其次就是算法比赛和面试中,能通过就不用改,除非是时间复杂度不行通不过再改。

(3)master公式

        master公式用来确定递归的时间复杂度,看公式可以看出来,master公式只能用于估计子问题等规模的时候的时间复杂度。具体总结如下。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值