题目心得
学过线性代数的同学应该对稀疏矩阵并不陌生,这道题的思路很简单:读入a数组,如果数组b和数组a中存在同样不为零的维度,那么就把这个维度上的数值相乘,最后相加。
我们一步步分解来看:
- 读入数组a
int[][] ara = new int[a][2];
for(int i=0;i<a;i++){
ara[i][0] = sc.nextInt();
ara[i][1] = sc.nextInt();
}
- 按行读入数组b,而不进行储存,因为我们的目标是得到内积,所以数组储存下来没有意义。只需要对数组b中有意义的元素进行计算,有意义的规则就是:两个数组的这个维度都不为零。这个时候就需要我们在数组a中查找是否存在这样的维度。
由于维度的序列是有序的,并且涉及到了大数量下的查找问题,这个时候就可以很自然地想到使用二分查找。这也是这道题拿100分的关键。
至于二分查找的算法,我在这里给出一种写法。这个写法是对于排序的基础上应用的。
//读取数组b当中的非零值和下标
for(int i=0;i<b;i++){
int[] tmp = new int[]{sc.nextInt(), sc.nextInt()};
//如果存在相同的下标,则说明在这个维度上相乘结果不为零
//现在的目标是找到数组a中是否含有该下标
//由于下标的序列是有序的,所以可以使用二分查找
int l = 0;
int r = a-1;
while(l<=r){
if (tmp[0]<ara[l][0] || tmp[0]>ara[r][0]) {
break;
}
int m = (l+r)/2;
if(tmp[0]<ara[m][0]){
r = m-1;
}else if(tmp[0]>ara[m][0]){
l = m+1;
}else{
res += tmp[1]*ara[m][1];
break;
}
}
}
-
找到可以同一维度上的非零元素,累加乘积。对于累计相加的问题,我们一般都是先声明一个变量存储,如rus,然后找到可以进行累计相加的“规则”,然后使用rus += 某些算式。
-
最后,还有一些小细节:
- 不需要考虑维度从0还是从1开始:因为我们把维度考虑成数值,而不是标号或者索引。
- 使用long储存最后的内积结果:遇到数据值比较大的题目都留意一下这个小细节,虽然有时候可能真的没有用到long,但是以防万一还是用long代替int吧,反正只需要更改一个变量。
完整代码
由于本人学术不精,粘出代码仅供大家参考,欢迎大家参与讨论和批评指正。
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int a = sc.nextInt();
int b = sc.nextInt();
long res = 0;//记录内积的结果
//存储数组a当中的非零值和下标
int[][] ara = new int[a][2];
for(int i=0;i<a;i++){
ara[i][0] = sc.nextInt();
ara[i][1] = sc.nextInt();
}
//读取数组b当中的非零值和下标
for(int i=0;i<b;i++){
int[] tmp = new int[]{sc.nextInt(), sc.nextInt()};
//如果存在相同的下标,则说明在这个维度上相乘结果不为零
//现在的目标是找到数组a中是否含有该下标
//由于下标的序列是有序的,所以可以使用二分查找
int l = 0;
int r = a-1;
while(l<=r){
if (tmp[0]<ara[l][0] || tmp[0]>ara[r][0]) {
break;
}
int m = (l+r)/2;
if(tmp[0]<ara[m][0]){
r = m-1;
}else if(tmp[0]>ara[m][0]){
l = m+1;
}else{
res += tmp[1]*ara[m][1];
break;
}
}
}
System.out.println(res);
sc.close();
}
}
提交结果: