刷题小问题合计——持续更新

2022-10-25 16:13:42 浏览数 (1)

刷题小问题合计

  • 一、保留两位小数
  • 二、进制转换
  • 三、数字逻辑
    • 1. 2的幂次方
    • 3.2 求因子
  • 四、字符串逻辑及处理
    • 4.1 大小写转换
    • 4.2 字符串的比较判断
  • 五、集合
    • 5.1 集合比较大小
    • 5.2 BigDecimal 与浮点类型转换的精度损失问题
    • 5.3 bigdecimal 去除末尾多余的 0 和取消科学计数法显示
  • 六、输入输出
    • 6.1 Scanner.next() 和 Scanner.nextLine()
  • Final、格式规范

一、保留两位小数

  1. 方法一 BigDecimal.setScale(int newScale, RoundingMode roundingMod)方法用于格式化小数点。 翻译:scale——范围;round——范围。

roundingMod取值:

  • 默认用四舍五入方式ROUND_UNNECESSARY,但在精确度丢失时,抛出异常
  • BigDecimal.ROUND_DOWN 直接删除多余的小数位
  • BigDecimal.ROUND_UP 进位处理
  • BigDecimal.ROUND_HALF_UP 四舍五入,HALF表示对中点进行UP算法
  • BigDecimal.ROUND_HALF_DOWN 五舍六入
  • BigDecimal.HALF_EVEN 向最接近数字方向舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。根据统计学,此舍入模式可以在统计上将累加错误减到最小,类似Java中的浮点数舍入策略。
代码语言:javascript复制
BigDecimal bg = new BigDecimal(f);
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
  1. 方法二 DecimalFormat类用来格式化小数(Decimal还有十进制的意思),0 表示如果位数不足则以 0 填充,# 表示只要有可能就把数字拉上这个位置。
代码语言:javascript复制
DecimalFormat df = new DecimalFormat("#.00");
System.out.println(df.format(f));-

// 额外用法:将格式嵌入文本
System.out.println(newDecimalFormat("光速大小为每秒,###米。").format(c));
  1. 方法三 String.format参考文章,该方法类似C语言中的printf格式化输出,其中可以指定的语言环境。
代码语言:javascript复制
float result = String.format("%.2f", f);
  1. 方法四 MessageFormat、DateFormat、NumberFormat是Format三个常用的子类,常用于国际化。
代码语言:javascript复制
NumberFormat nf = NumberFormat.getNumberInstance(); // 得到默认的数字格式化显示
nf.setMaximumFractionDigits(2); // integer整数,fraction分数
System.out.println(nf.format(f));
  1. 方法五 floor 返回不大于的最大整数(翻译:地板) round 是四舍五入的计算 ceil 是不小于他的最小整数(翻译:天花板) 注意:函数返回的都是int类型,需要*100/100处理
代码语言:javascript复制
System.out.println((float)(Math.round(f*100)/100)); //如果要求精确4位就*10000然后/10000
  1. 补充:StringBuilder的setLength()方法
代码语言:javascript复制
StringBuilder sb = new StringBuilder(String.valueOf(m));
System.out.println(m.indexOf("."));
sb.setLength(10   m.indexOf(".")   1); // 保留十位小数
System.out.println(sb.toString());

二、进制转换

代码语言:javascript复制
思路:
	整数部分除2逆向取余
	小数部分乘2正向取整

注意:

  • 利用Math.floor来取整数部分;
  • 利用StringBuilder来拼接小数部分,利用reverse()函数来进行字符串反转;
  • 注意计算后的数据类型需要转换成int才能直接拼接。

三、数字逻辑

对于大数据问题,如果暴力求解必定超时,不妨先写出一些(不)符合的数,尝试寻找规律。

1. 2的幂次方

判断一个数能否写出2个以上连续的数的和,观察后发现(不符合的有0,1,2,4,8 …),只有N为2的幂次方时,不能写成连续整数和的形式。 而2的幂次方二进制表示为10…0的形式,故x & (x - 1)即可。

3.2 求因子

利用开方来减少时间,用两个数组分别来存因子,因为小于开方的因子一定对应一个大于开方的因子。

代码语言:javascript复制
for (int i = 1; i <= Math.sqrt(n); i  ) {
 	if (n % i == 0) {
    	smallToBig.add(i);
        if (n / i != i) { // 去重, 当开方后的数相等时,只收集一个
            bigTosmall.add(n / i);
        }
	}
}

四、字符串逻辑及处理

4.1 大小写转换

对于固定数量的大小写转换,可以利用replace()来特殊处理,不必用if挨个判断。

代码语言:javascript复制
// 要求:将日记中所有的元音字母大写,其他的小写
String result = scanner.nextLine().toLowerCase().replace('a', 'A').replace('e', 'E').replace('i', 'I').replace('o', 'O').replace('u', 'U');

思考:

  1. replace() VS replaceAll() 返回值String,需要将replace后的结果赋值给一个String。 replaceAll()可以用来处理正则表达式,参数是regex,但二者都是全部替换。对于简单型的替换而言,单以性能考虑,replace()是更好的选择。其中,String是接口类charSequence的一个实现类。
  1. StringBuilder的replaceAll() 由于StringBuilder的replace(int start, int end, String str)方法不能替换指定字串,故需要通过indexOf()和replace()方法来自定义,其性能相比String会快很多。
