练习+扩展总结

1.幸运数字

*题目

在这里插入图片描述

package com.lanqiao;

import java.*;
public class test1 {
	public static boolean check(int x,int base) {
		int n=x,sum=0;
		while(n!=0) {
			sum+=n%base;
			n/=base;
		}
		return x%sum==0;
	}
	
	public static void main(String[] args) {
		int count=0;
		int i;
		for(i=1;;i++) {
			if(check(i, 2)&&check(i, 8)&&check(i, 10)&&check(i, 16)) {
				count++;
			}
			if(count==2023) {
				System.out.println(i);
				break;
			}
		}
	}

}

1.1break和continue的区别

  • break
    (1)break是完全结束一个循环
    (2)用在循环体内和switch语句内
    注意:用在switch语句内只表示跳出该switch语句体,并不是终止整个循环
  • continue
    只是跳出本次循环,接着开始下一次循环

2.求和

*题目

求1(含)至20230408(含)中每个数的和.

package com.lanqiao;

import java.util.*;

public class test5{
	 public static void main(String[] args) {
//		 循环求和
		 long sum1=0;
		 for(long i=1;i<=20230408;i++) {
			 sum1+=i;
		 }
		 System.out.println(sum1);
		 
//		 利用等差数列求和公式
		 long sum2=0;
		 long n=20230408;
		 sum2=((1+n)*n)/2;
		 System.out.println(sum2);
	 }
}

3.阶乘求和

*题目

在这里插入图片描述

3.1求阶乘

public static long mul(int x) {
		if(x==0||x==1) {
			return 1;	//0和1的阶乘都为1
		}else {
			long mul=1;
			for(int i=2;i<=x;i++) {
				mul*=i;
			}
			return mul;
		}
	}
  • 求和
    • 我们发现,如果把1~202320232023的阶乘和都算出来,数太大了
    • 经过观察发现,当阶乘的底数大于等于5时,阶乘结果的末尾开始出现0(是因为有因子2,5);
    • 题目要求得出后九位,所以找出末尾9位都为0的阶乘结果(从这个数开始,后九位就都为0了,不会对最后结果有影响);
    • 也就是要找到第十个因子5–>(5,10,15,20,25(2个5),30,35,40)---->所以只需要计算1~40的阶乘和,取后九位即可
  • 所以,本题的代码应为
    //因为40的阶乘已经达到了40+的位数—>代码中只计算后九位
public static void main(String[] args) {
		int MOD=1000000000;
		long mul=1L;//mul为i的阶乘
		long sum=0L;//sum为各阶乘和
		for(int i=1;i<=40;i++) {
			mul=mul*i%MOD;
			sum=(sum+mul)%MOD;
		}
		System.out.println(sum);
	}

4.特殊日期

*题目

在这里插入图片描述

4.1权限使用区别(private,public,protected,default)

范围/权限privatedefaultprotectedpublic
同一包中同一类
同一包中不同类
不同包中的子类
不同包中的非子类
  • 有关日期的计算—>要判断是否为闰年(闰年有2月29日)
    //能被4整除且不能被100整除;或者能被400整除
//	判断闰年
	static boolean is_leap(int y) {
		return y%4 == 0 && y%100 != 0||y%400 == 0;
	}
  • 本题代码
package com.lanqiao;


public class test4 {
//	定义每月的天数
	static int days[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
	
//	判断闰年(闰年返回true)
	static boolean is_leap(int y) {
		return y%4 == 0 && y%100 != 0||y%400 == 0;
	}
	
//	如果是闰年,那么2月天数为29
	static int daysofMonth(int y,int m) {
		if(m==2&&is_leap(y)) {
			return 29;
		}
		return days[m];
	}
	
//	判断年=月+日
	static boolean check(int y,int m,int d) {
		int sum1=0;
		while(y!=0) {
			sum1+=y%10;
			y/=10;
		}
		int sum2=0;
		while(m!=0) {
			sum2+=m%10;
			m/=10;
		}
		while(d!=0) {
			sum2+=d%10;
			d/=10;
		}
		return sum1==sum2;
	}
	
	public static void main(String[] args) {
		int count=0;
		for(int i=1900;i<=9999;i++) {
			for(int j=1;j<=12;j++) {
				for(int k=1;k<=daysofMonth(i, j);k++) {
					if(check(i, j, k)) {
						count++;
					}
				}
			}
		}
		System.out.println(count);
	}

}

5.平均

*题目

在这里插入图片描述
在这里插入图片描述

import java.util.*;
import java.io.*;
// 1:无需package
// 2: 类名必须Main, 不可修改

public class Main{
  static int n;
    static ArrayList<Integer>[] e = new ArrayList[10];

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        n = Integer.parseInt(br.readLine());
        for (int i = 0; i < 10; i++) e[i] = new ArrayList<>();

