用BufferedReader快速输入有巨坑!!大佬们都是这么输入的;高精度题用BigInteger太爽啦!

刷洛谷题单第二天,今天第一道题(P2670 [NOIP2015 普及组] 扫雷游戏)还是挺简单的,但是又被现实给了一级大逼兜子,做这题关键还是想熟悉Java的快速输入。还有做这道题很容易出现RE错误,下面总结了常见的RE错误导致情况(点击跳转下文)。还用BigInteger爆杀了P1009 [NOIP1998 普及组] 阶乘之和问题(点击跳转下文),当然,作为刷算法,还用数组模拟了P1601 A+B Problem(高精)问题(点击跳转下文

P2670 [NOIP2015 普及组] 扫雷游戏

P2670 [NOIP2015 普及组] 扫雷游戏 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

我的上篇文章详细讲关于Java最快速输入输出法(关于StreamTokenizer和PrintWriter的应用)但是,StreamTokenizer有个不足就是,不能输入特殊符号,而今天做的洛谷这道题P2670 [NOIP2015 普及组] 扫雷游戏需要输入“*”和“?”,所以肯定得另外找过一个块输法了,这里就有另一个块输工具:BufferedReader。

BufferedReader实例化以及使用模板:

public class Main {
	// 用BufferedReader才能读特殊字符
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	public static void main(String[] args) throws IOException {    // 注意这里一定要抛出异常
        // 输入数字:
		String[] dimensions = in.readLine().split(" ");  // 例如,输入2 3
        int n = Integer.parseInt(dimensions[0]);         // 2
        int m = Integer.parseInt(dimensions[1]);         // 3
        // ...代码
        // 输入字符串:
        String str = in.readLine();    
        // 循环输入字符串:
        String line;  
        while ((line = in.readLine()) != null) {  
          // 当你输入一个空行并按下回车时,程序将停止读取  
          if (line.isEmpty()) {  
              break;  
          }  
          System.out.println(line);  
       }  
       // ...代码
    }
}

什么就是BufferedReader常用的输入数字和字符串的方法,大家会发现,输入数字的时候要利用String类的split方法分割然后用Integer类转换才能得到,看上去有点麻烦,而BufferedReader中恰好有一个直接返回int型的方法:read();这不可以直接输入吗?哈哈,本人就是踩了这个坑,没了解方法内部具体实现情况,只看返回值来使用,导致一开始数据怎么都输入不进去。

BufferedReader中的read();方法确实是返回int型但是,它返回的是输入字符的ASCII码值。所以,想要输入数字,只能用上面实例中的代码,防止踩坑啊。

扫雷游戏题解:

思路:

我的思路是:定义一个int型的二维数组作为雷区结果集minefield (最后根据这个集合来输出),遍历ch字符二维数组,当遇到一个雷,首先给雷区数组minefield 的这个位置设置一个最小值(Integer自带的MIN_VALUE,是个很小的负数),然后扫描它的八个方向,满足没有造成数组越界情况时,给雷区数组周围的位子都自增1,这样结束之后,在结果集minefield 中,非雷区就会标记周围雷区情况,代码如下:

代码:


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class Main {
	// 用BufferedReader才能读特殊字符
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	public static void main(String[] args) throws IOException {
		String[] dimensions = in.readLine().split(" ");  
        int n = Integer.parseInt(dimensions[0]); // 行数  
        int m = Integer.parseInt(dimensions[1]); // 列数  
        
		char[][] ch = new char[n][m];
		int[][] minefield  = new int[n][m];
		
		for(int i = 0; i < n; i++) {
			String str = in.readLine();
			ch[i] = str.toCharArray();
		}
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) {
				if(ch[i][j] == '*') {
					minefield [i][j] = Integer.MIN_VALUE;
                    // 注意是否越界条件,否则在洛谷提交中会出现RE错误
					if((i - 1) >= 0) {
						minefield [i - 1][j]++;
					}
					if((i - 1) >= 0 && (j + 1) <= m - 1) {
						minefield [i - 1][j + 1]++;
					}
					if((j + 1) <= m - 1) {
						minefield [i][j +1]++;
					}
					if((i + 1) <= n - 1 && (j + 1) <= m - 1) {
						minefield [i + 1][j + 1]++;
					}
					if((i + 1) <= n - 1) {
						minefield [i + 1][j]++;
					}
					if((i + 1) <= n - 1 && (j - 1) >= 0) {
						minefield [i + 1][j - 1]++;
					}
					if((j - 1) >= 0) {
						minefield [i][j - 1]++;
					}
					if((i - 1) >= 0 && (j - 1) >= 0) {
						minefield [i - 1][j - 1]++;
					}
				}
			}
		}
		for(int i = 0; i < n; i++) {
			for(int j = 0; j < m; j++) {
				if(minefield [i][j] < 0) {
					out.print('*');
				}else {
					out.print(minefield [i][j]);
				}
			}
			out.println();
		}
		out.close();
	}
}
运行结果图:

 这题难就难在八个方向的判断这里,很容易出现数组越界错误,当出现数组越界错误时,洛谷会出现一个叫“RE”的错误,RE:运行时错误。

RE错误常见的情况:

  1. 数组越界:尝试访问数组超出其定义范围的元素。
  2. 空指针解引用:试图通过空指针访问对象或内存。
  3. 除以零:在整数或浮点数除法中,除数为零。
  4. 栈溢出:通常由于无限递归或过大的局部变量/数组分配导致。
  5. 内存溢出:尝试分配超过可用内存的空间。
  6. 访问非法地址:试图读取或写入不属于程序的内存地址。
  7. 使用未初始化的变量:在某些情况下,使用未初始化的变量可能导致运行时错误。
  8. 浮点数异常:如除以零、溢出、下溢或非法的浮点操作。

