【Java基础算法】21-40题(数字转字符串valueOf()+字符串转字符数组+数组拷贝扩容System.arraycopy+charAt() +String length() )

目录

21、求1+2!+3!+…+20!的和。

思路:用循环,遍历次数的同时累乘temp,即为每项的值,同时累加

/**
     * 参数确定项数
     * @param num
     */
           public static void factorial(int num){
        int fac = 1;//存储每项的阶乘
        int sum = 0;//存储阶乘的和

        for(int i=1; i<=num; i++){
            fac *= i;
            System.out.print("+"+i+"!");
            sum += fac;
        }
        System.out.println("="+sum);

    }

	    factorial(5);
        factorial(4);
        factorial(3);
        factorial(2);
        factorial(20);

在这里插入图片描述

22、利用递归方法求5!。

思路:形参num为5,4,3……,调用时num*fac(num-1);
递归出口,形参为1时,结果为1

 //# 22、利用递归方法求5!。
    public static int recursion(int num){
        if(num == 1){
            return 1;
        }
        return num*recursion(num-1);

    }

		System.out.println(recursion(5));
        System.out.println(recursion(3));

在这里插入图片描述

23、有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个人多大?

思路:类似猴子吃桃子。从后往前每次减2,得到第一个人为10岁。则以10岁为初始条件,有循环和递归两种写法。
递归出口为第一个人10岁,形参为当前人是第几个

public static void age(){
        //
        int young = 10;
        for(int i=2; i<=5; i++){//注意,只加四次,因为只有五个人,第一个人年龄已知的,直接从第二个人开始算
            young += 2;
        }
        System.out.println("循环计算第五个人"+young+"岁");
    }


    public static int age_1(int num){
        if(num == 1){
            return 10;
        }
        return 2+age_1(num-1);

    }

		age();
        System.out.println("递归计算第五个人年龄为"+age_1(5));

在这里插入图片描述

★(数字转字符串,字符串转字符数组)24、给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。

思路:
1>①用除法一直试除4次,分别检查十位,百位,千位,万位。每次除如果不为0则位数加一,用来计算数字位数。
因为需要逆序打印,在每次判断位数的时候,按位将数字保存在数组里,从前往后依次保存的是个位,十位,百位……。恰好是逆序保存的
计算位数的方法二用switch-case判断属于那个位数区间
②然后根据位数将保存的位从个位*10*10的次数按位数-1开始递减,。然后相加得到逆序数字然输出
方法二也可以直接逆序输出计算的数组

2>优化,把数字直接转换为字符数组
①计算数字位数,直接输出数组.length即可。
②逆序输出数组即可
注意:与方法一的数字区别在于,字符转化的数组长度是数字的位数,且顺序排列。方法一手动定义的数组长度恒为5,输出时要注意不能多0,所以用位数限制输出范围,且逆序排列。

3>原作者的方法,感觉逆序输出没实现
①计算数字位数,直接输出数组.length即可。
②原作者写的逆序输出数字,跑了一下好像不对System.out.println(num%((int)Math.pow(10, length)));

工具:
Java toCharArray() 方法字符串转数组
Java valueOf() 方法数字等转字符串
Java pow() 方法计算x^y
方法一:试除计算位数,逆序存在数组里。可以直接输出数组结果,也可以组合成数字后输出。

 public static void reverse(int num ){
        int n = num;
        int position = 0;//如果存在至少是个位数

        //每一位都保存一下
        int[] arr = {0,0,0,0,0};

        //计算位数,同时各位存入数组
        for(int i = 0; i<5; i++){

            if(n != 0){
                arr[i] = n%10;
                position++;
                n = n/10;
            }
            else{
                break;//不用再继续
            }
        }
        System.out.println(num+"是"+position+"位数");

        //逆序排序
        //数组存储中,本身就是个位存在arr[0],十位存在arr[1],这种逆序存储,
        // 按位乘10输出即可,十位乘1一次,百位乘2次,千位乘3次
        //外层循环遍历数组元素,并在内层处理完乘10后相加
        //内层循环,实现按位循环乘10,从个位开始循环position-1次
        
        //2.1逆序输出方法一,直接输出数组即可
        System.out.print("输出逆序数组为:");
        for(int i = 0; i<position; i++){
            System.out.print(arr[i]);
        }
        System.out.println();//换行

        //2.2逆序输出方法二,组合成数字输出
//        n = 0;
//        for(int i = 0; i<position;i++){
//            for(int j = position-1-i; j>0; j--){
//                arr[i] *= 10;
//            }
//            n += arr[i];
//        }
//        System.out.println("逆序排序后的数字为:"+n);
    }

方法二:直接把数字转换为字符数组,输出.length计算位数。逆序输出数组为逆序数字。

//24.2 数字转化为字符数组
    public static void reverse_1(int num ){
        //先数字转为字符串
        String str = String.valueOf(num);
        //字符串转为字符数组
        char[] arr = str.toCharArray();
        System.out.println("数组长度为数字"+num+"的位数:"+arr.length);

        //逆序输出
        System.out.print("逆序输出数组为逆序数字");
        for(int i=arr.length-1; i>=0; i--){
            System.out.print(arr[i]);
        }
        System.out.println();
    }

