【Java基础算法】41-50题(字符串直接拼接+String与字符数组互相转换换+文件创建与读写)

目录

★41、海滩上有一堆桃子,五只猴子来分。第一只猴子把这堆桃子平均分为五份,多了一个,这只猴子把多的一个扔入海中,拿走了一份。第二只猴子把剩下的桃子又平均分成五份,又多了一个,它同样把多的一个扔入海中,拿走了一份,第三、第四、第五只猴子都是这样做的,问海滩上原来最少有多少个桃子?

思路: 跟17题猴子吃桃子,和第23题五个人一个比一个大2岁类似。都属于倒推问题。此处需要注意的是,每次分桃子前的数量都是除5后余1;除了第一只猴子,每只猴子看到的桃子数都是4的倍数 (因为是上一只猴子剩下的4份)。且桃子数量只能是整数

1>①假设第五只猴子分的每份都是一个桃子,则分之前有6个桃子,分完后留下了4个桃子的情况。倒推前面猴子分时有几个桃子
②如果中途哪只猴子开始分时,桃子数量不满足%5=1(说明没法分成五分多一个的情况),或者/4有余数,只有第一个猴子不用(说明上一个剩下的四份不是整数显然不对)。则说明假设不成立,再假设第五只猴子分出的每份桃子数++,依次类推出最少桃子的情况。
③第5只猴子只看到6个桃子,拿走后剩4个桃子,推出第4只猴子拿走后剩余的(即第5只猴子见到的)(4/4)*5+1 = 6,第3只拿走后剩余的为(6/4)*5+1 =34/4,类推,第i只猴子见到的桃子数设为xi,
第i-1只猴子见到的桃子数为:xi-1 = (xi/4)*5+1

2>不适合使用递归,因为无法一次通过递归倒推出桃子初始值,无法确定第5只猴子见到的桃子数是多少的情况下符合每一只猴子都可以%5=1.只能不断假设第5只猴子见到的数量,在递推到前面猴子的时候判断,不满足就重新假设。因为中间递推的过程中有假设失败重新倒推的风险,递归不好进行这样的不断试错。

 public static void beachPeach(){
        int lastEach = 1;//假设第五个猴子分的每份只有1个,4份就是4个
        int See = 1*5+1;//初始为第5只猴子看见的桃子数量,随着flag+1,意为前一只猴子看到的桃子数
        int firstSee = 0;
        int flag = 0;//标记有几只猴子分桃子成功
			//当5只猴子都分桃子成功时,跳出循环
        while(flag<5){
        	//判断当前看到的桃子数,是否可以满足分成五分余1,并且要被4整除,才算是找到合理的桃子数跳出循环
        	/*逻辑上来说可以无需判断是否被4整除,只需要满足前一个除5余1,在不满足时再从第五只开始即可,
        	但是推算前一只猴子看到的桃子数时需要除4,很可能吞掉小数位造成计算错误。
        	所以在这里加上写出来更简洁,不然就要写在 See = (See / 4) * 5 + 1;判断句之前,
        	还要进行再一次的返回第五只猴子让flag至0,有部分重复代码,所以干脆把重复部分的判断写到一起*/
            while(See%5 != 1 || (flag< 4 && See%4 != 0)){//后4只猴子看到的桃子数都是前一个猴子剩下的4份
                lastEach++;//有一只猴子分的桃子不是除5余1,则假设第5只猴子分的每份+1
                See = lastEach*5+1;//第5只猴子看见的数量
                flag = 0;//只要有一只猴子分不成功,就从第五只重新开始,跳出循环时,第5只猴子就是分桃子成功的
            }
            flag++;//多一只猴子分桃子成功。假性,并不是真的成功。因为只是当前循环检查下下多一只成功,如果计算出前一只不成功,flag直接清0

            if(flag<5) {//第2,3,4,5只猴子都要算前一个猴子看到的桃子数,第一只猴子看到的桃子数未必除4无余数
                See = (See / 4) * 5 + 1;//前一个看到的等于后一个看到的数目/4×5+1
            }
        }

        firstSee = See;
        System.out.println("初始桃子最少的数量为:"+firstSee);
    }
 beachPeach();

在这里插入图片描述

42、809*??=800*??+9*??,其中??代表的两位数,8*??的结果为两位数,9*??的结果为3位数。求??代表的两位数,及809*??后的结果。

思路:
①假设??代表的数为x,分解式子809x=800x+9x。发现809x = x*(800+9),说明这个式子一点用都没有。
②假设x的范围是【10,99】循环与8乘,筛选出结果为2位数的范围
③在筛选出的范围里,再与9乘,筛选出结果为3位数的范围

 public static void twoDigit(){
        int x = 0;
        for(x = 10; x<100; x++){
            if((x*8)/100 == 0){//最小就是2位数,所以只需判断不到3位数即可
                if(((x*9)/100)%10 > 0  && ((x*9)/100)%10 < 10){ 
                //3位数、100后去掉了个位十位,%10有余数说明>=3位,余数<10,>0说明是3位数
                    System.out.println(" ?? = "+x+", 809*?? = "+x*809);
                }
            }
        }
    }

 twoDigit();

