蓝桥杯Java——算法训练3

本文介绍了多种算法题目,涉及大数乘法、字符串压缩、数组操作、链表处理等。通过实例展示了如何利用Java实现斐波那契数列、最大获利计算、大数乘法、字符串压缩、数组求和、链表操作等,以及如何设计高效的算法解决实际问题。

目录

1.最大获利(数组)

 2.斐波那契串(递推)

3.P0805(大数乘法)

 4.P0804(字符串压缩)

5.P0801(数组求和)

6.唯一的傻子(链表) 

 7.数组移动

 8.自行车停放(双向链表)

9.ascii应用(ascii码)

 10.P0705(集合运算)


1.最大获利(数组)

问题描述

  Chakra是一位年轻有为的企业家,最近他在进军餐饮行业。他在各地开拓市场,共买下了N个饭店。在初期的市场调研中,他将一天划分为M个时间段,并且知道第i个饭店在第j个时间段内,会有Aij位服务员当值和Bij位客户光临。他还分析了不同饭店不同时间段客户的需求,得到第i个饭店在第j个时间段内,平均每位客户消费Cij元。为了创设品牌形象,Chakra决定每个饭店每天只选择一个时间段营业,每个服务员至多接待一位顾客(若顾客数多于服务员数,超过部分的顾客当天就无法在该店消费了)。
  企业家的目的终究还是获利。请你安排营业时间,并告诉Chakra每天消费总额最多为多少。

输入格式

  第一行两个整数,N、M。
  第二行开始依次给出三个矩阵A(N*M)、B(N*M)、C(N*M)。

输出格式

  一行一个整数,最大消费总额。

样例输入

2 3
1 2 3
3 2 1
3 2 1
1 2 3
4 5 2
3 1 6

样例输出

16

数据规模和约定

  1 <= M,N <= 100
  1 <= Aij, Bij <= 5000
  0 <= Cij <= 10^9

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();
		int m = scanner.nextInt();
		long[][] a = new long[n][m];
		long[][] b = new long[n][m];
		long[][] c = new long[n][m];
		for (int i = 0; i < n; i++) {         // 服务生数据
			for (int j = 0; j < m; j++) {
				a[i][j] = scanner.nextInt();
			}
		}
		for (int i = 0; i < n; i++) {         // 客户数据
			for (int j = 0; j < m; j++) {
				b[i][j] = scanner.nextInt();
			}
		}
		for (int i = 0; i < n; i++) {         // 盈利数据
			for (int j = 0; j < m; j++) {
				c[i][j] = scanner.nextInt();
			}
		}
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (a[i][j] < b[i][j]) {         // 服务生<客户
					c[i][j] = a[i][j] * c[i][j]; // 服务*盈利
				} else {
					c[i][j] = b[i][j] * c[i][j]; // 客户 *盈利
				}
			}
		}
		for (int i = 0; i < n; i++) {            // 1 2 3 第一层服务       3 2 1第二层服务   
  			for (int j = m - 1; j >= 0; j--) {   // 3 2 1 第一层客户       1 2 3第二层客户
				for (int k = 0; k < j; k++) {    // 盈利
					if (c[i][k] < c[i][k + 1]) {
						long t = c[i][k + 1];
						c[i][k + 1] = c[i][k];
						c[i][k] = t;
					}
				}
			}
		}
		long ans = 0;                            // 找出两组时间数里盈利最大值
		for (int i = 0; i < n; i++) {
			long max = 0;
			for (int j = 0; j < m; j++) {
				if (max < c[i][j]) {
					max = c[i][j];
				}
			}
			ans += max;
		}
		System.out.println(ans);
	}
}

 2.斐波那契串(递推)

问题描述

  斐波那契串由下列规则生成:
  F[0] = "0";
  F[1] = "1";
  F[n] = F[n-1] + F[n-2] (n≥2,+表示连接)
  给出一个由0和1构成的串S和一个数n,求出F[n]中S出现的次数。

输入格式

  第一行一个数n。
  第二行一个01串S。