方法三:好像是错误的
原作者写的逆序输出,跑了一下不对System.out.println(num%((int)Math.pow(10, length)));

  private static int digitCapacity(int num){
        char[] ch=String.valueOf(num).toCharArray();
        return ch.length;
    }
    private static void print(int num){
        int length=digitCapacity(num);
        System.out.println(num%((int)Math.pow(10, length)));
    }

		reverse(1237);
        reverse(38109);
        reverse(90);
        reverse_1(1237);
        reverse_1(38109);
        reverse_1(90);
        print(1237);
        print(38109);
        print(90);

在这里插入图片描述

25、一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同。

思路:1>与24题类似,已经确定是5位数,则把数字转换为数组。然后比较arr[0]与arr[4],arr[1]与arr[3]即可。
2>也可以通过数字,提取这五位到五个变量里(通过,/%存到长度5的数组里更方便)存储然后比较,1>直接使用方法toCharArray更方便,且可以不限回文长度。
工具:str.toCharArray(),将字符串转为字符数组

方法一

 public static boolean palindrome(int num){
        int n = num;
        int left = 0;
        int right = 0;//规定一组边界值,可以判断更多位的回文数字

        String str = String.valueOf(n);
        char[] arr = str.toCharArray();

        right = arr.length-1;

        //偶数也有回文,124421
        //奇数走到一个位置跳出,偶数走到相邻位置发现如果值相等跳出.
        //left,right走到相邻位置必为偶数情况,必须相等才算回文
        while(left != right) {
            if(arr[left] == arr[right]){
                if((left == right-1)) {
                    //偶数情况符合回文,且已经走到终点,跳出
                    System.out.println(n+"是回文数");
                    break;//这里不跳出会死循环,永远循环,永远符合循环和上一句if条件。并且left和right一直自增自减
                }
                //奇数情况符合回文条件,继续循环
                left++;
                right--;
            }else{
                //不符合回文条件
                System.out.println(n+"不是回文数");
                return false;
            }

        }
        System.out.println(n+"是回文数");
        return true;
    }

		palindrome(12321);
        palindrome(124421);
        palindrome(123676321);
        palindrome(121);
        palindrome(123421);
        palindrome(123432);
        palindrome(1236321);

在这里插入图片描述

26、请输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续判断第二个字母。

思路:一周七天里,首字母只有T和S需要判断判断第二个字母,单个字符可以用单个字符判断,考虑使用switch语句
注意:在判断数组内元素时,防止越界访问。需要排除空数组的情况,也要注意需要两个字符判断前,先判断数组长度是否>1

 public static void week(char[] weeks){
        String week ="";//用来存放后续判断出的星期
        if(weeks.length <1){
            System.out.println("没有输入数据,请重新输入两位");
            return;
        }
        
        switch(weeks[0]){
            case 'M':
            case 'm':
                week = "Monday";
                break;
            case 'T':
            case 't':
                if(weeks.length<2){//只输入了一位且无法判断
                    System.out.println(weeks[0]+"只输入了一位且无法判断,请重新输入");
                    return;
                }
                else if(weeks[1] == 'u' || weeks[1] == 'U'){
                    week = "Tuesday";
                }
                else if(weeks[1] == 'h' || weeks[1] == 'H'){
                    week = "Thursday";
                }
                break;
            case 'W':
            case 'w':
                week = "Wednesday";
                break;
            case 'F':
            case 'f':
                week = "Friday";
                break;
            case 'S':
            case 's':
                if(weeks.length<2){
                    //只输入了一位且无法判断
                    System.out.println(weeks[0]+"只输入了一位且无法判断,请重新输入两位");
                    return;
                }
                else if(weeks[1] == 'a' || weeks[1] == 'A'){
                    week = "Saturday";
                }
                else if(weeks[1] == 'u' || weeks[1] == 'U'){
                    week = "Sunday";
                }
                break;
            default:
                System.out.println(weeks[0]+"输入错误,请重新输入");
        }
        System.out.print("根据");
        for(int i = 0; i<weeks.length;i++){
            System.out.print(weeks[i]);
        }
        System.out.println("判断是"+week);

    }

		week("".toCharArray());
        week("a".toCharArray());
        week("s".toCharArray());
        week("su".toCharArray());
        week("t".toCharArray());
        week("f".toCharArray());
        week("tu".toCharArray());

在这里插入图片描述

27、求100之内的素数。