        for (int i = 0; i < n; i++) {
            String[] tokens = br.readLine().split(" ");
            int a = Integer.parseInt(tokens[0]);
            int v = Integer.parseInt(tokens[1]);
            e[a].add(v);
        }

        long ans = 0;
        for (int i = 0; i <= 9; i++) {
            if (e[i].size() > n / 10) {
                Collections.sort(e[i], Collections.reverseOrder());
                for (int j = n / 10; j < e[i].size(); j++) {
                    ans += e[i].get(j);
                }
            }
        }
        System.out.println(ans);
    }
}

5.1ArrayList

ArrayList与普通数组最大区别就是它可以自动调节大小
ArrayList是java中提供的一个动态数组类,它实现了List接口
ArrayList可以根据需要自动调整大小,并且可以存储任意类型的对象
ArrayList的泛化类型只能为引用数据类型

	下面是一些原语ArrayList的重要特点和常用方法:
	1.动态大小:ArrayList的大小可以根据需要自动调整.他会自动增长或缩小以适应添加或删除元素
	2.随机访问:ArrayList中的元素可以通过索引进行快速访问.可以所使用的get(index)方法获取指定索引位置的元素
	3.允许重复元素:ArrayList可以存储重复的元素
	4.可以存储任意类型的对象:ArrayList是一个泛型类,可以存储任意类型的对象,例如:ArrayList<String>可以存储字符串对象

下面是一些常用的ArrayList方法:

方法解释
add(element)将指定的元素添加到ArrayList的末尾
add(index,element)在指定的索引位置插入指定的元素
get(index)获取指定索引位置的元素
set(index,element)将指定索引位置的元素替换为新的元素
remove(index)删除指定索引位置的元素
size()返回ArrayList中的元素个数
isEmpty()检查ArrayList是否为空
contains(element)检查ArrayList是否包含指定的元素
clear()清空ArrayList中的所有元素

5.2引用数据类型

在这里插入图片描述

5.3BufferedReader

在这里插入图片描述

5.3.1字节流和字符流

  • 流的分类
    按照流向 : 输入流(如:键盘,麦克风);输出流(如:显示器,音响)
    按传输单位 : 字节流;字符流

  • 字节流 : 以字节为单位进行读写,适用于处理二进制数据(如图像,音频,视频等)或文本数据的原始字节.

  • 字符流 : 以字符为单位进行读写,适用于处理文本数据

      字节流
      - 字节流以字节为单位进行读写,主要用于处理为禁止数据或文本数据的原始字节
      - 字节流类位于'java.io'包中,例如'InputStream'和'OutputStream'
      - 字节流类提供了读取和写入字节的方法,如'read()'和'write()'
      - 字节流适用于处理图像,音频,视频等二进制数据,以及处理文本数据时不需要进行字符集编码转换的情况
    
    
      字符流
      - 字符流以字符为单位进行读写,主要用于处理文本数据
      - 字符流类位于'java.io'包内,例如'Reader'和'Writer'
      - 字符流类提供了读取和写入字符的方法,如'read()'和'writer()'
      - 字符流在读取和写入文本数据时会自动进行字符集编码和解码,是的处理数据更加方便灵活
      - 字符流适用于处理文本文件,配置文件,文档等文本数据
    

5.3.2而BufferedReader是java的输入流类之一

  • 主要用于从字符输入流中读取文本,并将文本缓存到缓冲区中,从而提高读取文本的效率

  • BufferedReader只能用来读取字符类型的数据,如果需要读取其他类型的数据,需要进行数据转换

      应用场景:
      BufferedReader类适用于需要高效读取字符输入流的场景,比如从文件中逐行读取文本内容,读取网络数据流等
    

在这里插入图片描述

5.4split

split()是Java中’String’类中的一个方法,用于将字符串拆分成多个子字符串,根据指定的分隔符进行拆分.

split(String regex)方法

  • 1.单个分割符
	String str="1 2 3";
	String[] data=str.split(" ");
	for(int i=0;i<data.length;i++){
		System.out.println(data[i]);
	}
	//输出结果:
	1
	2
	3
  • 2.如果分隔符为"|“,那么需要使用转义字符”"让其产生效果
	String str="a|bc|d";
	//java中 \\ 表示一个普通的 \ ;\+特殊字符表示字符本身
	String[] data=str.split("\\|");
	for(...){
		sout(data[i]);
	}
	//输出结果为
	a
	bc
	d
  • 3.如果直接使用 |
	String str="a|bc|d";
	String[] data=str.split("|");
	for(...){
		sout(data[i]);
	}
	//输出结果为:
	a
	|
	b
	c
	|
	d
  • 4.多个分隔符
	String str="a;1,2,3";
	String[] data=str.split(";|,");
	for(...){
		sout(data[i]);
	}
	//输出结果为:
	a
	1
	2
	3

5.5Collections

  • Collections不能new对象,因为Collections的构造方法被私有化处理了
  • 可以通过 类名.方法名 直接调用Collections中的方法(因为Collections中的方法都是static方法)

5.5.1Collections.sort()

  • 默认是升序排列
    在这里插入图片描述
  • 也可以存储对象类型的数据---->要让自定义的类实现Comparabler接口,并重写Comparabler接口中的compare to方法

//自定义的类


public class Person implements Comparable<Person>{
	private String name;
	private int age;
	...
	//重写CompareTo排序的规则
	@Override
	public int compareTo(Person o){
		//自定义比较的规则 this指代当前对象,o指代后一个要传进来的对象
		return this.getAge()-o.getAge();//按照年龄升序排序
		//return -(this.getAge()-o.getAge());//按照年龄的降序排序

//main

public static void main(String[] args){
	ArrayList<Person> list=new ArrayList<>();
	list.add(new Person("张三",18));
	list.add(new Person("李四",20));
	list.add(new Person("王五",15));
	System.out.println(list);

	Collections.sort(list);
	System.out.println(list);
//输出结果:
王五,15
张三,18
李四,20
compareTo的逻辑
    1. compareTo()方法知识sort排序中的很少一部分代码---->我们把这部分代码单拎出来重写---->来实现我们的目的
    1. 重写@Override compareTo的目的---->在自定义的类中,定义自己的排序规则(不然机器是不知道该如何排序的)---->可以在使用sort()方法排序时,使用自己的排序规则进行排序
    1. compareTo 的作用---->提供一个 i 的返回值

         ---->返回值为**正数**,则在sort其他部分的代码中会转换为 **1** ;然后sort的其他代码段,将会对参与比较的两个对象**对调次序**;
         ---->返回值为**负数**,则会转化为 **-1** ;在sort的其他代码段中,**不会**进行**对调**
         ---->如果参与比较的两个数相等,会返回 0 .
      
  • 在上述代码中,return this.getAge()-o.getAge()

      - 如果返回值是正数,则要与后一个参数进行对调---->也就是年龄小的排在前面---->升序排列
      - 如果返回值是负数,则不进行操作--->还是年龄小的排在前面---->升序排列
      - 所以this.getAge()-o.getAge()实现的是升序排列
      - 反之,则可进行 降序排列
    

5.5.2 Collections.reverseOrder()

是Collections中的一个静态方法—>功能是 : 反转默认的自然排序顺序
例子:

import java.util.ArrayList;
import java.util.Collections;

public class ReverseOrderExample {
    public static void main(String[] args) {
        ArrayList<Integer> numbers = new ArrayList<>();
        numbers.add(5);
        numbers.add(2);
        numbers.add(8);
        numbers.add(1);
        numbers.add(10);

        Collections.sort(numbers, Collections.reverseOrder());

        System.out.println(numbers);
    }
}

输出结果:


[10, 8, 5, 2, 1]

其他请看:

6.棋盘

*题目

在这里插入图片描述
在这里插入图片描述

package com.lanqiao;

import java.util.Scanner;

public class test6_1 {

	public static void main(String[] args) {
		Scanner scanner=new Scanner(System.in);
//		输入n,m
		int n=scanner.nextInt();
		int m=scanner.nextInt();
		
//		创建一个数组,用于存储(x1,y1);(x2,y2)
		int[][] b=new int[n+2][n+2];
		
//		输入x1,y1,x2,y2--->要输入m次
		for(int i=1;i<=m;i++) {
			int x1=scanner.nextInt();
			int y1=scanner.nextInt();
			int x2=scanner.nextInt();
			int y2=scanner.nextInt();
			
//			根据每次输入的x,y 将对应区域的格子数值+1
			b[x1][y1]++;
			b[x2+1][y1]--;
			b[x1][y2+1]--;
			b[x2+1][y2+1]++;
		}
		
//		计算m次操作后的数组,(每个格子最后的数值为偶数-->白色;奇数-->黑色)
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=n;j++) {
//				每个格子的数值
				b[i][j]=b[i][j]+b[i-1][j]+b[i][j-1]-b[i-1][j-1];
//				输出n行 ; 如果是白色则输出0,如果是黑色则输出1 
				if (b[i][j]%2==0) {
					System.out.print("0");
				}else {
					System.out.print("1");
				}
			}
			System.out.println();
		}
		scanner.close();
		
	}
}

  • 二维数组定义的 n+2
    在这里插入图片描述

6.1数组

6.1.1一维数组

数组是一组相同类型元素的集合

	- 数组的创建方式:
		type name [n]
		数组的元素类型 数组的名字 数组的大小
		eg.int arr[10]
	- 数组的初始化:
		eg.int arr[3]={1,2,3}
		(可以不定义数组的大小)
		int arr[]={1,2,3,4,5,6}

6.1.2二维数组

-  二维数组创建时,行数可以忽略不写(所有维度的数组,第一个方括号的内容可以忽略)
- 二维数组可以用于表示矩阵,图像,游戏地图等具有二维结构的数据.
- 通过使用嵌套的循环,可以对二维数组进行遍历和操作

int h[3][4];

h[0][0]h[0][1]h[0][2]h[0][3]
h[1][0]h[1][1]h[1][2]h[1][3]
h[2][0]h[2][1]h[2][2]h[2][3]

二维数组的创建,初始化,遍历输出

int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        System.out.print(matrix[i][j] + " ");
    }
    System.out.println();
}

6.2差分

6.2.1什么是差分?

  • 首先有一个原数组a: a[1],a[2],a[3]…a[n]
  • 然后构造一个数组b: b[1],b[2],b[3]…b[n],使得a[n]=b[1]+b[2]+b[3]+…+b[n]
  • 所以,我们就称a数组是b数组的前缀和,而b数组就称为a数组的差分
  • 差分数组:每个位置的值表示原始数组对应位置的 增量

6.2.2一维差分

- 就是给区间[l,r]中的每个数加上c--->b[l]+=c , b[r+1]-=c , 并且时间复杂度为O(1)

在这里插入图片描述
注意 : 只需要在b[L]的位置加一个c---->整个a[L]数组,每个a[i]都会加c

计算前缀和 a[n]=a[n-1]+b[n]

在这里插入图片描述

6.3二维差分

  • 图解
    思路

在这里插入图片描述

计算前缀和(根据差分计算出最终结果)

在这里插入图片描述

  • 普通版:时间复杂复为O(n*n)
for(int i=x1;i<=x2;i++){
	for(int j=y1;j<=y2;j++){
		a[i][j]+=c;
	}
}
  • 差分矩阵核心操作:时间复杂度为O(1)
static void insert(int x1,int y1,int x2,int y2,int c){
	b[x1][y1]+=c;
	b[x1][y2+1]-=c;
	b[x2+1][y1]-=c;
	b[x2+1][y2+1]+=c;
}
  • 计算前缀和
    n行,m列的数组
for(int i=1;i<=n;i++){
	for(int j=1;j<=m;j++){
		s[i][j]=s[i-1][j]+s[i][j-1]+s[i][j]-s[i-1][j-1];
	}
}

7.与或异或

*题目

在这里插入图片描述
在这里插入图片描述

package com.lanqiao;

public class test7_1 {
	static int sum=0;
	static int[] ops=new int[11];//本题共10个操作符
	static int[][] op=new int[5][5];//对上面操作符的二维化
	static int[][] arr=new int[6][6];//表示对应的1/0

    
	public static void dfs(int cnt) {
//		cnt==11时,代表10个操作符已经赋值完了---->形成了一种方案
		if(cnt==11) {
			for(int i=1;i<=4;i++) op[1][i]=ops[i];
			for(int i=1;i<=3;i++) op[2][i]=ops[i+4];
			for(int i=1;i<=2;i++) op[3][i]=ops[i+7];
			for(int i=1;i<=1;i++) op[4][i]=ops[i+9];

			
//			为了方便--->用0,1,2表示三种操作符
			for(int i=1;i<=4;i++) {
				for(int j=1;j<=4-i+1;j++) {
					if(op[i][j]==0) arr[i][j]=arr[i-1][j] | arr[i-1][j+1];
					if(op[i][j]==1) arr[i][j]=arr[i-1][j] ^ arr[i-1][j+1];
					if(op[i][j]==2) arr[i][j]=arr[i-1][j] & arr[i-1][j+1];
				}
			}

			
			if(arr[4][1]==1) 
				sum++;
			return;
			
		}
		
		for(int i=0;i<3;i++) {
//			枚举第cnt个操作符为i
			ops[cnt]=i;
//			开始枚举下一个操作符
			dfs(cnt+1);
		}
	}
	
	
	
