在小组的安排下,这个暑假我们统一学习三个星期的算法,在这里让我感觉最大的感受是,前面有人引你入门真的好,可以少走很多的冤枉路,可以快速增长自己的能力和水平,但后续就要求自己自主的学习,因为别人的路线毕竟是别人的,不可能完全的适合自己的,但入门系列是每一个程序员或爱好算法的同学的必经之路,入门系列就是基础阶段,只有将基础打好,后面才能走的更远更好。在完成入门系列专项训练之后,我将自己做的题和做题过程中遇到的问题及解题思路总结成笔记。
记得上数据结构的时候老师说过,数据结构好比是武林高手的内功,往往刚修炼的时候内功比较的弱,但当我们持之以恒的练习,我们终将练就一身内功成就宗师。加油!
计算机运算速度很快,一秒钟可以处理成千上万的数据。之前的例子都是读取一个数据后立刻对这些数据进行处理,然后再也不需要用到这些数据了;有时候,我们读入数据后还需要将这些数据保存下来,便于以后再次使用。如果保存个别几个数据,可以设立几个变量存储;但是如果要存储成千上万个数据,总不能定义成千上万个变量吧。
AC代码:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//鱼的总数
int fishSum = scanner.nextInt();
//六头鱼的可爱程度
int[] arr = new int[fishSum];
for (int i = 0; i < fishSum; i++) {
arr[i] = scanner.nextInt();
}
//比较可爱值
int[] cute = new int[arr.length];
//遍历所有鱼
for (int i = 0; i < arr.length; i++) {
//与它左边的鱼比较
for (int j =i-1; j >= 0; j--) {
if (arr[i] > arr[j]){
cute[i]++;
}
}
}
//输出得到的可爱值列表
// System.out.println(Arrays.toString(cute));
for (int i = 0; i < fishSum; i++) {
System.out.print(cute[i]+" ");
}
}
}
本题重点:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] arr = new int[100];
int middle = 0;
//输入数据
for (int i = 0; ; i++) {
arr[i] = sc.nextInt();
if (arr[i] == 0){//当遇到0的时候就结束输入,并记下当前的i值,方便输出
middle = i;
break;
}
}
//遍历从middle - 1 --- 0之间的左右数据,为什么方向遍历,是为了倒着输出这一串数据。
for (int i = middle-1; i >= 0 ; i--) {
System.out.print(arr[i]+" ");
}
}
}
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[1000];
int count = 1;//中间变量count,看最后需要多少步
if(n == 1){//当输入的n等于1时
System.out.println("1");
}else{//当输入的n不等于1时
while(n != 1){//题中的操作最终的结果就是n = 1;所以将n != 1作为循环条件,当n == 1时结束。
arr[count] = n;//将每一次的得到的值存入数组之中。
if(n % 2 == 0){//偶数时
n = n / 2;
}else{//奇数时
n = n * 3 + 1;
}
count++;//计数:有多少条数据
}
arr[count] = 1;//while循环的条件就是n != 1;所以当n == 1时没有存入数组,需要单独存进去
//遍历得到想要的数据。
for (int i = count; i > 0; i--) {
System.out.print(arr[i]+" ");
}
}
}
}
AC代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int l = sc.nextInt();
int m = sc.nextInt();
int[] a = new int[10001];//因为 1 <= l <=10000;
int[] b = new int[10001];
int n = 2*m;
//给各个区段的首尾进行赋值
for(int i=0; i<n; i+=2) {
b[i] = sc.nextInt();//首节点
b[i +1] = sc.nextInt();//尾节点
}
//给整个区间内的点进行赋值
for(int i=0; i<=l; i++) {
a[i] = 1;
}
int r,s;
for(int i=0; i<n; i+=2) {
r = b[i]; //区间起始点
s = b[i+1]; //区间终点
for(int j=r; j<=s; j++) {//把数组b各个区间内元素在数组a中映射为0
a[j] = -1; //将区段内符合的带你进行赋值标记
}
}
int k = 0;
for(int i=0; i<=l; i++) {
if(a[i] != -1) {
k++; //用来统计非0的个数,即不在数组b区间内的数的个数
}
}
System.out.println(k);
}
}
本题重点:
AC代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int count = 0;//计数使用
int[][] a = new int[1100][5];//每位同学的各科成绩
int[] b = new int[1100];//每位同学的总成绩
//给每位同学的各科成绩和总成绩进行赋值操作
for (int i = 0; i < n; i++) {
a[i][0] = sc.nextInt();
a[i][1] = sc.nextInt();
a[i][2] =sc.nextInt();
b[i] =a[i][0] + a[i][1] + a[i][2];
}
//循环时,不能自己和自己比,所以第二个变量要从第一个变量 + 1+1 开始。
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if(Math.abs(a[i][0] - a[j][0]) <= 5 && Math.abs(a[i][1] - a[j][1]) <= 5 && Math.abs(a[i][2] - a[j][2]) <= 5 && Math.abs(b[i] - b[j]) <= 10){//记得要取绝对值使用Math.abs();
count++;
}
}
}
System.out.println(count);
}
}
本题重点:
AC代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
//输入这个工艺品的长宽高
int x = scanner.nextInt(), y = scanner.nextInt(), z = scanner.nextInt();
//输入切割的数据
int num = scanner.nextInt();
int[][][] a = new int[x + 1][y + 1][z + 1];//数据从1开始,所以在原来的基础上加一
for (int i = 0; i < num; i++) {//遍历输入每一次切割的数据
//输入起始点
int x1 = scanner.nextInt(), y1 = scanner.nextInt(), z1 = scanner.nextInt();
//输入终止点
int x2 = scanner.nextInt(), y2 = scanner.nextInt(), z2 = scanner.nextInt();
//使用标记法,将这一区域内的数据进行赋值标记
for (int j = x1; j <= x2; j++) {
for (int k = y1; k <= y2; k++) {
for (int l = z1; l <= z2; l++) {
a[j][k][l] = 1;
}
}
}
}
int counter = 0;//剩下的工艺品还剩下的体积,因为是1*1*1的所以直接累加即可
//遍历整个工艺品,没有被标记赋值的部分累加起来,
for (int i = 1; i <= x; i++) {
for (int j = 1; j <= y; j++) {
for (int k = 1; k <= z; k++) {
if (a[i][j][k] == 0) {
counter++;
}
}
}
}
System.out.println(counter);
}
}
本题重点:
AC代码:
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 = new int[n][7];//自己买的我彩票
int[] b = new int[7]; //中奖的彩票
int[] c = new int[]{0,0,0,0,0,0,0}; //中奖个数数组
//给中奖的彩票赋值
for (int i = 0; i < 7; i++) {
b[i] = sc.nextInt();
}
//给自己彩票赋值
for (int i = 0; i < n; i++) {
for (int j = 0; j < 7; j++) {
a[i][j] = sc.nextInt();
}
}
for (int i = 0; i < n; i++) {//这个循环是自己的每张彩票
int temp = 0;
for (int j = 0; j < 7; j++) {//遍历一张彩票的每个数据
for (int k = 0; k < 7; k++) {//遍历中奖彩票的每一个数据
if (b[k] == a[i][j]){
temp++;
}
}
}
if (temp != 0){
c[7 - temp ]++;//因为自己的彩票上与中奖彩票相同的越多则计数越大,将屏数越小。
}
}
for (int i = 0; i < 7; i++) {//遍历中奖数组,一次输出各种将中奖的次数
System.out.print(c[i] + " ");
}
}
}
本题重点:
AC代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = sc.nextInt();
int n = sc.nextInt();
int[] a = new int[10];
int count;
for (int i = m; i <= n; i++) {
int j = i;//避免循环致使i值出现混乱,将i赋值给新的值j
while (j != 0){//对每一个数进行操作:将每一个数 模10求余个位数,然后除以十得到倒数第二位以此类推将数据的每一位都求出来对1 - 10进行比较,相同则数组对应的数据自增;
count = j % 10;
if(count == 0)a[0]++;
if(count == 1)a[1]++;
if(count == 2)a[2]++;
if(count == 3)a[3]++;
if(count == 4)a[4]++;
if(count == 5)a[5]++;
if(count == 6)a[6]++;
if(count == 7)a[7]++;
if(count == 8)a[8]++;
if(count == 9)a[9]++;
j = j / 10;//让数据的每一位都可以是个位,然后求余得到各个位上的数
}
}
//遍历得到区段类数据中包含0 - 9中各个数有多少个。
for (int i = 0; i < 10; i++) {
System.out.print(a[i] +" ");
}
}
}
本题重点:
AC代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//有n件不爽的事情
int m = sc.nextInt();//连续m件
int[] a = new int[n];
int sum = 0,count = 0;
for (int i = 0; i < n; i++) {
a[i] = sc.nextInt();//给n件不爽的事情进行刺痛点赋值
}
for (int i = 0; i < m; i++) {
count += a[i];//初始化一个最初的m件不爽的事情的累加
}
for (int i = 0; i < n - m; i++) {//遍历从0开始到n - m;因为内层循环是i开始的m个值,防止数组越界
for (int j = i; j
本题重点:
AC代码:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int s1 = sc.nextInt();
int s2 = sc.nextInt();
int s3 = sc.nextInt();
int[] a = new int[16000];//定义一个数组,将对应的面和放在作为数组中对应的位置上
int maxx = 0,maxs = 0;
//遍历三个面,让面和对应的数组的值自增。
for (int i = 1; i <= s1 ; i++) {
for (int j = 1; j <= s2 ; j++) {
for (int k = 1; k <= s3 ; k++) {
a[i + j + k]++;
}
}
}
//因为面和的值是连续的从三个面最小值到三和面和的最大值
for (int i = s1 + s2 + s3; i >= 3 ; i--) {
if (a[i] >= maxx){//看面和对应的数组中的数据谁最大
maxx = a[i];
// maxs = i;
}
}
System.out.println(maxs);
}
}
本题重点:
AC代码:
第一种:使用异或思想解决本题
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(),t,result = 0;
double a;
for (int i = 0; i < n; i++) {//遍历输入每一组数据,
a = sc.nextDouble();
t = sc.nextInt();
for (int j = 1; j <= t; j++) {//
int x = (int)Math.floor(a*j);//[k]表示实数kk的整数部分,每一次操作都有t盏灯进行开或者关。
result ^= x;//使用异或,开关灯是对应的,n次操作后只有一盏灯是亮的,所以使用异或可以的到最后那个亮的
}
}
System.out.println(result);
}
}
第二种:使用数组解决问题
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
double a[] = new double[n];
int t[] = new int[n];
// 输入
for(int i = 0;i
本题重点:
AC代码:
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 = new int[n][n];
int count = 1;
int x = 0,y = 0;
a[0][0] = 1;
while(count < n * n){//输出边长为n的数字矩阵,所以最后的count值为n*n,以此作为判断。
//向右递增
while (y + 1 < n && a[x][y + 1] == 0){//向右下一个数据存在且值为0,表示未被赋值
a[x][++y] = ++count;
}
//向下递增
while (x + 1 < n && a[x + 1][y] == 0){//同上
a[++x][y] = ++count;
}
//向左递增
while (y - 1 >= 0 && a[x][y - 1] == 0){//同上
a[x][--y] = ++count;
}
//向上递增
while (x - 1 >= 0 && a[x - 1][y] == 0){//同上
a[--x][y] = ++count;
}
}
//遍历获得正方型矩阵
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.printf("%3d",a[i][j]);//使用printf来让每个数字占3个字符。
}
System.out.println();
}
}
}
本题重点:
AC代码:
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 = new int[n + 1][n + 1];//数组的数据从1开始,所以数组范围+1;
//将每一行的第一个和最后一个赋值为1;数组从1开始,方便
for (int i = 1; i <= n; i++) {
a[i][1] = a[i][i]=1;
}
//头两行在给每行的第一个和最后一个复制的同时就复制了,所以从第三行开始即可。
if (n > 2){
for(int i = 3;i <= n;i++){
for(int j = 2;j <= i;j++)//因为a[i][1]、a[i][i]已经赋值过了,所以循环是2~n-1
a[i][j] = a[i-1][j] + a[i-1][j-1];
}
}
//输出每一行的数据;
for (int i = 1; i <= n ; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(a[i][j] + " ");
}
System.out.println();//内部循环遍历完成之后进行换行
}
}
}
本题重点:
AC代码:
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();//m个火把
int k = sc.nextInt();//k个萤石
int[][] arr = new int[n + 3][n + 3];//数组的范围定义大一点,下面遍历就不用考虑数组越界了 。
if (n == 2) {//可能没有萤石,但一定有火把。所以当n <= 2 的时候,没有怪物。
System.out.print("0");
} else {
//遍历火把的情况,将火把范围内的点赋值1
for (int i = 1; i <= m; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
x = x + 2;
y = y + 2;
for (int j = x - 2; j < x + 1; j++) {
for (int l = y - 2; l < y + 1; l++) {
arr[j][l] = 1;
arr[x - 3][y - 1] = 1;
arr[x + 1][y - 1] = 1;
arr[x - 1][y - 3] = 1;
arr[x - 1][y + 1] = 1;
}
}
}
//遍历萤石的情况,将萤石范围内的点赋值1
for (int i = 1; i <= k; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
x = x + 2;
y = y + 2;
for (int j = x - 3; j <= x + 1; j++) {
for (int l = y - 3; l <= y + 1; l++) {
arr[j][l] = 1;
}
}
}
int count = 0;//计数变量
//遍历整个数组,若数组内元素的值为0则是火把和萤石未照耀的部分将出现怪物
for (int i = 2; i < n + 2; i++) {
for (int j = 2; j < n + 2; j++) {
if (arr[i][j] == 0) {
count++;
}
}
}
System.out.print(count);
}
}
}
本题重点:
使用标记法,定义数组之后,数组内部元素会初始全部赋值为0,让火把和萤石照耀的部分赋值为1,最后遍历矩阵,数组元素为0的部分是未照耀的部分,会出现妖怪。
将数组的范围定义的大一点,不用考虑数组是否越界等问题,担当我们遍历的时候只用将自己想用的那部分遍历出来即可,
AC代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();//输入 n;
int middle = 0,b = 0, c, d = 0;//定义几个变量,
while(d < n * n){
c = sc.nextInt();
middle++;//middle变量的作用是交换输出0和1
for (int j = c; j > 0 ; j--) {
if (b == n){//当每一行达到n的时候换行且将变量重新赋值为0
System.out.println();
b = 0;
}
//交替输出0和1
if (middle % 2 == 1){//排序奇数时
System.out.print("0");
}else{//偶数时
System.out.print("1");
}
b++;//控制每一行输出数字的个数
d++;//控制while循环
}
}
System.out.println();
}
}
本题重点:
AC代码:
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 = new int[n][n];
int x = 0,y = n / 2;
a[0][y] = 1;
for (int i = 2; i <= n*n; i++) {
if (x == 0 && y != n-1) {
x = n-1;
++y;
} else if (x != 0 && y == n-1) {
--x;
y = 0;
} else if (x == 0 && y == n-1) {
++x;
} else if (a[x-1][y+1] == 0) {
--x;
++y;
} else {
++x;
}
a[x][y] = i;
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(a[i][j] + " ");
}
System.out.println();
}
}
}
本题重点:
注意题目说的是,幻方的N必定是奇数(实测确实不能是偶数),那就不需要检测了。
按指定的要求移动就行。并不需要自己设计什么算法。
AC代码:
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
int[] m = new int[n];
for(int i = 0; i < n; i++){
arr[i] = sc.nextInt();
m[i] = 1;//将数组m的所有函数赋值为1做标记
}
int count = 0;
for(int i = 0; i < n; i++ ){
for(int j = i + 1; j < n; j++){
for(int k = 0; k < n; k++){
if(arr[i] + arr[j] == arr[k] && m[k] == 1){//判断数据是否符合条件
count++;
m[k] = 0;//若符合条条件的那个数将数组中对应的位置赋值为0,防止下次再进来计算,
}
}
}
}
System.out.println(count);
}
}
本题重点: