目录
- 21、求1+2!+3!+...+20!的和。
- 22、利用递归方法求5!。
- 23、有5个人坐在一起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第一个人大两岁。最后问第一个人,他说是10岁。请问第五个人多大?
- ★(数字转字符串,字符串转字符数组)24、给一个不多于5位的正整数,要求:一、求它是几位数,二、逆序打印出各位数字。
- 25、一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同。
- 26、请输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续判断第二个字母。
- 27、求100之内的素数。
- 28、对10个数进行排序。
- 29、求一个3*3矩阵对角线元素之和。
- ★(数组拷贝扩容System.arraycopy)30、有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。
- 31、将一个数组逆序输出。
- 32、取一个整数a从右端开始的4~7位。
- 33、打印出杨辉三角形(要求打印出10行)
- 34、(两种输出数组方法,增强for)输入3个数 a、b、c,按大小顺序输出。
- 35、输入数组,最大的与第一个元素交换,最小的与最后一个元素交换,输出数组。
- ★36、有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面的m个数。
- ★(增强for不可初始化数组)37、有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
- 38、写一个函数,求一个字符串的长度,在main函数中输入字符串,并输出其长度。
- 39、编写一个函数,输入n为偶数时,调用函数求1/2+1/4+...+1/n,当输入n为奇数时,调用函数1/1+1/3+...+1/n。
- ★(charAt() ,String length() )40、字符串排序。
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]=i
(k从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);