思路:跟第2题一样,当时用了三种方法,
①双层循环,外层遍历可能的数,1-100,。内层判断循环取余比自己小的数。设置信号变量每次在外层循环置true。内层取余为0时,判断信号false,外层循环输出素数
②双层循环,无需信号。内层取余为0时跳出循环,外层判断内层循环是否走完,走完为素数。
③优化了②,内层取余的除数开方,因为如果可以被整除,一定有一组数相乘为该数,且其中较小的数小于等于该数的开方。
④ 这次写优化③,给除数从3开始每次自增2,因为偶数一定不是素数,没有判断的必要。
方法四

  private static void printNum(int num){
       int n = num;
        System.out.print(" "+2);

       for(int i = 3; i<=n; i+=2){//3往后的素数必不可能为偶数,所以从3开始每次自增2
           int j = 0;
           for(j = 2; j<=(int)Math.sqrt(i); j++){//计算是否素数从2开始除,若不是,除数一定小于该数i的开方
               if(i%j == 0){
                   break;
               }
           }
           if((int)Math.sqrt(i)+1 == j){//判断内循环有没有走完最后一次
                System.out.print(" "+i);
           }
       }
       System.out.println();
    }


		printNum(100);
        printNum(1000);

在这里插入图片描述

28、对10个数进行排序。