输出格式

  答案。

样例输入

96
10110101101101

样例输出

7540113804746346428

数据规模和约定

  n≤263-1,子串长≤10000,答案≤263-1。

import java.util.Scanner;
public class Main {
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		long n=sc.nextLong();
		String m=sc.next();
		int i=0;
		for(;i<n;i++) {
			long sum=swap(i,m);
			//如果字符串存在于指定字符串中,打破循环,使用斐波那契数列规律求出
			if(sum==1) {
				break;
			}	
		}
		long su=adds(i-1,n);
		System.out.println(su);
	}
	//继续菲波那切数列规律进行计算
	public static long adds(long m,long n) {
		long a=0;
		long b=1;
		for(long j=m;j<=n;j++) {			
			long t=b;
			b=b+a;
			a=t;
		}
		return b-1;
	}
	//获取第一次出现子串的时候
	public static long swap(long m,String s) {		
		String pre="0";
		String cur="1";
		for(int j=2;j<=m;j++) {
			String t=cur;
			cur=pre+cur;
			pre=t;
		}
		//计算字串个数
		long sum=0;
		for(int i=0;i<cur.length()-s.length();i++) {
			String str=cur.substring(i,i+s.length());
			if(str.equals(s)) {
				sum++;
			}
		}		
		return sum;
	}	
}

3.P0805(大数乘法)

当两个比较大的整数相乘时,可能会出现数据溢出的情形。为避免溢出,可以采用字符串的方法来实现两个大数之间的乘法。具体来说,首先以字符串的形式输入两个整数,每个整数的长度不会超过10位,然后把它们相乘的结果存储在另一个字符串当中(长度不会超过20位),最后把这个字符串打印出来。例如,假设用户输入为:62773417和12345678,则输出结果为:774980393241726.
  编写函数 void Multiply(char* s1, char* s2, char* result); 实现大数乘法(只考虑正整数),其中result = s1 * s2.
  编写main函数测试该函数的正确性.

输入:
  62773417 12345678

输出:
  774980393241726

import java.math.BigInteger;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        String s1=input.next();
        String s2=input.next();
        String result=null;
        System.out.println(Multiply(s1, s2, result));
    }
    public static String Multiply(String s1, String s2, String result){
        BigInteger m=BigInteger.valueOf(Long.parseLong(s1.trim()));
        BigInteger n=BigInteger.valueOf(Long.parseLong(s2.trim()));
        //System.out.println(m);
        BigInteger result1=m.multiply(n);
        //System.out.println(result1);
        result=String.valueOf(result1);
        return result;
    }
}

 4.P0804(字符串压缩)

编写一个函数void strcompress(char *s),输入一个字符串(只包含小写字母和空格,且长度小于1000),然后采用如下的规则对该字符串当中的每一个字符进行压缩:
  (1) 如果该字符是空格,则保留该字符。
  (2) 如果该字符是第1次出现或第3次出现或第6次出现,则保留该字符。
  (3) 否则,删除该字符。
  例如,若用户输入occurrence,经过压缩后,字符c的第2次出现被删除,第1和第3次出现仍保留;字符r和e的第2次出现均被删除,因此最后的结果为:ocurenc。
  编写main函数测试该函数的正确性。

输入:
  occurrence

输出:
  ocurenc

import java.io.*;
import java.util.*;
public class Main {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String str = br.readLine();
		Map<Character,Integer> map = new HashMap<>();
		StringBuilder builder = new StringBuilder();
		for(int i = 0; i < str.length();i++) {
			char c = str.charAt(i);
			Integer value = map.get(c);
			if(c == ' ') {
				builder.append(c);
			}
			if(value == null) {
				map.put(c, 1);
				builder.append(c);
			}else {
				map.put(c, value + 1);
				if(value == 2 || value == 5) {
					builder.append(c);
				}
			}
		}
		System.out.println(builder.toString());
	}
}

5.P0801(数组求和)

