跑步锻炼
题目链接:https://www.lanqiao.cn/problems/597/learning/
这个题直接遍历所有的日期就可以了,原来我一直用的都是Calendar类,有一次查到了
LocalDate
类,发现也挺好用的,不过有很多函数的返回值不知道类型,只能看源码去找了,或者看看API手册
package daily;
import java.time.DayOfWeek;
import java.time.LocalDate;
/**
* https://www.lanqiao.cn/problems/597/learning/
*
* @author Jia
*
*/
public class day3_31_1 {
public static void main(String[] args) {
LocalDate left = LocalDate.of(2000, 1, 1);
LocalDate right = LocalDate.of(2020, 10, 1);
int ans = 0;
while (left.compareTo(right) <= 0) {
DayOfWeek dayOfWeek = left.getDayOfWeek();// 星期几
int dayOfMonth = left.getDayOfMonth();// 每月的日期
if (dayOfWeek.getValue() == 1 || dayOfMonth == 1) {
ans += 2;
} else {
ans += 1;
}
left = left.plusDays(1);// 下一天
}
System.out.println(ans);
}
}
直线
题目链接:https://www.lanqiao.cn/problems/1449/learning/
这个题真的是麻了,第一次做的时候用的方法是 y = k x + b y=kx+b y=kx+b,然后直接公式计算 k k k,忘了double的精度问题,直接错了,然后后面把直线方程看成 A x + B y + C = 0 Ax+By+C=0 Ax+By+C=0就可以做了,但是就是在对 A B C ABC ABC进行通分的时候出现了问题,最后终于是改出来了
思路比较简单,就是对于任意两点求一个直线,然后对这个直线去重,得到的就是最终结果,难就难在如何去重上面,如果直接计算斜率的话会由于精度问题失败,也有一种思路是存储斜率和偏移的分子分母,并进行通分到最简,这是一种思路,另一种是像我这样,换一种直线的表达式去计算,这样就不会存在分数了,自然而言也就不会有精度问题了。
由于java中的Set如果要使用自定义的类的话,是需要自己重写
hashCode
和equals
两个方法的,自己写的话太慢了,eclipse有快捷键可以直接构造出来,在写代码的界面,右键->source->选择框中的两个即可,这个可以节约很多时间,其他的话还有toString可以很方便的调试程序,不然打印出来的就是一堆地址
package daily;
import java.util.HashSet;
import java.util.Set;
/**
* https://www.lanqiao.cn/problems/1449/learning/
*
* @author Jia
*
*/
public class day3_31_2 {
public static void main(String[] args) {
int xEnd = 20;
int yEnd = 21;
int[][] points = new int[xEnd * yEnd][2];
int index = 0;
// 构造点集
for (int i = 0; i < xEnd; i++) {
for (int j = 0; j < yEnd; j++) {
points[index][0] = i;// x
points[index][1] = j;// y
index++;
}
}
// 两点构造一条直线,得到该直线 Ax + By + C = 0 的表达式,在构造函数中会对 ABC 除以他们的最大公约数进行约分
Set<Line1> lineSet = new HashSet<>();
for (int i = 0; i < points.length; i++) {
for (int j = i + 1; j < points.length; j++) {
int a1 = points[i][0];
int b1 = points[i][1];
int a2 = points[j][0];
int b2 = points[j][1];
int A = a2 - a1;
int B = b2 - b1;
int C = a2 * b1 - a1 * b2;
lineSet.add(new Line1(A, B, C));
}
}
System.out.println(lineSet.size());
}
}
class Line1 {
int A;
int B;
int C;
public int gcd(int a, int b) {
// 当有一个数为0的时候,直接返回另一个数字
if (a == 0 || b == 0) {
return a == 0 ? b : a;
}
return a % b == 0 ? b : gcd(b, a % b);
}
public Line1(int a, int b, int c) {
super();
int gcd = 1;
gcd = gcd(a, b);
gcd = gcd(gcd, c);
A = a / gcd;
B = b / gcd;
C = c / gcd;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + A;
result = prime * result + B;
result = prime * result + C;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Line1 other = (Line1) obj;
if (A != other.A)
return false;
if (B != other.B)
return false;
if (C != other.C)
return false;
return true;
}
}
循环小数
题目链接:https://www.lanqiao.cn/problems/1051/learning/
呃,这个题自己做的话估计直接就暴力算了,但是感觉可能会有和上面一问同样的精度问题,然后在网上百度了一下转换方法:
1、纯循环小数化为分数
方法:将纯循环小数改写为分数,分子是一个循环节的数字组成的数;分母各位数字都是9,9的个数与循环节中的数字的个数相同,最后能约分的再约分。
2、混循环小数化为分数
方法:将混循环小数改写为分数,分子就是循环节中小数部分的数字组成的数减去小数部分中不循环部分数字组成的数而得到的差;分母的头几位数字是9,末几位数字是0,9的个数跟循环节的数位相同,0的个数跟不循环部分的数位相同。
应用:
13.12323…=13+(123-1)/990=6496/495
0.123123…=123/999
0.12333…=(123-12)/900=111/900=37/300
把上面的结论特点统一一下就是:如果循环节加上不循环的数位总共有多少位,那么分母就是多少位的9+0,9的个数等同循环节位数,0的个数等同不循环的位数;分子等于=小数点后不循环的数字加第一个循环节构成的数字,再减去小数点后不循环的数字。
这里可以只看例子和最后的结论就ok了,然后把它翻译成代码就是下面这样的
package daily;
import java.util.Scanner;
/**
* https://www.lanqiao.cn/problems/1051/learning/
*
* @author Jia
*
*/
public class day3_31_3 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int p = sc.nextInt();
int q = sc.nextInt();
String num = sc.next();
sc.close();
int len_buxunhuan = p - 1;
int len_xunhuan = q - p + 1;
int buxunhuan = len_buxunhuan == 0 ? 0 : Integer.parseInt(num.substring(0, p - 1));
int xunhuan = Integer.parseInt(num.substring(p - 1, q));
int fenmu = 0;
for (int i = 0; i < len_xunhuan; i++) {
fenmu = fenmu * 10 + 9;
}
for (int i = 0; i < len_buxunhuan; i++) {
fenmu = fenmu * 10;
}
int fenzi = (int) (buxunhuan * Math.pow(10, len_xunhuan) + xunhuan - buxunhuan);
int gcd = gcd(fenzi, fenmu);
System.out.println(fenzi / gcd + " " + fenmu / gcd);
}
/**
* 求最大公约数
*
* @param a
* @param b
* @return
*/
private static int gcd(int a, int b) {
return a % b == 0 ? b : gcd(b, a % b);
}
}
卡片换位
题目链接:https://www.lanqiao.cn/problems/125/learning/
这个题直接bfs就可以做了,早上上课上麻了,写了一半写不下去了,晚上再补全吧
package daily;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.Set;
/**
* https://www.lanqiao.cn/problems/125/learning/
*
* @author Jia
*
*/
public class day3_31_4 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
char[][] chs = new char[2][3];
for (int i = 0; i < chs.length; i++) {
String str = sc.nextLine();
for (int j = 0; j < str.length(); j++) {
chs[i][j] = str.charAt(j);
}
}
sc.close();
Deque<char[][]> queue = new LinkedList<>();
Set<String> set = new HashSet<>();
set.add(chs2Str(chs));
queue.addFirst(chs);
int[] nextRow = {
0, 1, 0, -1 };
int[] nextCol = {
1, 0, -1, 0 };
int ans = 0;
while (!queue.isEmpty()) {
int size = queue.size();
ans++;
while (size > 0) {
char[][] chArr = queue.removeLast();
for (int i = 0; i < nextRow.length; i++) {
// todo
}
}
}
}
/**
* 字符数组转化成字符串
*
* @param chs
* @return
*/
private static String chs2Str(char[][] chs) {
String str = "";
for (int i = 0; i < chs.length; i++) {
for (int j = 0; j < chs[0].length; j++) {
str += chs[i][j];
}
}
return str;
}
}