洛谷高精度阶乘之和:

P1009 [NOIP1998 普及组] 阶乘之和

自从知道了Java自带处理高进度的类(BigInteger)妈妈再也不用担心我不会做高精度题啦(下文纯属熟练Java的BigInteger类,并非用数组求解的一般解法题)

首先总结一下BigInteger常用方法:

BigInteger常用方法:

构造方法

  • BigInteger(String val):将字符串转换为 BigInteger。

算术运算

  • BigInteger add(BigInteger val):返回其值为 (this + val) 的 BigInteger。
  • BigInteger subtract(BigInteger val):返回其值为 (this - val) 的 BigInteger。
  • BigInteger multiply(BigInteger val):返回其值为 (this * val) 的 BigInteger。
  • BigInteger divide(BigInteger val):返回其值为 (this / val) 的 BigInteger。整数除法,丢弃小数部分。

静态方法

  • BigInteger valueOf(long val):返回其值等于指定 long 的值的 BigInteger。
  • BigInteger ONE:BigInteger 常量 1。
  • BigInteger ZERO:BigInteger 常量 0。

那么这道题,利用BigInteger类,那就不用担心溢出的问题了,直接正常的求阶乘即可,求阶层很简单,用一个temp储存从1~n 之间每一个数的阶层,然后用一个sum累加即可,其实一个for循环就行,因为每次temp都保存了上一个数的阶乘,即:n! = (n - 1)! * n;

因此会用到 BigInteger.ZERO 来初始化sum,用 BigInteger.ONE 初始化temp为1,当要累乘时,要用到multiply,以及把for循环里的i转化为BigInteger,要用上BigInteger.valueOf(i),综上便可以写出以下代码:

代码如下:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigInteger;

public class Main {
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
	public static void main(String[] args) throws IOException {
		String n = in.readLine();
		int N = Integer.parseInt(n);
		 BigInteger sum = BigInteger.ZERO;  
         BigInteger temp = BigInteger.ONE;  
		for(int i = 1; i <= N; i++) {
			temp = temp.multiply(BigInteger.valueOf(i));
			sum = sum.add(temp);
		}
		out.print(sum);
		out.close();
	}
}

也是舒舒服服的AC了(*^▽^*)

 当然~这是一道算法题,对于高精度的运算,本质上还是一种模拟,用数组模拟,所以接下来,用模拟法做一道 P1601 A+B Problem(高精)吧(你问我为什么不做这道题了,哈哈哈,因为难的我暂时不会了)

P1601 A+B Problem(高精)

P1601 A+B Problem(高精) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

做这道题的时候呢,一开始卡住了,知道大致的思路,就是把每个数字用数组存储然后按位求和,把每一位求和的个位保留存入结果中,十位(进位位)保留到下一次按位求和中。但是在做的时候发现了下面这些问题。

遇到的问题

  1. 不清楚用什么类型数组存储A和B的每一位。其实根据思路,我们后续是需要拿出每一位来求和的,即:需要求“数字和”,那么用char数组就不行了,因为char不方便把字符变成数字,所以用String(用Integer.parseInt()把字符串转化为数字)
  2. 循环怎么写?最终结果多长?做这题的时候,思路很简单,可是自己写的时候,发现哎~这个循环咋整啊,循环啥时候停啊,还有长度是多少嘞??其实,两数之和的长度一定是不超过两数中,位数较大者+1的,所以,可以先确定结果的长度为两数中位数较大者+1,这样,循环的终止条件也可就是结果的长度,因为最后一个进位也要加上去。

代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.math.BigInteger;

public class Main {
	static BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); // 块速输入
	static PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out))); // 快速输出
	public static void main(String[] args) throws IOException {
		// 输入的结果都用字符串数组来存储,方别后续用整型存储按位求和结果
		String[] chA = in.readLine().split("");	// readLine()就是按行读入数据,然后分割字符变成字符串数组
		String[] chB = in.readLine().split("");
		int length = (chA.length > chB.length ? chA.length : chB.length) + 1;	// 这是保存最终结果长度的,因为是求和,最大长度肯定是输入的两数中最长的长度加1
		StringBuilder result = new StringBuilder();								// 结果用StringBuilder,因为后面要用到字符串拼接和转置结果
		int sum = 0;	// 每一位求和的结果
		for(int i = 0; i < length; i++) {
			if(i < chA.length) {	// 为了防止数组越界,有可能这个数字已经加完了,当i大于他的长度时,就不用求它的和了
				sum += Integer.parseInt(chA[chA.length - i - 1]);
			}
			if(i < chB.length) {
				sum += Integer.parseInt(chB[chB.length - i - 1]);
			}
			// sum为A和B的每一位之和,从个位开始	
			result.append(sum % 10);	// 把每一位之和的个位存入结果集中,结果为倒序
			sum /= 10;	// 进位将会保留在下一次按位求和中
		}
		BigInteger a = new BigInteger("0");
		a.add(val);
		if(result.charAt(result.length() - 1) == '0') {
			result.deleteCharAt(result.length() - 1);
		}// 由于刚刚的length始终都比最长的大1,有可能出现两个数之和没有进位的情况,如 1 + 1 = 2,如果不加这段代码,结果会变成02
		out.print(result.reverse());// 逆序输出
		out.close();
	}
}

结果图:

 似乎和用BigInteger做差不多的运行时间哦:

  • 32
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值