代码语言:javascript复制
/**
 * 实现StringBuilder的replaceAll
 * 
 * @param stb
 * @param oldStr 被替换的字符串
 * @param newStr 替换oldStr
 * @return
 */
public static StringBuilder replaceAll(StringBuilder stb, String oldStr, String newStr) {
	if (stb == null || oldStr == null || newStr == null || stb.length() == 0 || oldStr.length() == 0) {
		return stb;
	}
	int index = stb.indexOf(oldStr);
	if (index > -1 && !oldStr.equals(newStr)) {
		int lastIndex = 0;
		while (index > -1) {
			stb.replace(index, index   oldStr.length(), newStr);
			lastIndex = index   newStr.length();
			index = stb.indexOf(oldStr, lastIndex); // indexOf(String str, int fromIndex)用于查找后续匹配的子串
		}
	}
	return stb;
}

4.2 字符串的比较判断

  • 比较相等 equals(Object anObject),比较实例的值。 contentEquals(StringBuffer sb),调用了contentEquals(CharSequence cs)方法,因为CharSequence是String,StringBuilder,StringBuffer的父类,适用范围比equals广
  • 比较大小 compareTo(String anotherString),按字典顺序(基于Unicode 值)比较两个字符串。
  • 判断存在 indexOf(String str, int fromIndex),返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。 startsWith(String str)和endsWith(String str)可以优化判断字符串头部和尾部匹配。
  • 匹配正则 boolean matches(String regex) 告知此字符串是否匹配给定的正则表达式。

五、集合

5.1 集合比较大小

重写Collections工具类的Compare()方法,如果要对Map进行排序,则需将其实体类存入List中,通过getValue()/getKey()来获取相应的值。

代码语言:javascript复制
// 以国家、金银铜三种奖牌数为输入,得到奖牌排名
Map<String, int[]> input = new HashMap<>();
List<Map.Entry<String, int[]>> output = new ArrayList<>(input.entrySet());

Collections.sort(output, (o1, o2) -> { // 升序o1大于o2返回-1,逆序则返回1
    // 第一次判断
    if (o1.getValue()[0] > o2.getValue()[0]) {
        return -1;
    } else if (o1.getValue()[0] < o2.getValue()[0]) {
        return 1;
    } else {
        // 第二次判断
        if (o1.getValue()[1] > o2.getValue()[1]) {
            return -1;
        } else if (o1.getValue()[1] < o2.getValue()[1]) {
            return 1;
        } else {
            // 第三次判断
            if (o1.getValue()[2] > o2.getValue()[2]) {
                return -1;
            } else if (o1.getValue()[2] < o2.getValue()[2]) {
                return 1;
            } else {
                // 第四次判断
                return o1.getKey().compareTo(o2.getKey());
            }
        }
    }
});

Iterator iterator = output.iterator();
while (iterator.hasNext()) {
    System.out.println(((Map.Entry<String, int[]>) iterator.next()).getKey());
}

5.2 BigDecimal 与浮点类型转换的精度损失问题

BigDecimal的构造函数 public BigDecimal(double val) 损失了double 参数的精度。

  • 解决方法一 使用BigDecimal的以String(scanner.next())为参数的构造函数:public BigDecimal(String val) 来替代。
  • 解决方法二 写一个工具类,基于小数位数和进位来控制损失。这个方法具有一定的局限性。
代码语言:javascript复制
// 转换时出现精度损失的情况
float = 1.2
1.1999999999999999555910790149937383830547332763671875
1.2000000476837158203125

5.3 bigdecimal 去除末尾多余的 0 和取消科学计数法显示

  • stripTrailingZeros() trip:除去;trailing:后续,尾部
  • toPlainString() plain:清楚的,简单的 代替toString()方法,防止出现类似1E 2的科学计数法输出。
代码语言:javascript复制
System.out.println( new BigDecimal("100.000").stripTrailingZeros().toPlainString());
// 输出:100

三种toString()方法:

  • toEngineeringString() 有必要时使用工程计数法。工程记数法是一种工程计算中经常使用的记录数字的方法,与科学技术法类似,但要求10的幂必须是3的倍数
  • toPlainString() 不使用任何指数
  • toString() 有必要时使用科学计数法

六、输入输出

6.1 Scanner.next() 和 Scanner.nextLine()

  • next() 一定要读取到有效字符后才可以结束输入,对输入有效字符之前遇到的空格键、Tab键或Enter键等结束符,next() 方法会自动将其去掉,只有在输入有效字符之后,next()方法才将其后输入的空格键、Tab键或Enter键等视为分隔符或结束符。
  • nextLine() 方法的结束符只是Enter键。

要注意nextLine()收集nspace的情况。 避免:

代码语言:javascript复制
// Method 1
if (input.nextLine() != "n") {}
// Method 2
sc.nextLine(); 

Final、格式规范

  1. 不应用*形式的import;
  2. 一个源文件按顺序包含版权、Package、import等信息;
  3. 对于非空块和块状结构,左大括号放在行尾;
  4. 非常量字段名称采用首写字母小写的驼峰法命名法;
  5. 减少不必要的空行,保持代码紧凑(大括号内行首之前行尾之后不要加空行)

0 人点赞