	public static void main(String[] args) {
		arr[0][1]=1;
		arr[0][2]=0;
		arr[0][3]=1;
		arr[0][4]=0;
		arr[0][5]=1;
		
		dfs(1);
		
		System.out.println(sum);
	}

}

逻辑门

1.1与门---->且 , A&&B

  • 全真才为真
输入 A输入 B输出 Q
111
100
010
000

1.2或门---->或 , A||B

  • 有真就为真
输入 A输入 B输出 Q
111
101
011
000

1.3非门---->非 , !A

  • 取反
输入 A输出 Q
10
01

1.4与非门---->!(A&&B)

与门+非门

1.5或非门---->!(A||B)

或门+非门

1.6异或门---->A^B

  • 输入不同–>输出1
  • 输入相同–>输出0

1.7同或门---->!(A^B)

异或门+非门

  • 输入不同–>输出0
  • 输出相同–>输出1

8.填充

*题目

在这里插入图片描述

package com.lanqiao;

import java.util.Scanner;

public class test8_1 {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		String s = scanner.next();
		int n=s.length();
		s="?"+s;
		int[] f=new int[n+1];
		for(int i=2;i<=n;i++) {
			if((s.charAt(i) == s.charAt(i-1)) || s.charAt(i)=='?' || s.charAt(i-1)=='?') {
				f[i]=f[i-2]+1;
			}else {
				f[i]=f[i-1];
			}
		}
		System.out.println(f[n]);
	}

}

8.1charAt()方法

java中charAt()方法的使用

9.数组分割

在这里插入图片描述
在这里插入图片描述

package com.lanqiao;

import java.util.Arrays;
import java.util.Scanner;

public class test10_1 {
//	根据题目定义的两个常量 : N数组大小
	static final int N=1010,MOD=(int) 1e9+7;
	static int[] a=new int[N];
//	dp[i][j]数组表示 前i个元素的和的奇偶 --->如果为偶dp[i][0] ; 如果为奇--->dp[i][1]
	//dp[i][j]数组的值表示成立的方案个数
	static int[][] dp=new int[N][2];

	
	
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);

		int T=scanner.nextInt();
//		循环输入T组数据
		for(int k=1;k<=T;k++) {
//			输入数组个数
			int n=scanner.nextInt();
			long sum=0;
//			输入数组的值 ; 并求数组的整和
			for(int i=0;i<n;i++) {
				a[i]=scanner.nextInt();
				sum+=a[i];
			}
//			如果和为奇数-->那一定从不成两个都是偶数的S(因为 奇数+?=奇数)
			if(sum%2==1) {
				System.out.println(0);
				continue;
			}
//			初始化 动态规划的数组dp[i][j] 都为0
			for(int i=0;i<=n;i++) {
				Arrays.fill(dp[i], 0);
			}
			
//			题目允许为空--->前0个数组的和为0-->偶数-->所以dp[0][0]=1
			dp[0][0]=1;
			for(int i=1;i<=n;i++) {
				if(a[i]%2==1) {
					dp[i][0]=(dp[i-1][0]+dp[i-1][1])%MOD;
					dp[i][1]=(dp[i-1][0]+dp[i-1][1])%MOD;
				}else {
					dp[i][0]=dp[i-1][0]*2%MOD;
					dp[i][1]=dp[i-1][1]*2%MOD;
				}
			}
			System.out.println(dp[n][0]);
			
		}
	}

}

10.买二赠一

*问题

在这里插入图片描述
在这里插入图片描述

package com.lanqiao;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;



public class test12_1 {

	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		
		long sum=0;
		int n=scanner.nextInt();
		int[] a=new int[n];
		for(int i=0;i<a.length;i++) {
			a[i]=scanner.nextInt();
		}
		
		Arrays.sort(a);
		
		//A 队列:当前未购买的所有商品
		Queue<Integer> A=new LinkedList<Integer>();
		//Free 队列 存放 可以免费的商品
		Queue<Integer> Free=new LinkedList<Integer>();
		
		for(int i=a.length-1;i>=0;i--) {
			A.add(a[i]);
		}
		
		int count=1;
		while(!A.isEmpty()) {
			long x=A.poll();
			
			
//			满足免费条件的-->直接跳出本次循环 , 并将免费队列的头元素删除(因为 二换一)
			if(!Free.isEmpty() && x<=Free.peek()) {
				Free.poll();
				continue;
			}
			
//			不能免费的,直接购买
			sum+=x;
			if(count==2) {
				Free.add((int) (x/2));
				count=1;
			}else {
				count=2;
			}
			
			
		}
		
		
		
		System.out.println(sum);
		
	}
}

  • 队列

参考文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值