目录
HJ1 字符串最后一个单词的长度
题目
题目描述
计算字符串最后一个单词的长度,单词以空格隔开。
输入描述:
输入一行,代表要计算的字符串,非空,长度小于5000。
输出描述:
输出一个整数,表示输入字符串最后一个单词的长度。
解法1
读入整行字符串,用split(" ")方法获取字符串数组,取得数组最右一项字符串属性length,输出结果。
笔记:
1 用split(" “)方法获取以” "分隔的字符串数组。
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();//读入一行
String[] s = str.split(" ");//将每个单词存入数组
int length = s[s.length-1].length();//取得最后一个单词的长度
System.out.println(length);
}
}
解法2
读入整行字符串,用toCharArray()方法转为字符数组,倒序比较字符计数,读到’ '时停止计数,输出结果。
笔记:
1 用toCharArray()方法将字符串转为字符数组。
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();//读入一行
//转为字符数组,加快定位比较
char[] chArr = str.toCharArray();
int count = 0;//用于记录最后一个单词长度
//倒序读取,读到空格就停止
for(int i = chArr.length-1; i>=0; i--){
if(str.charAt(i)==' '){
break;
}
count++;
}
System.out.println(count);
}
}
HJ2 计算字符个数
题目
题目描述
写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字母,然后输出输入字符串中该字母的出现次数。不区分大小写。
输入描述:
第一行输入一个由字母和数字以及空格组成的字符串,第二行输入一个字母。
输出描述:
输出输入字符串中含有该字符的个数。
解法1
遍历字符串,逐位比较
笔记:
1 读入第一行字符串,用toLowerCase()方法获取大写字母转换为小写字母的字符串。
2 用charAt(0)方法取出字符串特定位置的字符。
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
//将所有输入的字母都转换为小写
String l1 = sc.nextLine().toLowerCase();
String l2 = sc.nextLine();
char target = l2.charAt(0);
target = Character.toLowerCase(target);
int count = 0;//计数目标字母出现次数
//逐位比较
for(int i = 0;i<l1.length();i++){
if(l1.charAt(i)==target){
count++;
}
}
System.out.println(count);
}
}
HJ3 明明的随机数
题目
题目描述
明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤1000),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“去重”与“排序”的工作(同一个测试用例里可能会有多组数据(用于不同的调查),希望大家能正确处理)。
注:测试用例保证输入参数的正确性,答题者无需验证。测试用例不止一组。
当没有新的输入时,说明输入结束。
输入描述:
注意:输入可能有多组数据(用于不同的调查)。每组数据都包括多行,第一行先输入随机整数的个数N,接下来的N行再输入相应个数的整数。具体格式请看下面的"示例"。
输出描述:
返回多行,处理后的结果
解法1
使用TreeSet排序,正序输出。
笔记:
1 TreeSet排序方式是从小到大
2 用.toArray()将TreeSet转换为数组
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int num = sc.nextInt();
//新建TreeSet对加入的数进行排序去重
TreeSet ts = new TreeSet();
for(int i=0;i<num;i++){
ts.add(sc.nextInt());
}
//用迭代器输出
//Iterator iterater = ts.iterator();
//while(iterater.hasNext()){
// System.out.println(iterater.next());
//}
//转为数组输出
for(Object tmp : ts.toArray()){
System.out.println(tmp);
}
}
}
}
解法2
使用Arrays工具类的.sort()方法排序,正序输出。
笔记:
1 Arrays工具类的.sort()方法对数组进行从小到大的排序。
import java.util.Scanner;
import java.util.Arrays;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
int num = sc.nextInt();
//新建数组记录输入的学号
int[] intArr = new int[num];
for(int i=0;i<num;i++){
intArr[i]=sc.nextInt();
}
//对数组进行排序
Arrays.sort(intArr);
//输出数组,重复元素不输出
for(int i=0;i<intArr.length;i++){
//若是第一个元素或与上一个元素不想等,则可以输出
if(i==0||intArr[i]!=intArr[i-1]){
System.out.println(intArr[i]);
}
}
}
}
}
HJ4 字符串分隔
题目
题目描述
连续输入字符串,请按长度为8拆分每个字符串后输出到新的字符串数组;
长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。
输入描述:
连续输入字符串(输入多次,每个字符串长度小于100)
输出描述:
输出到长度为8的新字符串数组
解法1
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
//读入字符串
String s = sc.nextLine();
//获取要完整输出的组数
int numLine = s.length()/8;
for(int i=0; i<numLine; i++){
System.out.println(s.substring(i*8,i*8+8));
}
//若还有待输出的不完整数组,单独输出
if(s.length()%8!=0){
int zeroNum = (numLine+1)*8-s.length();
String tmp = s.substring(numLine*8);
for(int i=0; i<zeroNum; i++){
tmp += "0";
}
System.out.println(tmp);
}
}
}
}
HJ5 进制转换
题目
题目描述
写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。
输入描述:
输入一个十六进制的数值字符串。注意:一个用例会同时有多组输入数据,请参考帖子https://www.nowcoder.com/discuss/276处理多组输入的问题。
输出描述:
输出该数值的十进制字符串。不同组的测试用例用\n隔开。
解法1
倒序读取16进制数,根据字符取得单位16进制数,乘上位对应的权,转换为10进制。
import java.util.Scanner;
public class Main {
public static void main(String[] args){
//监视输入
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
//读入下一行输入,取出剔除前两个字符的字符串
String line = sc.nextLine().substring(2);
int length = line.length();
int target=0;
int bitHeight = 1;//位数
for(int i=length-1;i>=0;i--){
char c = line.charAt(i);
if(c<='9'&&c>='0'){
target+=(c-'0')*bitHeight;
}else if(c>='A'&&c<='F'){
target+=(c-'A'+10)*bitHeight;
}
bitHeight*=16;
}
System.out.println(target);
}
}
}
解法2
使用Integer.valueOf(str, n)将字符串按n进制数转换成10进制数。
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
while(scanner.hasNext())
{
String str = scanner.nextLine();
//System.out.println(str.substring(2));
//System.out.println(Integer.valueOf(str.substring(2),16));
System.out.println(Integer.valueOf(str.substring(2),16).toString());
}
}
}
HJ6 质数因子
题目
题目描述
功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 )
最后一个数后面也要有空格
输入描述:
输入一个long型整数
输出描述:
按照从小到大的顺序输出它的所有质数的因子,以空格隔开。最后一个数后面也要有空格。
示例1
输入
180
输出
2 2 3 3 5
解法1
从i=2开始对该整数l_input进行整除,如果i已经不能整除该数l_input,说明该数l_input的因数中已经不包含任何能整除i的因数。
i++;
直到l_input==1||i>l_input,说明已经获取所有质因子(它本身也算自身的质因子)。
下面的代码会导致超时,需要优化。
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
//获取输入
long l1 = sc.nextLong();
//取质因子
for(long i=2;i<=l1;i++){
while(l1%i==0){
System.out.print(i+" ");
l1/=i;
}
}
}
}
解法2
由于因数总是成对出现的,从2开始取质因子的循环仅需要将i增长到i>sqrt(l_input)即可停止。
最后再判断l_input是否为1,假如为1,说明最后一个因数不是质数,l_input已经没有更多的质因子;假如不为1,说明最后一个因数是一个质数,l_input还有一个质因数,即是该质数。
取质因子的循环到i>sqrt(l_input)就停止,可以使算法的时间复杂度降低很多。
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
//获取输入
long l1 = sc.nextLong();
//获取输入的开方项
long k = (long)Math.sqrt(l1);
//取质因子
for(long i=2;i<=k;i++){
while(l1%i==0){
System.out.print(i+" ");
l1/=i;
}
}
System.out.println(l1 == 1 ? "": l1+" ");
}
}
HJ7 质数因子
题目
题目描述
写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于5,向上取整;小于5,则向下取整。
输入描述:
输入一个正浮点数值
输出描述:
输出该数值的近似整数值
示例1
输入
5.5
输出
6
解法1
取小数部分做大小判断,大于0.5就输出整数部分+1,小于0.5就直接输出整数部分。
import java.util.Scanner;
public class Main {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
//取得输入的数值
float num = sc.nextFloat();
//取输入数值的整数部分
int tmp = (int)num;
if(num-tmp>=0.5){
System.out.println((int)num+1);
return;
}
System.out.println((int)num);
}
}
}
HJ16 进制转换
题目
题目描述
王强今天很开心,公司发给N元的年终奖。王强决定把年终奖用于购物,他把想买的物品分为两类:主件与附件,附件是从属于某个主件的,下表就是一些主件与附件的例子:
主件 附件
电脑 打印机,扫描仪
书柜 图书
书桌 台灯,文具
工作椅 无
如果要买归类为附件的物品,必须先买该附件所属的主件。每个主件可以有 0 个、 1 个或 2 个附件。附件不再有从属于自己的附件。王强想买的东西很多,为了不超出预算,他把每件物品规定了一个重要度,分为 5 等:用整数 1 ~ 5 表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是 10 元的整数倍)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。
设第 j 件物品的价格为 v[j] ,重要度为 w[j] ,共选中了 k 件物品,编号依次为 j 1 , j 2 ,……, j k ,则所求的总和为:
v[j 1 ]*w[j 1 ]+v[j 2 ]*w[j 2 ]+ … +v[j k ]*w[j k ] 。(其中 * 为乘号)
请你帮助王强设计一个满足要求的购物单。
输入描述:
输入的第 1 行,为两个正整数,用一个空格隔开:N m
(其中 N ( <32000 )表示总钱数, m ( <60 )为希望购买物品的个数。)
从第 2 行到第 m+1 行,第 j 行给出了编号为 j-1 的物品的基本数据,每行有 3 个非负整数 v p q
(其中 v 表示该物品的价格( v<10000 ), p 表示该物品的重要度( 1 ~ 5 ), q 表示该物品是主件还是附件。如果 q=0 ,表示该物品为主件,如果 q>0 ,表示该物品为附件, q 是所属主件的编号)
输出描述:
输出文件只有一个正整数,为不超过总钱数的物品的价格与重要度乘积的总和的最大值( <200000 )。
示例1
输入
1000 5
800 2 0
400 5 1
300 5 1
400 3 0
500 2 0
输出
2200
解法1
动态规划,分组进行动态规划,分组动态规划。
参考资料:
https://blog.csdn.net/qq_44682003/article/details/109898435
https://blog.nowcoder.net/n/e724901d260f4afca0c5c37944c1c5be?f=comment
import java.util.Scanner;
public class Main {
//物品类
public static class good{
public int v; //物品的价格
public int p; //物品的重要度
public int q; //物品的主件ID
public int a1=0; //附件1ID
public int a2=0; //附件2ID
public good(int v, int p, int q) {
this.v = v;
this.p = p;
this.q = q;
}
public void setA1(int a1) {
this.a1 = a1;
}
public void setA2(int a2) {
this.a2 = a2;
}
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int money = sc.nextInt();//奖金
int n = sc.nextInt();//物品个数
if(n<=0||money<=0) System.out.println(0);
//定义物品数组
good[] Gs = new good[n+1];
//取得每个物品的情况
for (int i = 1; i <= n; i++) {
int v = sc.nextInt();
int p = sc.nextInt();
int q = sc.nextInt();
Gs[i] = new good(v,p,q);
//如果有主件,需要给对应主件标识该附件
if(q>0){
if(Gs[q].a1==0){
Gs[q].setA1(i);
}else {
Gs[q].setA2(i);
}
}
}
//动态规划数组,dp[i][j]表示有j元时想买i件物品
int[][] dp = new int[n+1][money+1];
for (int i = 1; i <= n; i++) {
int v=0,v1=0,v2=0,v3=0,tempdp=0,tempdp1=0,tempdp2=0,tempdp3=0;
v = Gs[i].v;
tempdp = Gs[i].p*v; //只有主件
if(Gs[i].a1!=0){//主件加附件1
v1 = Gs[Gs[i].a1].v+v;
tempdp1 = tempdp + Gs[Gs[i].a1].v*Gs[Gs[i].a1].p;
}
if(Gs[i].a2!=0){//主件加附件2
v2 = Gs[Gs[i].a2].v+v;
tempdp2 = tempdp + Gs[Gs[i].a2].v*Gs[Gs[i].a2].p;
}
if(Gs[i].a1!=0&&Gs[i].a2!=0){//主件加附件1和附件2
v3 = Gs[Gs[i].a1].v+Gs[Gs[i].a2].v+v;
tempdp3 = tempdp + Gs[Gs[i].a1].v*Gs[Gs[i].a1].p + Gs[Gs[i].a2].v*Gs[Gs[i].a2].p;
}
for(int j=1; j<=money; j++){
if(Gs[i].q > 0) { //当物品i是附件时,相当于跳过
dp[i][j] = dp[i-1][j];
} else {
dp[i][j] = dp[i-1][j];
if(j>=v&&v!=0) dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v]+tempdp);
if(j>=v1&&v1!=0) dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v1]+tempdp1);
if(j>=v2&&v2!=0) dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v2]+tempdp2);
if(j>=v3&&v3!=0) dp[i][j] = Math.max(dp[i][j],dp[i-1][j-v3]+tempdp3);
}
}
}
System.out.println(dp[n][money]);
}
}
HJ18 识别有效的IP地址和掩码并进行分类统计
题目
题目描述
请解析IP地址和对应的掩码,进行分类识别。要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类。
所有的IP地址划分为 A,B,C,D,E五类
A类地址1.0.0.0~126.255.255.255;
B类地址128.0.0.0~191.255.255.255;
C类地址192.0.0.0~223.255.255.255;
D类地址224.0.0.0~239.255.255.255;
E类地址240.0.0.0~255.255.255.255
私网IP范围是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255
子网掩码为二进制下前面是连续的1,然后全是0。(例如:255.255.255.32就是一个非法的掩码)
注意二进制下全是1或者全是0均为非法
注意:
- 类似于【0...】和【127...】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时可以忽略
- 私有IP地址和A,B,C,D,E类地址是不冲突的
输入描述:
多行字符串。每行一个IP地址和掩码,用~隔开。
输出描述:
统计A、B、C、D、E、错误IP地址或错误掩码、私有IP的个数,之间以空格隔开。
示例1
输入
10.70.44.68~255.254.255.0
1.0.0.1~255.0.0.0
192.168.0.2~255.255.255.0
19…0.~255.255.255.0
输出
1 0 1 0 0 2 1
解法1
思路:
1 读入一行,以~分割,分割成IP地址和子网掩码;若没有输入可读入,去到第5步。
2 首先判断IP地址格式是否合法,如果不合法,也要计数(与题意冲突),直接跳到第1步;如果合法,跳到第3步。
3 判断子网掩码是否合法,可以通过与运算逐位判断该位是否与上一位不同,若变化次数超过1,则合法,若不合法,计数,跳到第1步;若子网掩码合法,判断IP地址是否合法,若不合法,计数,跳到第1步;否则跳到第4步。
4 判断IP地址是否在几类地址的范围内,计数。回到第1步。
5 输出结果。
笔记:
1 ip用“.”分割,有个小坑,“.”是split的一个关键字,必须转译一下才可以使用。split("\.")
2 关于不计入计数的IP地址:存在空段,即【192…1.0】这种
3 关于正确IP地址:0.0.0.0-0.255.255.255 和 127.0.0.0-127.255.255.255为合法ip但不属于A~E类任一类
4 关于错误IP地址:有数字不在0~255的范围内
参考资料:
https://my.oschina.net/u/2822116/blog/817672
https://blog.nowcoder.net/n/ebd233f92fc840a19b8bdea8dd178d25?f=comment
https://blog.nowcoder.net/n/9366c0749e444abf8361cd4d0daaafda?f=comment
含错代码:
//通过50%,子网掩码255.252.0.0误判为错
import java.util.Scanner;
public class Main {
public static void main(String[] args){
int[] res = new int[7];//储存结果集
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
boolean isTrue = true;//用于标记该行IP或掩码是否错误
String[] sArr = sc.nextLine().split("~");
//首先判断IP地址格式是否有误,有误就可以结束本轮了
String[] sIPArr = sArr[0].split("\\.");
//判断IP地址格式是否错误,若格式错误,跳过本轮
if(sIPArr.length<4){
res[5]++;//IP地址错误,错误数+1
continue;//若IP地址数字小于4个,直接结束,不计入计数
}
//判断子网掩码是否合法
String[] sMaskArr = sArr[1].split("\\.");
int[] intMask = new int[4];
for(int i=3;i>=0;i--){//逐个取得子网掩码数字
intMask[i] = Integer.parseInt(sMaskArr[i]);
}
int numChangeTimes = 0;//记录子网掩码位数变化情况,若大于2或小于1,则有误
int last = 0;
for(int i=0;i<4;i++){//逐个数字逐个位数判断子网掩码是否有误
int j = intMask[i];
for(int k=0;k<8;k++){
int now = j&1;
j>>=1;
if(now!=last){
numChangeTimes++;
}
last = now;
}
}
//System.out.println(numChangeTimes);
if(numChangeTimes!=2){
res[5]++;//子网掩码错误,错误数+1
isTrue = false;
}
if(isTrue==false){continue;}
//判断IP地址是否合法
int[] intIP = new int[4];
for(int i=3;i>=0;i--){//逐个取得IP地址数字
intIP[i] = Integer.parseInt(sIPArr[i]);
}
for(int i=3;i>=0;i--){//逐个数字判断IP地址是否有误
if(intIP[i]>255||intIP[i]<0){
res[5]++;//IP地址错误,错误数+1
isTrue = false;
continue;//无需再判断IP地址类型,掩码是否错误
}
}
if(isTrue==false){continue;}
//判断IP地址属于哪一类
if(intIP[0]<127&&intIP[0]>0){
res[0]++;//A类地址计数+1
if(intIP[0]==10){
res[6]++;//私有IP计数+1
}
}else if(intIP[0]<=191&&intIP[0]>=128){
res[1]++;//B类地址计数+1
if(intIP[0]==172&&intIP[1]<32&&intIP[1]>15){
res[6]++;//私有IP计数+1
}
}else if(intIP[0]<224&&intIP[0]>191){
res[2]++;//C类地址计数+1
if(intIP[0]==192&&intIP[1]==168){
res[6]++;//私有IP计数+1
}
}else if(intIP[0]<240&&intIP[0]>223){
res[3]++;//D类地址计数+1
}else if(intIP[0]<256&&intIP[0]>239){
res[4]++;//E类地址计数+1
}
//for(int i=0;i<7;i++){
// System.out.print(res[i]+" ");//测试一把
//}
//System.out.println();
}
for(int i=0;i<7;i++){
System.out.print(res[i]+" ");//测试一把
}
}
}
更正代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args){
int[] res = new int[7];//储存结果集
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
boolean isTrue = true;//用于标记该行IP或掩码是否错误
String[] sArr = sc.nextLine().split("~");
//首先判断IP地址格式是否有误,有误就可以结束本轮了
String[] sIPArr = sArr[0].split("\\.");
//判断IP地址格式是否错误,若格式错误,跳过本轮
if(sIPArr.length<4){
res[5]++;//IP地址错误,错误数+1
continue;//若IP地址数字小于4个,直接结束,不计入计数
}
//判断子网掩码是否合法
String[] sMaskArr = sArr[1].split("\\.");
int[] intMask = new int[4];
for(int i=3;i>=0;i--){//逐个取得子网掩码数字
intMask[i] = Integer.parseInt(sMaskArr[i]);
}
int numChangeTimes = 0;//记录子网掩码位数变化情况,若大于2或小于1,则有误
int last = 1;
if((intMask[3]&1)==1){//末尾位为1,直接pass
res[5]++;//子网掩码错误,错误数+1
continue;
}
//逐个数字逐个位数判断子网掩码是否有误
for(int i=3;i>=0;i--){
int j = intMask[i];
for(int k=0;k<8;k++){
int now = j&1;
j>>=1;
if(now!=last){
numChangeTimes++;
}
last = now;
}
}
//System.out.println(numChangeTimes);
if(numChangeTimes!=2){
res[5]++;//子网掩码错误,错误数+1
isTrue = false;
}
if(isTrue==false){continue;}
//判断IP地址是否合法
int[] intIP = new int[4];
for(int i=3;i>=0;i--){//逐个取得IP地址数字
intIP[i] = Integer.parseInt(sIPArr[i]);
}
for(int i=3;i>=0;i--){//逐个数字判断IP地址是否有误
if(intIP[i]>255||intIP[i]<0){
res[5]++;//IP地址错误,错误数+1
isTrue = false;
continue;//无需再判断IP地址类型,掩码是否错误
}
}
if(isTrue==false){continue;}
//判断IP地址属于哪一类
if(intIP[0]<127&&intIP[0]>0){
res[0]++;//A类地址计数+1
if(intIP[0]==10){
res[6]++;//私有IP计数+1
}
}else if(intIP[0]<=191&&intIP[0]>=128){
res[1]++;//B类地址计数+1
if(intIP[0]==172&&intIP[1]<32&&intIP[1]>15){
res[6]++;//私有IP计数+1
}
}else if(intIP[0]<224&&intIP[0]>191){
res[2]++;//C类地址计数+1
if(intIP[0]==192&&intIP[1]==168){
res[6]++;//私有IP计数+1
}
}else if(intIP[0]<240&&intIP[0]>223){
res[3]++;//D类地址计数+1
}else if(intIP[0]<256&&intIP[0]>239){
res[4]++;//E类地址计数+1
}
//for(int i=0;i<7;i++){
// System.out.print(res[i]+" ");//测试一把
//}
//System.out.println();
}
//for(int i=0;i<7;i++){
// System.out.print(res[i]+" ");//测试一把,提示与输出格式不一致,需要去掉末尾空格
//}
//测试一把
for(int i=0;i<6;i++){
System.out.print(res[i]+" ");
}
System.out.print(res[6]);
}
}