思路:默认由小到大排序,冒泡排序
①比较相邻元素,如果第一个比第二个大就交换他们两个
②每趟从第一对相邻元素开始,对每一对相邻元素做同样的工作,直到最后一对
③针对所有的元素重复以上的步骤,除了已经排序过的元素(每趟排序后的最后一个元素),直到没有任何一对数字需要比较
用双层循环实现,内循环遍历一次比较交换两个相邻的数字,外循环控制遍历次数及内循环的遍历停止位置。
如遍历第三次时,倒数1,2的位置已经是排好顺序的位置,应该在第8位停止。

  public static void bubbleSort(int[] num){
        int temp = 0;
        for(int i=0; i<num.length-1; i++){//10个数字,比较9次即可

            for(int j=1; j<=num.length-1-i; j++){//第一次比较[0],[1]一直比较到[l-2][l-1]
                //j范围[1,length-1]
                if(num[j-1] > num[j]){
                    temp = num[j-1];
                    num[j-1] = num[j];
                    num[j] = temp;
                }
            }
        }

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

		int[] num = {10,9,8,7,6,5,4,3,2,1};
        int[] num1 = {10,59,8,7,36,5,42,3,2,91};
        int[] num2 = {10,39,8,17,67,5,4,23,42,1};
        bubbleSort(num);
        bubbleSort(num1);
        bubbleSort(num2);

在这里插入图片描述

29、求一个3*3矩阵对角线元素之和。

思路:用二维数组来表述一个n行n列的矩阵
工具:二维数组
在这里插入图片描述
在这里插入图片描述

public static void diagonal(int[][] arr) {
        //第一个一维数组的长度即为他们的行列长度
        //对角线上的元素下标为两个相同
        int sum = 0;
        for (int i = 0; i < arr[0].length; i++) {
            sum += arr[i][i];
        }

        //打印3*3的矩阵
        for (int j = 0; j < arr[0].length; j++) {
            for (int k = 0; k < arr[0].length; k++) {
                System.out.print(" " + arr[j][k]);
            }
            System.out.println();
        }
        System.out.println("该3*3矩阵对角线的和为:" + sum);
    }

 		int[][]arr = new int[][]{
                {1,2,3},
                {4,5,6},
                {7,8,9}
        };
        int[][]arr1 = new int[][]{
                {3,8,2},
                {2,7,5},
                {9,0,1}
        };
        diagonal(arr);
        diagonal(arr1);

在这里插入图片描述

★(数组拷贝扩容System.arraycopy)30、有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。

思路:将数组扩容一个位置,为插入的数做准备
①先判断已经排好序的数组是升序还是降序,比较前两位大小,如果两两比较一直相等就比较到有大小为止(也有可能全部相等平序,但这种情况插入到哪都可以,没有讨论意义)
②根据升序或降序,比较插入的数据即将插入的位置,例如升序的话,arr[i]<=inset<arr[i+1]则即将插入的下标为i+1找到的i+1也是第一个比自己大数所在的位置。
③寻找插入位置时,有可能一直找到了数组尾,这种情况,无需后移,在数组最后补上插入的数即可
④创建了新的大一个空间的数组之后,关于集体移动连续的后半部分数组有两种做法,用循环每个数依次往后挪一格将i+1所在的数~原length-1位的数,全部往后挪一位。
⑤或者用赋值函数,一开始赋值时,就将原数组分成两部分进行拷贝,后半部分粘贴到新数组时起始位置比原数组+1即可。
注意:必须从原length-1位开始挪,因为前面的依次往后挪,会覆盖掉后面的数字

工具:数组扩容和拷贝
观察实例理解函数的形参含义System.arraycopy(原数组名,原数组复制的起始位置,目标数组名,目标数组粘贴的起始位置,拷贝粘贴的长度)
在这里插入图片描述

 public static int[] insert(int[] num ,int x){
        if(num.length<1){
            System.out.println("数组为空,请重新输入");
            return num;
        }
        int n = num.length;
        int i = 0;//记录一直相同的数字末尾
        int j = 0;//遍历数组
        int insert = x;
        int ii = 0;//记录要插入的位置
        int[] arr = new int[num.length+1];


        while((i<n-1) && (num[i]==num[i+1])){
            i++;//找出数组中不相同的两个相邻数
        }

        if(i == n-1){
            //说明num中所有数都相等,或只有一位数,直接return,因为没有排序规律
            System.out.print(" 数组num :");
            Test_36_40.printArray(num);
            System.out.println(" 数组num没有排序规律");
            return num;
        } else if(num[i] > num[i+1]){
            //降序
            j = i;
            while(j<n && insert<=num[j]){//注意必须把下标控制写在前面,防止数组越界
                j++;//没找到比他小的就不能停,直到找到第一个比他小的,或者走到头了,说明他要填到现数组的末尾
            }
        }else{
            //升序
            j = i;
            while(j<n&&insert>=num[j]){
                j++;没找到比他大的就不能停,直到找到第一个比他小的,或者走到头了,说明他要填到现数组的末尾
            }
        }

        System.out.print(" 数组num :");
        Test_36_40.printArray(num);

        System.arraycopy(num,0,arr,0,num.length);
        if(j == n){//要插入的数字正好在整个数组之后
            ii = n;
            arr[ii] = insert;

        }else {
            ii = j;
            //写法一
//            i = n - 1;//从原数组的最后一位开始
//            while (i >= ii) {//位置ii往后都要向后挪一位
//                arr[i + 1] = arr[i];
//                i--;
//            }
            //写法二
            System.arraycopy(num,ii+1,arr,ii+1,num.length-ii-1);
            //写法二结束
            arr[ii] = insert;
        }
        System.out.print("按排序规律插入"+insert+"后为: ");
        Test_36_40.printArray(arr);
        return arr;
    }

	    int[] arr = {4,4, 4,2,2,1};
        int[] arr1 = { 1,1,1,2,3,3};
        int[] arr2 = {5,5,5,5,5};
        int[] arr3 = {1};
        int[] arr4 = {1,3};
        int[] arr5 = {10,5,3};
        int[]arr6 = {};
        insert(arr,3);
        insert(arr1,4);
        insert(arr2,100);
        insert(arr3,23);
        insert(arr4,0);
        insert(arr5,7);
        insert(arr6,89);

在这里插入图片描述

31、将一个数组逆序输出。

思路:
1>下标i范围[0,length-1],按下标[length-1-i]输出
2>考虑怎么取数组下标i范围[length-1,0],按下标[i]输出
方法一

 public static void reverse(int[] arr){
        for(int i=0; i<arr.length; i++){
            System.out.print(arr[arr.length-1-i]+" ");
        }
        System.out.println();
    }
   

方法二:

 public static void reverse_1(int[] arr){
        for(int i=arr.length-1; i>=0; i++){
            System.out.print(arr[i]+" ");
        }
        System.out.println();
    }

//31.
        int[] arr = {42,5};
        int[] arr1 = new int[]{3,2,6,13,56};

        int[] arr2 = new int[3];
        arr2[0] = 45;
        arr2[1] = 6;
        arr2[2] = 78;

        int arr3[] = new int[]{21};

        reverse(arr);
        reverse(arr1);
        reverse(arr2);
        reverse(arr3);

在这里插入图片描述

32、取一个整数a从右端开始的4~7位。

思路:取这几位不知道要取出来是数字还是数组
1>如果是数字的话用原数/1000得到从有段开始的第4位在个位,然后再%10000,得到4~7的这四位
2>如果是取出数组,则将数字转为字符串,然后字符串转为字符数组。再从倒数第4位开始打印四次
方法一:

public static void takeOut(long num){
        System.out.println(num+"从右端开始的4~7位为 "+(num/1000)%10000);
    }  

方法二:

  public static void takeOut_1(long num){
        //先数字转为字符串
        String str = String.valueOf(num);
        //字符串转为字符数组
        char[] arr = str.toCharArray();

        System.out.print(num+"从右端开始的4~7位为 ");
        for(int i = arr.length-7; i <arr.length-3; i++){
            System.out.print(arr[i]);
        }
        System.out.println();
    }

 		takeOut(1234503467891l);
        takeOut(1240534109230L);

        takeOut_1(1234503467891l);
        takeOut_1(1240534109230L);

在这里插入图片描述

33、打印出杨辉三角形(要求打印出10行)

在这里插入图片描述
思路:
①杨辉三角的规律是每个数都等于自己上方左右两个数的和,首先想到的是要怎么通过存储上方两个变量来循环相加计算下方的,显然两个int型变量很难满足5行以后的情况,因为只能记录一组。考虑可以通过一个二维数组存储。
②默认二维数组元素全为0,先对数组前两行进行辅赋值,只对二维数组的下三角赋值。观察得知,每行的首位与末尾都为1,首位为arr[i][0],末位为arr[i][i]
③从第2行循环开始,发现i行j列的数= i-1行j-1列的数+i-1行+j列的数。即[i][j] = [i-1][j-1] +[i-1][j]
④用双层循环,外层循环遍历每行,内层循换计算该行数字。外循环取值[0,num-1](num为规定的杨辉三角行数)内层每行赋值循环i+1次(第i行遍历赋值取值[0,i])
此时已经完成杨辉三角的直角形状,再调整每行的空格数

1 
[0][0]
1        1
[1][0]  [1][1]
1          2        1
[2][0]  [2][1]    [2][2]
1          3         3      1
1          4         6      4       1
1          5        10      10      5        1
1          6        15      20      15       6     1
 public static void yangHui(int num){
        int[][] arr = new int [num][num];

        //先赋值1

        for(int i=0; i<num; i++){
            for(int j=0; j<=i; j++){
                if(j == 0 ||j == i){
                    arr[i][j] = 1;
                }else{
                    //只有排除了首列才不会出现数组访问越界的问题,如arr[-1]这种情况
                    arr[i][j] = arr[i-1][j-1]+arr[i-1][j];
                }

            }
        }

        //打印数组
        for(int i=0; i<num; i++){
            for(int k=num+-i; k>0; k--){//本来写的num/2想着刚好是一半长的空格,但是一个空格一个字符,一个数字两个。不匹配
                System.out.print("  ");//敲了两个空格
            }
            for(int j=0; j<=i; j++){
                System.out.printf(" %3d",arr[i][j]);//格式控制符,因为最多的是三位数
            }
            System.out.println();
        }
    }

yangHui(10);
yangHui(20);//20行就有点不齐了

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

34、(两种输出数组方法,增强for)输入3个数 a、b、c,按大小顺序输出。

思路:与15题相同,15题的形参为三个int ,这里可以设置为一个一维数组存放。依旧是,冒泡排序的思路,类似28题。题目顺序不明,可以写升序和降序两种

//输出数组
	public static void printArray(int[] num){
//        for(int i=0; i<num.length; i++){
//            System.out.print(" "+ num[i]);
//        }
//        System.out.println();

        for(int n:num){
            System.out.print(n+",");
        }
    }
//升序
    public static void AscendingSort(int[] num){
        int temp = 0;

        printArray(num);
        System.out.print(" 该数组升序排序后为  ");
        //升序
        for(int i=0; i<num.length-1; i++){//比较次数length-1次即可
            for(int j=0; j<num.length-i-1; j++){
                if(num[j]>num[j+1]){
                    temp = num[j];
                    num[j] = num[j+1];
                    num[j+1] = temp;
                }
            }
        }

        printArray(num);
    }
//降序
  public static void DescendingSort(int[] num) {
        int temp = 0;
        printArray(num);
        System.out.print(" 该数组降序排序后为  ");
        //降序
        for(int i=0; i<num.length-1; i++){
            for(int j=0; j<num.length-1; j++){
                if(num[j]<num[j+1]){
                    temp = num[j];
                    num[j] = num[j+1];
                    num[j+1] = temp;
                }
            }
        }

        printArray(num);
    }

		int[] arr = new int[]{1,2,3,4};
        int arr1[] = {5,2,7,19,23,0};
        AscendingSort(arr);
        AscendingSort(arr1);

        DescendingSort(arr);
        DescendingSort(arr1);

在这里插入图片描述

35、输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组。

思路:①遍历一遍数组,用两个变量max和min存储最大数和最小数,初始值为数组首位,依次和每一位相比较。
②例如max,若所比较的数比max大,则将下标赋值给max,min同理。遍历一遍结束后,将max和min位置的数字与数组首位末尾交换
注意:过程中发现一种特殊情况如{1,2,3,4}找到max为3,min为0。第一次交换max与0位置,第二次交换min与3位置。等于什么都没做,这种特殊情况属于,找到了min为0并且max为length-1。只需交换一次即可

  public static void exchange(int num[]){
        int max = 0;
        int min = 0;//并不是初始化为0,而是指数组的首位下标
        int temp = 0;

        System.out.print("该数组 ");
        printArray(num);

        //找到最大值和最小值的下标
        for(int i=0; i<num.length; i++){
            if(num[i]<num[min]){
                min = i;
            }
            if(num[i]>num[max]){
                max = i;
            }
        }
        //最大值交换到首位
        temp = num[0];
        num[0] = num[max];
        num[max] = temp;

        //最小值交换到末尾,要排除最小值等于首位,最大值等于末尾的情况,这样会重复交换两次
        if(max != num.length-1 || min != 0){
        temp = num[num.length-1];
        num[num.length-1] = num[min];
        num[min] = temp;
        }
        System.out.print(" 最大值交换到首位,最小值交换到末尾为:");
        printArray(num);

        System.out.println();

    }

		int[] arr = new int[]{1,2,3,4};
        int arr1[] = {5,2,7,19,23,0};
        exchange(arr);
        exchange(arr1);

在这里插入图片描述

★36、有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面的m个数。

思路:由题目得到n=m的情况无需变化所以n>m,。
1>①可以先将后m个数【n-m,n-1】存放起来,然后将前n-m个数字【0,n-m-1】从第n-m位开始向后移m个位置。从后开始移动是为了防止,前n-m的前几位将后几位数字覆盖掉。
②完成n-m次移动后,再用存起来的m个数覆盖前m位

2>①使用System.arraycopy进行两次复制拷贝,分别复制前n-m个【0,n-m-1】到数组1,再复制后m个【n-m,n-1】到数组2
②然后将数组2粘贴给原数组的【0,m-1】的位置,再粘贴数组1到原数组的【m,n-1】位置即可。

工具:跟30题一样
观察实例理解函数的形参含义System.arraycopy(原数组名,原数组复制的起始位置,目标数组名,目标数组粘贴的起始位置,拷贝粘贴的长度)

public static void cover(int[] num,int n,int m){

        if(m>= n){
            System.out.println("m和n输入错误");
            return;
        }
        int[] arr = new int[m];
        int kk = 0;
        //存放后m位
        for(int i=n-m; i<n; i++){
            arr[kk] = num[i];
            kk++;
        }

        System.out.print("存放后m个数的数组arr为:  ");
        printArray(arr);

        //移动前n-m个数字
        for(int j= n-m-1; j>=0; j--){
            num[j+m] = num[j];
        }

        System.out.print("前n-m个数字后挪m个位置后的num数组为: ");
        printArray(num);

        System.arraycopy(arr,0,num,0,arr.length);
        System.out.print("最后m个数变为前m个数后num数组为: ");
        printArray(num);


    }

方法二:用System.arraycopy

 public static void cover_1(int[] num,int n,int m){
        if(m>= n){
            System.out.println("m和n输入错误");
            return;
        }
        System.out.print("m = "+m+" n = "+n+" num数组为:");
        printArray(num);

        int[] arr1 = new int[n-m];
        int[] arr2 = new int[m];

        System.arraycopy(num,0,arr1,0,n-m);
        System.arraycopy(num,n-m,arr2,0,m);

        //打印保存的两部分
        System.out.print("arr1保存的前n-m个数为:");
        printArray(arr1);
        System.out.print("arr2保存的后m个数为:");
        printArray(arr2);


        //给原数组num赋值
        System.arraycopy(arr1,0,num,m,n-m);
        System.arraycopy(arr2,0,num,0,m);

        System.out.print("交换完成后的num为 :");
        printArray(num);


    }

		 int[] arr = {1,2,3,4,2};
         int[] arr1 = {5,34,56,32,198,4};
         //注意:以下两组不同方法分开调用,因为每次调用完会影响作为实参的数组内容
         //cover(arr,arr.length,2);
         //cover(arr1,arr1.length,4);
         cover_1(arr,arr.length,2);
         cover_1(arr1,arr1.length,4);

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

★(增强for不可初始化数组)37、有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。

思路:
需要注意特殊情况,即人数少于两个,和只有两个时
人数少于两个直接返回人数n,不参与报数判断,人数为2时,第一个人第一轮报数参与两次,一次1一次3。
1>①创建一维数组,存储这n个人。数组存储初始值都设置为1,若报数为3退出圈子,则设置为0。
②循环重复报数,每循环一次实际为确定报数1,2,3的三人在num中的下标。用一个数组arr记录正在报数1,2,3的3位在num中的下标位置。三个变量循环每次走1,碰到num变量值为0时说明该位置无人就跳过,走到数组尾时又重新从数组头开始,组成一个圈。
③因为不知道哪个位置有人,所以arr中的每个元素都可能要跳过很多num值为0的位置,用i的自增来遍历num[i]i从上一次退圈的人的下一位开始循环,判断确定arr的值。
④当找到一个num[i]不为0的位置时,确定arr[k]=ik从0开始意思为报数为1的人的位置),即找到了报数1的人的位置。k++开始找报数为2的人的位置,依次类推直到三个人的位置都找到,即k只自增两次到3停止循环。寻找过程中若i超过了num的长度,则i又从0开始。
⑤有两种方法判断结束,一,给定变量count记录圈中所剩人数,即数组中只有一个位置是1时停止。二,只剩一个人时,寻找的新一组arr的值全部相等,都是这一个人在num中的下标位置。
在这里插入图片描述2>①用boolean类型来存储当前位置是否有人,初始化都为true,如果报数为3当前位置内容设置为false。
②无需arr存储,只需循环每次找出一个报数为3的人位置即可,每次从假设报数为0,确认当前位置有人再报的数++,加到3则找到了这次循环要退圈的人。若遍历到尾部从0开始完成圈。
③需要记录圈中剩余人数,即开始为n个人,每次报数3时减一。直到剩一个人为止结束循环。
④需要记录每次报数的人的位置,即在数组中的下标索引,在达到数组尾部时,调回数组头。

工具:踩的坑注意不可以用增强for来初始化数组,无法改变数组元素
在这里插入图片描述

方法一:arr存储当前一组报数1,2,3人的下标。这个方法自己硬想的,写法和思路都有点绕,方法二写的更好。

 public static void loop(int n){
        //要求实参数组至少两位,且都要等于1
        int num[] = new int[n];
        for(int i=0; i<num.length; i++){
            num[i] = 1;
        }
        int[] arr =new int[3];//定义一个数组,arr[0]存放报数1的人所在num中的下标。
        arr[0] = 0;
        arr[1] = arr[0]+1;
        arr[2] = arr[1]+1;//考虑数组只有两个人的情况下会越界

        int count = n;
        //while(count != 1)//这两种写法都可
        while(!(arr[0] == arr[1] && arr[1] == arr[2])) {//每循环一次就是找一组1,2,3的人,如果按遍历一遍循环一次的话,剩两个人时无法判断
            //每次循环进来判断上一次循环尾部设置的三个下标是否越界,如果越界根据末尾标记,从数组头重新开始
            //报数为3的人退出,报数为1的在退出的人的下一个位置

            //判断特殊情况,如一开始就只有两个人,或一个人或没有人
            if (n<2) {
                System.out.println("人数不足2个,输入错误");
                return;
            } else if (n<3) {//只有两个人,则报数3的人也为第一个
                arr[2] = 0;
            }

            //报3的退出
            if (num[arr[2]] == 1) {
                num[arr[2]] = 0;//报数3的人退出
                count--;

                arr[0] = arr[2] + 1;//先把报1的挪到报三之后的位置,再判断该位有没有人
            }
            System.out.print("剩余人数为" + count + ",这一轮有人退出后的num数组为:");
            printArray(num);

            //核心,从arr[0]开始找不为0的位置,组成一组新的报数组1,2,3。
            //且生成过程中已经判断过越界情况
            int k = 0;//先给arr[0]确定内容
            for (int i = arr[0]; k < 3; i++) {//此时从报数1的人从上一个退圈的人的下一位开始判断该位置是否有人
                if (i >= num.length) {//数组越界了,就从0又开始
                    i = 0;
                }
                if (num[i] == 1) {
                    //报数为1的人位置确定了,则k++,开始判断报数为2的人的位置
                    //或报数为2的人位置确定了,则k++,开始判断报数为3的人的位置
                    arr[k] = i;
                    k++;
                }
            }

            System.out.print("新找到的报数下标依次为:");
            printArray(arr);
        }

        count = arr[0]+1;//结束时,arr数组内统一都是剩余那个人的下标,这里随便填arr[1],arr[2]都可
        System.out.println("最后剩下的人是第"+count+"个");
        System.out.println();
    }