编写一个数组求和函数void Add(int n, int* a1, int* a2, int* result); 其中n<100是数组长度,a1是第一个数组,a2是第二个数组,result是a1和a2的和。假设a1={2, 4, 5, 8}, a2={1, 0, 4, 6},则result={3, 4, 9, 14};
  编写main函数测试该函数的正确性。依次输入n, a1, a2, 输出result。

输入:
  4
  2 4 5 8
  1 0 4 6

输出:
  3 4 9 14

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int[] a1=setArray(input, n);
        int[] a2=setArray(input, n);
        int[] result=new int[n];
        for (int i=0;i<n;i++){
            System.out.print(Add(n, a1, a2,result)[i]+" ");
        }
    }
    //数组求和
    public static int[] Add(int n, int[] a1, int[] a2, int[] result){
        for (int i=0;i<n;i++){
            result[i]=a1[i]+a2[i];
        }
        return result;
    }
    //创建数组,整合现相同代码,减少代码冗余
    public static int[] setArray( Scanner input,int n){
        int[] a=new int[n];
        for (int i=0;i<a.length;i++){
            a[i]=input.nextInt();
        }
        return a;
    }
}

6.唯一的傻子(链表) 

问题描述

  腿铮找2255有点事,但2255太丑了,所以腿铮不知道他的长相。正愁不知道到如何找他的时候,他突然看见计33班围成了一个圈在领微积分试卷。计33班有n个人,其中班长编号为0,其余同学依次按顺时针方向编号。
  只听见计33小导说“x号同学顺时针方向往后数的第k个的神犇出列(不包括x号同学),领取满分试卷!”。剩下的人继续围成一个小圈。这样一个过程持续了n-1次,那么显然,最后只剩下了一个人。众所周知,2255是个大傻子,门门挂科,不符合满分试卷这一前提条件。通过这样一个过程,腿铮终于找到了2255并血虐了他。
  求2255的编号是多少。

输入格式

  第一行一个n,表示计33班的人数。
  接下来n-1行,表示小导说话中的x和k。

输出格式

  一个数字,表示2255的编号。

样例输入

3
1 1
0 1

样例输出

0

数据规模和约定

  前90%数据保证n<=10^4.
  前100%数据保证n<=10^6,1<=k<min(当时圈中人数,1000)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Scanner;
import java.util.StringTokenizer;
public class Main {
	public static void main(String[] args) throws IOException {
		Reader sc=new Reader();
		int n=sc.nextInt();
		for(int i=0;i<n-1;i++) {
			int x=sc.nextInt();
			int y=sc.nextInt();
			if(i==n-2){
				System.out.println(x);
			}
		}
	}
	 /** 快速输入类 */
    static class Reader {
        static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        static StringTokenizer tokenizer = new StringTokenizer("");
        /** 获取下一段文本 */
        static String next() throws IOException {
            while ( ! tokenizer.hasMoreTokens() ) {
                tokenizer = new StringTokenizer(reader.readLine());
            }
            return tokenizer.nextToken();
        }
        static int nextInt() throws IOException {
            return Integer.parseInt( next() );
        }
        static double nextDouble() throws IOException {
            return Double.parseDouble( next() );
        }
    }
}

 7.数组移动

问题描述

  初始数组A[N]中为1,2,..,N,N个数字,现要进行M次操作,每次操作给定一个数字i,记其在数组中的位置为Bi,将A[1]..A[Bi]移到数组末尾。

输入格式

  输入的第一行包含两个整数N,M。接下来M行,每行一个正整数,表示给定的数字i。

输出格式

  一行,输出M次操作后的A数组。

样例输入

5 2
3
2

样例输出

3 4 5 1 2

样例说明

  第一次操作后变为 4 5 1 2 3

  第二次操作后变为 3 4 5 1 2

