这篇文章主要记录一些使用数学方法后更加容易求解的题目:
例题1:
解析: 首先我们要求的是等差数列的个数,那么我们只需要使用使用最大值-最小值/公差即可,可是题目要求求得是最短的等差数列,如何确保是等差数列,并且是最大的,就是两两数之差的最大公因数
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scan =new Scanner(System.in);
int N=scan.nextInt();
if(N<=1) {
System.out.print(1);
return ;
}
int[] nums=new int[N];
for(int i=0;i<N;i++) {
nums[i]=scan.nextInt();
}
// 将数组进行排序
Arrays.sort(nums);
// 找出公差
int gc=nums[1]-nums[0];
// 通过循环找出最小公差,公差不一定时两处只差,也可能时两数之差的最大公因数
for(int i=2;i<N;i++) {
gc=gcd(gc, nums[i]-nums[i-1]);
}
if(gc==0) {
System.out.print(N);
return;
}
int count=(nums[N-1]-nums[0])/gc+1;
System.out.print(count);
}
// 创建一个函数求最大公因数
public static int gcd(int a,int b) {
return b==0?a:gcd(b,a%b);
}
}
例题2: 买不到的数目
解释: 这题考察的是数论的知识——对于互质的两个数a和b,其不能组成的最大整数为a*b-a-b。
注意这里a和b一定得是互质的,否则是无解的。题目给你的例子也肯定是会互相为质数的,除非题目有说若无解则输出-1。当然这题也可以暴力去求解一下。
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int m=sc.nextInt();
System.out.println(n*m-n-m);
}
}
例题3: 连号区间数
小明这些天一直在思考这样一个奇怪而有趣的问题:
在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:
如果区间[L, R]
里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。
解释: 如何保证一个子数组是一个公差为1的等差数列。对于数组arr一段子数组[i,j],如果这段序列最大值为max,最小值为min。如果max-min==j-i,那么说明这段子数组就是一段公差为1的等差数列。 所以对于每一段子数组,我们可以去遍历获得它的最大值和最小值,然后判断它们的差值是否等于下标差。
package five;
import java.util.Scanner;
//这道题主要使用了连续数组的性质
//首先题目强调了连续所以我们的的公差就一定为1
//所以如果排序好想要为一个地政的连续数组那么最大值减去最小值就等于下标的相减
public class Three {
public static void main(String[] args) {
Scanner scan=new Scanner(System.in);
int N=scan.nextInt();
int[] nums=new int[N];
for(int i=0;i<N;i++) {
nums[i]=scan.nextInt();
}
// 创建一个变量保存符合条件的个数
int count=0;
// 使用双重循环找出所有子区间
for(int i=0;i<N;i++) {
// 创建两个变量保存区间的最大值
int max=nums[i];
int min=nums[i];
for(int j=i;j<N;j++) {
max=Math.max(max, nums[j]);
min=Math.min(min, nums[j]);
if(max-min==j-i) {
count++;
}
}
}
System.out.print(count);
}
}