方法二:只有报数3的人需要退圈所以无需保存报数1,2的人。选择报数从0开始,若当前位置有人再+1。避免了先把报数1的人的位置挪到报数3人之后,还要再判断报数1的位置是否有人。

//37.1
    //无需arr数组,只需要每次报数从0开始,遇到数组位置有人再加1即为报数
    private static int stay(int n) {
        if (n < 2) {
            System.out.print("圈人数不足两个");
            return n;
        }

        boolean[] num = new boolean[n];
        int numOff = 0;//报的数为0,说明无人,没报数
        int indexes = 0;//当前报数人的位置
        int count = n;
        //初始化人数组
        //错误写法,增强for不能改变num数组
//        for (boolean b : num) {
//            b = true;
//        }
        for(int i=0; i<num.length; i++){
            num[i] = true;
        }
        
        while (count > 1) {//每次循环都会indexes++,每次count最多-1
            if (indexes == n) {//经过上一轮循环末尾的++遍历,下标已经越界
                indexes = 0;//从数组头重新开始
            }
            if (num[indexes] == true) {//当前索引所在位置有人
                numOff++;//可以报数
                //嵌套if跟方便,比分开写每次报数3时少走一次循环
                if (numOff == 3) {//当前人退圈,且报数重新从0开始
                    num[indexes] = false;
                    count--;
                    numOff = 0;
                }
            }
            indexes++;//当前位置的本轮工作做完;即报数或无人则越过;或报3已退出,下一位从0开始报数。

            System.out.print("循环本次后数组num为: ");
            for (boolean b : num) {
                System.out.print(" " + b);
            }
            System.out.println();
        }

        //循环结束,只剩一个人时,此时indexes在上一个退圈人后一个位置,count为1
        //需要重新寻找剩的人的位置

        for(int i = 0; i<num.length; i++){
            if(num[i] == true)
                indexes = i;
        }
        return indexes+1;
    }

		 loop(7);
         loop(2);
         loop(3);
         loop(0);
         loop(1);
         System.out.println(stay(7));
         System.out.println(stay(2));
         System.out.println(stay(3));
         System.out.println(stay(0));
         System.out.println(stay(1));

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