数据规模和约定

  N<=10^5,M<=10^5

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int n=input.nextInt(); //A数组的长度
        int m=input.nextInt();//m次操作
        int []A=new int[n];
        int []M=new int[m];
        //A数组
        for (int i=0;i<n;i++){
            A[i]=i+1;
        }
        //存储操作次数
        for (int i=0;i<m;i++){
            M[i]=input.nextInt();
        }

        int distance=M[m-1];//最后一次的操作次数
        int []B=new int[distance];//存储A[1]..A[distance]
        for (int i=0;i<distance;i++){
            B[i]=A[i];
        }
        int s=0;
        for (int i=0;i<A.length;i++){
            if (i==A.length-distance){//A[1]..A[distance]移到数组末尾
                while (s< B.length){
                    A[i]=B[s];
                    s++;
                    i++;
                }
            }else{//A[i+distance]往前挪
                A[i]=A[i+distance];
            }

        }
        //遍历数组
        for (int i=0;i<n;i++){
            System.out.print(A[i]+" ");
        }
    }
}

 8.自行车停放(双向链表)

问题描述

  有n辆自行车依次来到停车棚,除了第一辆自行车外,每辆自行车都会恰好停放在已经在停车棚里的某辆自行车的左边或右边。(e.g.停车棚里已经有3辆自行车,从左到右编号为:3,5,1。现在编号为2的第4辆自行车要停在5号自行车的左边,所以现在停车棚里的自行车编号是:3,2,5,1)。给定n辆自行车的停放情况,按顺序输出最后停车棚里的自行车编号。

输入格式

  第一行一个整数n。
  第二行一个整数x。表示第一辆自行车的编号。
  以下n-1行,每行3个整数x,y,z。
  z=0时,表示编号为x的自行车恰停放在编号为y的自行车的左边
  z=1时,表示编号为x的自行车恰停放在编号为y的自行车的右边

输出格式

  从左到右输出停车棚里的自行车编号

样例输入

4
3
1 3 1
2 1 0
5 2 1

样例输出

3 2 5 1

数据规模和约定

  n<=100000
  自行车编号为不超过100000的正整数。

import java.util.Scanner;
public class Main {
	/*
	 * 样例输入
		4 //一共有4辆自行车
		3 //第一辆自行车的编号
		1 3 1  z=1, 1在3的右边 即 3 1(三个数依次对应x y z)  
		2 1 0  z=0, 2在1的左边 即 2 1
		5 2 1  z=1, 5在2的右边 即2 5
		
		思路:用双向链表解决
	 * */
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();//自行车总数
		int num = sc.nextInt();//第一辆自行车的编号
		
		doubleNode first = new doubleNode();//创建双向链表
		first.data = num;
		first.prior = null;
		first.next = null;
		
		doubleNode xx = null,yy = null;
		doubleNode[] local = new doubleNode[100005];//存放自行车的地址
		local[num] = first;//第一辆自行车的地址
		for(int i=1;i<n;i++){//依次向双向链表中插入数据
			int x = sc.nextInt();
			int y = sc.nextInt();
			int z = sc.nextInt();
			
			xx = new doubleNode();
			xx.data = x;
			local[x] = xx;//编号为x的自行车地址
			
			yy = new doubleNode();
			yy = local[y]; //获取编号y的自行车地址,存入的比x早
			
			if(z==0){ //1.x放在y的左边(即将x插入到双向链表中结点yy的前面)
				xx.next = yy;
				if(yy.prior!=null){//yy结点不是头节点
					xx.prior = yy.prior;
					yy.prior.next = xx;
				}else{
					xx.prior = null;
				}
				yy.prior = xx; //y的前驱指针指向x
				if(yy==first){//yy是头节点,则更改头节点
					first = xx;
				}
			}//if
			
			if(z==1){//2.x放在y的右边(即将x插入到双向链表中y的后面)
				xx.prior = yy;
				if(yy.next!=null){//yy结点不是尾结点
					xx.next = yy.next;
					yy.next.prior = xx;
				}else{//yy是尾结点
					xx.next = null;
				}
				yy.next = xx; 
			}//if
		}//for
		