在这里插入图片描述

43、求0—7所能组成的奇数个数。

思路:①个位是奇数一定是奇数,个位是偶数一定是偶数
②0-7有8个数,题意应该为一个数中没有数字重复出现。则奇数位数为1-8位,8种不同位数的类型
③可以从个位开始考虑每一位数字取值的可能性,如果组成个位的奇数,一共有1,3,5,7。4种可能。考虑完个位的奇数后,在个位上考虑十位,十位可以取得数字有7个,除0以外。十位数则有7*4种可能。
④但是到了百位,十位又可以取0,百位的奇数有4*8*7种可能
⑤观察出规律,i位数(9>i>2)组成的奇数有4*8*8*……(*i-2个8)*7
⑥用双层循环,内层循环实现4*8*8*……(*i-2个8)*7。外层遍历1位到8位,八种不同位数的奇数类型,在内层循环结束时累加计算总和

 public static void oddNum(){
        long sum = 4;//一位的奇数有4种
        long num = 4;//作为个位的可能种类
        for(int i=2; i<9; i++ ){
            num = 4;
            for(int j=0; j<i-2; j++){
                //计算*8的次数
                num = (long)num*8;
            }
            num = (long)num*7;
            System.out.print(i+"位的奇数有"+num+"种  ");
            sum = (long)sum+num;
        }
    }

oddNum();

在这里插入图片描述

44、一个偶数总能表示为两个素数之和。

思路:从2开始判断比该偶数小的两个素数,判断相加是否为该偶数
这两个数一定是一个较小<=该数/2,一个较大>=该数/2。
判断较小的是否为素数,如果是则用该数减去较小数,判断得到的较大数是否为素数。如果不是,较小数继续++判断

 public static boolean isPrime(int num){
        //虽然最小的质数是2,被2整除必然是偶数不是素数,所以除数从3开始取值
        for(int i=2; i<=Math.sqrt(num); i++){//必须取<=,不可<不然4输进来都是素数
            if(num%i == 0){
                return false;//有被除1和自身以外的数整除,不是素数
            }
        }
        return true;
    }
    public static void prime(int even){
        int left = 0;
        int right = 0;
        for(int i=2; i<=even/2; i++){
            if(isPrime(i) && isPrime(even-i)){//双&&左边为真右边才运算
                //如果找到了这个小数为素数,再判断大数是否为素数。不是的话,较小数继续++
                left = i;
                right = even-i;
                System.out.println("偶数为两个素数之和 "+even +" = "+left+"+"+right);
            }
        }

    }

		prime(34);
        prime(66);
        prime(748);

在这里插入图片描述

45、判断一个数能被几个9整除。

思路:循环除9看能整除几个

 public static void divisible(int num){
        int n = num;
        int count = 0;//记录整除了几个9
        while(num%9 == 0){
            count++;
            num /= 9;
        }
        System.out.println(n+"可以整除"+count+"个9");

    }

		divisible(81);
        divisible(65610);
        divisible(4251528);

在这里插入图片描述

(字符串可以直接拼接,String与字符数组互相转换)46、两个字符串连接程序。

思路:1>字符串转为字符数组
新建一个数组长度为这两个数组长度之和,分别赋值前一个数组和后一个数组
用System.arraycopy(原数组,原数组复制开始的位置,目标数组,目标数组粘贴开始位置,复制粘贴的长度)
2>咱们就是发现,字符串可以直接拼接
工具:字符串和字符数组互相转化
在这里插入图片描述
方法一:

public static void connect(String str1, String str2){
        System.out.println("原字符串1为"+str1);
        System.out.println("字符串2为"+str2);
        char[] arr1 = str1.toCharArray();
        char[] arr2 = str2.toCharArray();
        char[] sum = new char[arr1.length+arr2.length];

        System.arraycopy(arr1,0,sum,0,arr1.length);
        System.arraycopy(arr2,0,sum,arr1.length,arr2.length);
        String ssum = new String(sum);

        System.out.println("合并后为"+ssum);


    }

方法二:

//46.1
 	    public static void connect_1(String str1, String str2){
        String str = str1+str2;
        System.out.println("合并后为"+str);

    }

		connect("123yg;=-——!@ ","uhahah8*9){4 _-+");
        connect_1(",87yu6* _=-","34chj98_  +");

在这里插入图片描述

47、读取7个数(1—50)的整数值,每读取一个值,程序打印出该值个数的*。

思路:把7个数存放到一个数组里,然后双层循环,内层循环在读取到值时,打印出该值个数的*
外层循环遍历这7个数

 public static void star(int[] num){
            for(int i=0; i<7; i++){
                for(int j=1; j<= num[i]; j++){
                    System.out.print("*");
                }
                System.out.println();
            }
    }

		int[] arr = {1,4,45,23,6,34,3};
        star(arr);

