202309-2 坐标变换(其二)
- 题解1
- 题解2
- 区别
- 第一种算法(使用ArrayList存储操作序列):
- 数据结构:
- 操作序列处理:
- 第二种算法(使用两个数组存储累积结果):
- 数据结构:
- 操作序列处理:
- 对比
- 效率
- 简洁性
- 可读性
题解1
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt(); // 操作次数
int m = scan.nextInt(); // 初始坐标个数
// 存储操作序列的ArrayList,每个操作为长度为2的double数组
ArrayList<double[]> op = new ArrayList<>();
// 初始化所有操作的累积倍数为1
for (int i = 0; i <= n; i++) {
op.add(new double[] {1, 0}); // 初始操作是不进行变换,k=1, sita=0
}
// 读取每个操作的类型和值,并存储到op中
for (int i = 1; i <= n; i++) {
int type = scan.nextInt(); // 操作类型,1表示乘法,2表示加法
double val = scan.nextDouble(); // 操作值
if (type == 1) {
// 如果是乘法操作,更新k值,sita不变
op.set(i, new double[] {op.get(i - 1)[0] * val, op.get(i - 1)[1]});
} else {
// 如果是加法操作,更新sita值,k不变
op.set(i, new double[] {op.get(i - 1)[0], op.get(i - 1)[1] + val});
}
}
// 对每个初始坐标进行操作并输出结果
for (int i = 0; i < m; i++) {
int l = scan.nextInt(); // 左边界
int r = scan.nextInt(); // 右边界
double x = scan.nextDouble(); // 初始x坐标
double y = scan.nextDouble(); // 初始y坐标
// 计算从l到r的累积旋转角度和累积缩放倍数
double sum_sita = op.get(r)[1] - op.get(l - 1)[1];
double sum_k = op.get(r)[0] / op.get(l - 1)[0];
// 根据公式计算最终的坐标
double nx = x * Math.cos(sum_sita) - y * Math.sin(sum_sita);
double ny = x * Math.sin(sum_sita) + y * Math.cos(sum_sita);
// 输出结果
System.out.println(nx * sum_k + " " + ny * sum_k);
}
scan.close();
}
}
题解2
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt(); // 操作次数
int m = scan.nextInt(); // 初始坐标个数
// 存储操作序列的ArrayList,每个操作为长度为2的double数组
ArrayList<double[]> op = new ArrayList<>();
// 初始化所有操作的累积倍数为1
for (int i = 0; i <= n; i++) {
op.add(new double[] {1, 0}); // 初始操作是不进行变换,k=1, sita=0
}
// 读取每个操作的类型和值,并存储到op中
for (int i = 1; i <= n; i++) {
int type = scan.nextInt(); // 操作类型,1表示乘法,2表示加法
double val = scan.nextDouble(); // 操作值
if (type == 1) {
// 如果是乘法操作,更新k值,sita不变
op.set(i, new double[] {op.get(i - 1)[0] * val, op.get(i - 1)[1]});
} else {
// 如果是加法操作,更新sita值,k不变
op.set(i, new double[] {op.get(i - 1)[0], op.get(i - 1)[1] + val});
}
}
// 对每个初始坐标进行操作并输出结果
for (int i = 0; i < m; i++) {
int l = scan.nextInt(); // 左边界
int r = scan.nextInt(); // 右边界
double x = scan.nextDouble(); // 初始x坐标
double y = scan.nextDouble(); // 初始y坐标
// 计算从l到r的累积旋转角度和累积缩放倍数
double sum_sita = op.get(r)[1] - op.get(l - 1)[1];
double sum_k = op.get(r)[0] / op.get(l - 1)[0];
// 根据公式计算最终的坐标
double nx = x * Math.cos(sum_sita) - y * Math.sin(sum_sita);
double ny = x * Math.sin(sum_sita) + y * Math.cos(sum_sita);
// 输出结果
System.out.println(nx * sum_k + " " + ny * sum_k);
}
scan.close();
}
}
区别
第一种算法(使用ArrayList存储操作序列):
数据结构:
使用了ArrayList<double[]>来存储操作序列。
每个操作是一个长度为2的double数组,存储了操作的缩放倍数和旋转角度。
操作序列处理:
在读取每个操作时,将其存储为一个数组,然后放入ArrayList中。
对每个操作序列进行遍历,根据操作类型更新缩放倍数和旋转角度。
每次操作都要通过ArrayList的get和set方法来获取和更新操作,可能需要多次遍历操作序列。
第二种算法(使用两个数组存储累积结果):
数据结构:
使用两个数组double[] k和double[] sita来分别存储累积的缩放倍数和旋转角度。
k数组存储缩放倍数,sita数组存储旋转角度。
操作序列处理:
在读取每个操作时,直接根据操作类型更新对应的数组元素。
操作序列处理时不需要遍历,直接根据索引获取和更新操作。
对比
效率
第一种算法使用ArrayList,操作时需要多次调用get和set方法,可能会造成性能损失,特别是在大量数据时。
第二种算法使用数组,直接根据索引获取和更新操作,更加高效。
简洁性
第一种算法使用了ArrayList,需要定义和操作ArrayList,代码相对复杂一些。
第二种算法直接使用数组,代码结构更简洁。
可读性
两种算法在理解上都是相对清晰的,但对于不熟悉ArrayList的人来说,第二种算法可能更容易理解。
总体来说,第二种算法使用数组直接存储累积结果,更加高效和简洁,而第一种算法使用了ArrayList,可能会在性能上稍逊一些。在处理大量数据时,第二种算法更为推荐。