		while(first != null){
			System.out.print(first.data+" ");
			first = first.next;
		}
	}
	
}
class doubleNode{//双向链表
	int data;
	doubleNode prior,next;
	public doubleNode() {
		
	}
	public doubleNode(int data, doubleNode prior, doubleNode next) {
		super();
		this.data = data;
		this.prior = prior;
		this.next = next;
	}	
}

9.ascii应用(ascii码)

问题描述

  输入ascii码n(65≤n≤90,97≤n≤122),输出对应的字母及其在字母表中的位置并判断大小写。

输入格式

  输入的数据只有一行,其中包括一个数字n,表示一个ascii码。

输出格式

  输出一行,分别是ascii码n所对应的字符,并判断大小写,及其在字母表中的位置。

样例输入一

  65

样例输出一

  A d1

样例输入二

  97

样例输出二

  a x1

数据规模和约定

  65≤n≤90,97≤n≤122。

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        String strChar= String.valueOf((char)n);//转ascii
        String strD="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        String strX="abcdefghijklmnopqrstuvwxyz";
        if (65<=n&&n<=90){
            System.out.println(strChar+" d"+(strD.indexOf(strChar)+1));
        }else{
            System.out.println(strChar+" x"+(strX.indexOf(strChar)+1));
        }

    }
}

 10.P0705(集合运算)

  输入两个整数集合A、B,求出他们的交集、并集以及B在A中的余集。交集、并集和余集的计算都要求写成一个单独的函数。
  输入第一行为一个整数n,表示集合A中的元素个数。
  第二行有n个按从小到大的顺序输入且互不相同的整数,表示集合A中的元素
  第三行为一个整数m,表示集合B中的元素个数。
  第四行有m个按从小到大的顺序输入且互不相同的整数,表示集合B中的元素
  集合中的所有元素均为int范围内的整数,n、m<=1000。
  输出第一行按从小到大的顺序输出A、B交集中的所有元素。
  第二行按从小到大的顺序输出A、B并集中的所有元素。
  第三行按从小到大的顺序输出B在A中的余集中的所有元素。
输入:
  5
  1 2 3 4 5
  5
  2 4 6 8 10
  输出:
  2 4
  1 2 3 4 5 6 8 10
  1 3 5

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();
        int[]A=setArray(input, n);
        int m=input.nextInt();
        int[]B=setArray(input, m);
        intersection(A, B);
        unionSet(A, B);
        complementary(A,B);
    }
    //交集
    public static void intersection(int[]A,int[]B){
        for (int i=0;i< A.length;i++){
            int n=0;
            while (n< B.length){
                if (A[i]==B[n]){//交集:找相等的
                    System.out.print(A[i]+" ");
                }
                n+=1;
            }
        }
        System.out.println("\r");
    }
    //并集
    public static void unionSet(int[]A,int[]B){
        int len=A.length+ B.length;
        int []merge=new int[len];
        int m=0;
        for (int i=0;i<len;i++){
            if (i<A.length){
                merge[i]=A[i];
            }else{
                merge[i]=B[m];
                m+=1;
            }
        }
        Arrays.sort(merge);
        Set set=new HashSet();
        for (int a:merge){//去重
            set.add(a);
        }
        Iterator iterator=set.iterator();//迭代器
        //遍历set中的元素
        while (iterator.hasNext()){
            System.out.print(iterator.next()+" ");
        }
        System.out.println("\r");
    }
    //余集
    public static void complementary(int[]A,int[]B){//找A集合中除交集外的
        for (int i=0;i<A.length;i++){
            int n=0;
            while (n<B.length){
               if (A[i]==B[n]) break;//相同的跳过while,再对比A的下一位
               if (n==B.length-1){//不相同的需要把B中的元素全部对比一遍,直到满足条件再输出A
                   System.out.print(A[i]+" ");
               }
                n+=1;
            }
        }

    }
    //创建数组,整合现相同代码,减少代码冗余
    public static int[] setArray( Scanner input,int N){
        int[] a=new int[N];
        for (int i=0;i<a.length;i++){
            a[i]=input.nextInt();
        }
        return a;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

得闲喝茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值