38、写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。

思路:可以用方法str.toCharArray将字符串转化为字符数组,然后输出数组长度
工具:toCharArray();

public static void character(String str){
        char[] arr = str.toCharArray();
        System.out.println(str+"字符串长度为"+arr.length);
    }

 character("12fs;,987;fa]/");
         character(" 12fahaha哈哈");

在这里插入图片描述

39、编写一个函数,输入n为偶数时,调用函数求1/2+1/4+…+1/n,当输入n为奇数时,调用函数1/1+1/3+…+1/n。

思路:判断输入数据的奇偶性来确定首项即可

public static void oddEven(int num){
        int k =0;
        double d = 0.0;
        if(num%2 == 0){
            k=2;
        }else{
            k=1;
        }

        System.out.print("调用函数:");
        for(int i=k; i<=num; i+=2){
            d += (double)1/i;
            System.out.print("+1/"+i);
        }

        System.out.println(" = "+d);
    }

		 oddEven(4);
         oddEven(9);

在这里插入图片描述

★(charAt() ,String length() )40、字符串排序。

思路:
1>①要排序一个字符串数组,比较字符串可以采用将字符串转化为字符数组的方式toCharArray()。
②从字符串的第一位开始比较,较大的字符所在的字符串为较大。如果相同则继续比较下一位,
③如果两个字符串长度不同,但可比较的范围内字符都相同,则较长的字符串为较大