在这里插入图片描述

48、某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:每位数字都加上5,然后用和除以10的余数代替该数字,再将第一位和第四位交换,第二位和第三位交换。

思路;取出4位存入数组即可,其他都是简单的数字运算

 public static int encryption(int num){
        int temp = 0;
        int sum = 0;
        int[] arr = new int[4];

        arr[3] = num%10;
        arr[2] = (num/10)%10;
        arr[1] = (num/100)%10;
        arr[0] = num/1000;

        for(int i=0; i<4; i++){
            arr[i] += 5;
            sum += arr[i];
        }

        sum %= 10;
        arr[3] = sum%10;
        arr[2] = (sum/10)%10;
        arr[1] = (sum/100)%10;
        arr[0] = sum/1000;

        temp = arr[3];
        arr[3] = arr[0];
        arr[0] = temp;

        temp = arr[2];
        arr[2] = arr[1];
        arr[1] = temp;

        return arr[0]*1000+arr[1]*100+arr[2]*10+arr[3];

    }

写完以后感觉这个题不知道是谁编的,加密以后怎么解密。离谱

		System.out.println("3467加密后为"+encryption(3467));
        System.out.println("6438加密后为"+encryption(6438));

在这里插入图片描述

★49、计算字符串中子串出现的次数。

思路:这里默认子串只有一个
通过循环依次比较两个字符串的每一个字符,母串可能需要重复遍历,因为要考虑一种特殊情况若子串中有字符重复出现,如子串为“ababc",母串为”abababc",如果母串只遍历一次中间从不回头比较到ababa时会误以为不相同而错过子串。
所以母串每一个与子串首字母相同的位置都要进行检查后续是否相同,不相同的话。母串遍历位置返回到一开始检查的下一位。子串可能需要很多次,尤其前几位。
先遍历子串找到与母串当前遍历的字符相同的子串中字符位置,找到后母串与子串同步遍历。
如果字符比较一直相同,再++遍历子串,一旦子串没有走到尾却不同了,子串再从头开始。如果一直到子串尾都相同,则出现次数++,子串再从头开始。

工具:charAt();
String.length();

 public static void substring(String mom,String son){
        int count = 0;
        int k = 0;//用来遍历母串与子串匹配时的位置
        for(int i=0; i<mom.length(); i++){
            k = i;
            int j = 0;
            while (j<son.length() && mom.charAt(k) == son.charAt(j)){
                   //先通过循环遍历找到首字母相同的位置,再开始位置一一对照
                   k++;
                   j++;
               }
            if(j == son.length()){
                count++;
            }
        }

        System.out.println("子串"+son+"在母串"+mom+"中出现了"+count+"次");
    }

		substring("123234- _8%237234*uyn23423_220","234");
        substring("7abababc-ababc +9ou_","ababc");

在这里插入图片描述

★(文件创建与读写)50、有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成绩),计算出平均成绩,把原有的数据和计算出的平均分数存放在磁盘文件 "stud "中。

此题考的内容有点多,文件创建与读写此处省略,简单理解为求平均值。
创建二维数组,计算成绩平均数
工具:
文件创建与读写

 public static void fileWriter(String str) {
        FileWriter fw = null;
        try{
            fw = new FileWriter("D:\\xuexueziproject\\ideaProjects\\stud.txt",true);
            System.out.println("数据已经成功写入");
            fw.write(str);
            fw.close();
        }catch(Exception e){
            //抛出一个运行时异常(直接停掉程序)
            throw new RuntimeException("运行时异常",e);
        }finally{
            try{
                //操作完要回收流
                fw.close();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
    public static void student(){
        int i = 0;
        int j = 0;
        int k = 0;
        double average = 0.0;
        String[][] stu = new String[5][2];//5个学生。,一门平均分,学号,姓名
        double[][] stuScore = new double[5][4];//3门成绩
        String str = "";

        Scanner inputId = new Scanner(System.in);
        Scanner inputName = new Scanner(System.in);
        Scanner inputScore = new Scanner(System.in);

        for(i=0; i<5; i++){
            System.out.print("请输入第"+(i+1)+"位同学的学号:");
            stu[i][0] = inputId.nextLine();
            System.out.print("请输入第"+(i+1)+"位同学的姓名:");
            stu[i][1] = inputName.nextLine();
            for(j = 0; j<3; j++){
                System.out.print("请输入第"+(i+1)+"位同学的第"+(++k)+"门成绩:" );
                stuScore[i][j] = inputScore.nextDouble();
                average += stuScore[i][j];
            }
            stuScore[i][3] = average/3;
            k = 0;
        }

        for(i=0; i<5; i++){
            str = "学号" +stu[i][0]+" 姓名"+stu[i][1];
            for(j = 0; j<3; j++){
                str = str +" 第"+(++k)+"门成绩="+stuScore[i][j];
            }
            str = str +" 平均成绩="+stuScore[i][3];
            k = 0;
            System.out.println();
            fileWriter(str+"\r\n");
        }

    }

student();

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值