刷题小问题合计
- 一、保留两位小数
- 二、进制转换
- 三、数字逻辑
- 1. 2的幂次方
- 3.2 求因子
- 四、字符串逻辑及处理
- 4.1 大小写转换
- 4.2 字符串的比较判断
- 五、集合
- 5.1 集合比较大小
- 5.2 BigDecimal 与浮点类型转换的精度损失问题
- 5.3 bigdecimal 去除末尾多余的 0 和取消科学计数法显示
- 六、输入输出
- 6.1 Scanner.next() 和 Scanner.nextLine()
- Final、格式规范
一、保留两位小数
- 方法一
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中的浮点数舍入策略。
BigDecimal bg = new BigDecimal(f);
double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
- 方法二 DecimalFormat类用来格式化小数(Decimal还有十进制的意思),0 表示如果位数不足则以 0 填充,# 表示只要有可能就把数字拉上这个位置。
DecimalFormat df = new DecimalFormat("#.00");
System.out.println(df.format(f));-
// 额外用法:将格式嵌入文本
System.out.println(newDecimalFormat("光速大小为每秒,###米。").format(c));
- 方法三
String.format参考文章,该方法类似C语言中的
printf
格式化输出,其中可以指定的语言环境。
float result = String.format("%.2f", f);
- 方法四 MessageFormat、DateFormat、NumberFormat是Format三个常用的子类,常用于国际化。
NumberFormat nf = NumberFormat.getNumberInstance(); // 得到默认的数字格式化显示
nf.setMaximumFractionDigits(2); // integer整数,fraction分数
System.out.println(nf.format(f));
- 方法五 floor 返回不大于的最大整数(翻译:地板) round 是四舍五入的计算 ceil 是不小于他的最小整数(翻译:天花板) 注意:函数返回的都是int类型,需要*100/100处理
System.out.println((float)(Math.round(f*100)/100)); //如果要求精确4位就*10000然后/10000
- 补充:StringBuilder的setLength()方法
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');
思考:
- replace() VS replaceAll() 返回值String,需要将replace后的结果赋值给一个String。 replaceAll()可以用来处理正则表达式,参数是regex,但二者都是全部替换。对于简单型的替换而言,单以性能考虑,replace()是更好的选择。其中,String是接口类charSequence的一个实现类。
- StringBuilder的replaceAll() 由于StringBuilder的replace(int start, int end, String str)方法不能替换指定字串,故需要通过indexOf()和replace()方法来自定义,其性能相比String会快很多。
/**
* 实现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) 来替代。 - 解决方法二 写一个工具类,基于小数位数和进位来控制损失。这个方法具有一定的局限性。
// 转换时出现精度损失的情况
float = 1.2
1.1999999999999999555910790149937383830547332763671875
1.2000000476837158203125
5.3 bigdecimal 去除末尾多余的 0 和取消科学计数法显示
- stripTrailingZeros() trip:除去;trailing:后续,尾部
- toPlainString()
plain:清楚的,简单的
代替toString()方法,防止出现类似
1E 2
的科学计数法输出。
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()收集n
和space
的情况。
避免:
// Method 1
if (input.nextLine() != "n") {}
// Method 2
sc.nextLine();
Final、格式规范
- 不应用*形式的import;
- 一个源文件按顺序包含版权、Package、import等信息;
- 对于非空块和块状结构,左大括号放在行尾;
- 非常量字段名称采用首写字母小写的驼峰法命名法;
- 减少不必要的空行,保持代码紧凑(大括号内行首之前和行尾之后不要加空行)