2>①将排序,与字符串比较分成两个函数,
②并使用函数直接取字符串中的某一个字符进行比较确定字符串大小,Java charAt() 方法
③使用Java String length() 方法比较字符串长度,在可比较的范围都相等的情况下

工具:toCharArray();
Java charAt() 方法
charAt() 方法用于返回指定索引处的字符。索引范围为从 0 到 length() - 1
Java String length() 方法
length() 方法用于返回字符串的长度。

空字符串的长度返回 0。
方法一:循环遍历字符串转为的字符数组得每一位比较大小

public static void stringSort(String[] str){
//排序前打印一下
        System.out.println("str数组 ");
        for(String s:str){
            System.out.print(" "+s);
        }
        System.out.println();

		//冒泡排序
        String temp ="";
        for(int i=0; i<str.length; i++){//外层循环控制遍历str数组次数,遍历str.length-1次即可,找出后str.length-1个较大字符串
            for(int j=0; j<str.length-1-i; j++){//中层循环遍历一次str数组,每次0-str.length-2-i时停止

                //设置两个数组,接收当前要比较的两个字符串的字符
                char[] arr = str[j].toCharArray();
                char[] arr1 = str[j+1].toCharArray();
                int k = 0;
                
                //比较字符串大小
               for(k=0; (k<arr.length) && (k<arr1.length); k++) {//内层循环,两两比较字符,k确定遍历的是第几个字符
                   if (arr[k] > arr1[k]) {
                       //同样的位置,字符大,则所在的字符串就更大
                       //str[i]>str[i+1]
                       temp = str[j];
                       str[j] = str[j+1];
                       str[j+1] = temp;
                       break;//比较完毕,进行下一组j的位置比较
                   } else if (arr[k] < arr1[k]) {
                       //str[i]<str[i+1]无需交换
                       break;//无需比较剩下的字符
                   }else{
                        //无法辨别继续比较
                   }
               }
               //若所比较的位置都相等,说明k已经走到了较短字符串的临界位置
                if(k == arr1.length){
                    //说明arr1较短,则str[j+1]较短,交换
                    temp = str[j];
                    str[j] = str[j+1];
                    str[j+1] = temp;

                }else{
                    //说明arr较短,则str[j]较短,无需交换
                }
            }

            System.out.println("这一趟比较完,str数组为 ");
            for(String s:str){
                System.out.print(" "+s);
            }
            System.out.println();

        }
    }

 //40.1用方法优化40
    //字符串大小比较
    public static boolean stringSize(String str1,String str2){
        //如果左比右大,返回true
        int i = 0;
        while(i<str1.length() && i<str2.length()){
            if(str1.charAt(i) > str2.charAt(i)){
                return true;
            }else if(str1.charAt(i) < str2.charAt(i)){
                return false;
            }
            i++;
        }
        if(i == str1.length()){//说明str1短,且与str2可比较部分都相同
            return false;
        }else{//说明i == str2.length ,str2短,且与str2可比较部分都相同
            return true;
        }
    }
    //字符串排序
    public static void bubbleSort_1(String[] str){
        //排序前打印一下
        System.out.print("字符数组为");
        for(String s:str){
            System.out.print(" "+s);
        }

        for(int i=0; i<str.length-1; i++){
            for(int j=0; j<str.length-i-1; j++){
                if(stringSize(str[j],str[j+1])){
                    String temp =str[j];
                    str[j] = str[j+1];
                    str[j+1] = temp;

                }

            }
        }

        //排序完打印一下
        System.out.print("排序后字符数组为");
        for(String s:str){
            System.out.print(" "+s);
        }
        System.out.println();

    }
		 String[] arr = {"abc","ab","z","cbdfg"};
         String[] arr1 = {"zc","zca","s","dfe","df"};
         //同样的,以下两组调用分开调
        // stringSort(arr);
         //stringSort(arr1);
		 bubbleSort_1(arr);
         bubbleSort_1(arr1);

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值