人生不易,生活无趣。一起来找点乐子吧。
特殊回文数:
问题描述
123321是一个非常特殊的数,它从左边读和从右边读是一样的。
输入一个正整数n, 编程求所有这样的五位和六位十进制数,满足各位数字之和等于n 。
输入格式
输入一行,包含一个正整数n。
输出格式
按从小到大的顺序输出满足条件的整数,每个整数占一行。
样例输入
52
样例输出
899998
989989
998899
数据规模和约定
1<=n<=54。
相比较上题的回文数,多了一个“各位数字之和为n”的条件,也就是多了一层判断。还是我们上次提到的那个问题,怎样把数字的各个位取出来。
上次提了一下,将数字当成字符串,一个个取出来,转换成数值类型计算,这样就不需要去考虑数学运算来一个个取出各位数了。
首先判断回文数,用我们上次的那个方法,依旧当成字符串,倒置后判断是否与原串相等。内层判断则判断各位数字和是否为n,这里说一个新的方法,String.toCharArray(),看方法名字也知道是干什么的了吧。返回的是char数组,如果学过python其实就是返回list(string)。我们要做的就是遍历这个数组,每个数取出来转成数值类型求和就可以了。
示例代码:
import java.util.*;
public class Main {
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
sc.close();
String s;
for(int i = 10000;i<1000000;i++){
s = ""+i;
if(new StringBuilder(s).reverse().toString().equals(s)){
int sum = 0;
char c[] = s.toCharArray();
for (int j = 0;j<c.length;j++){
sum += Integer.parseInt(String.valueOf(c[j]));
}
if(sum == n){
System.out.println(i);
}
}
}
}
}
十进制转十六进制:
问题描述
十六进制数是在程序设计时经常要使用到的一种整数的表示方式。它有0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F共16个符号,分别表示十进制数的0至15。十六进制的计数方法是满16进1,所以十进制数16在十六进制中是10,而十进制的17在十六进制中是11,以此类推,十进制的30在十六进制中是1E。
给出一个非负整数,将它表示成十六进制的形式。
输入格式
输入包含一个非负整数a,表示要转换的数。0<=a<=2147483647
输出格式
输出这个整数的16进制表示
样例输入
30
样例输出
1E
这个东西其实超简单,不用去自己编写逻辑处理,Integer.toHexString(int)方法直接使用,将int参数转为十六进制字符串,有一点需要注意,字母的大小写。
比如样例输入30,方法输出是1e,所以注意将最后字符串结果字母变成大写即可。(这个也有方法啊亲。)
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int a = sc.nextInt();
sc.close();
System.out.println(Integer.toHexString(a).toUpperCase());
}
}
十六进制转十进制:
问题描述
从键盘输入一个不超过8位的正的十六进制数字符串,将它转换为正的十进制数后输出。
注:十六进制数中的10~15分别用大写的英文字母A、B、C、D、E、F表示。
样例输入
FFFF
样例输出
65535
这个东西......有方法,不用急,先介绍下它,Integer.parseInt(string, int)。参数string是需要表示的字符串,后面的int是表示基数。十进制的基数是十,十六进制基数是十六。仅此而已,程序结束了:
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
sc.close();
System.out.println(Integer.parseInt(s, 16));
}
}
执行完75分,恭喜你啊兄dei,什么原因!!!嗯......最开始的问题,数据规模超出了,你看一下结果,最后一个数据测试不正确,so那个Integer.parseInt(s,16)换成Long.parseLong(s,16),执行完,100分,perfect。
有点坑爹啊,所以良心建议,能用Long的时候不用Integer,ok?不然跟玩游戏一样怎么没的都不知道。
所以你现在回头看它想要训练你的关键字:
一个都没用到~~~
别急兄嘚,下面这个就有点烦了:
十六进制转八进制:
问题描述
给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
输入的第一行为一个正整数n (1<=n<=10)。
接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
输出格式
输出n行,每行为输入对应的八进制正整数。
【注意】
输入的十六进制数不会有前导0,比如012A。
输出的八进制数也不能有前导0。
样例输入
2
39
123ABC
样例输出
71
4435274
【提示】
先将十六进制数转换成某进制数,再由某进制数转换成八进制。
我要说的东西很多,不想看的直接滑到最下面看代码吧。
好像思维逻辑上并没有什么难度,前面两题我们做了十进制转其他进制,其他进制转十进制,那我们就以十进制做桥梁,转两次就可以达到目的。搞他:
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String arr[] = new String[n];
for(int i = 0;i<n;i++){
arr[i] = sc.next();
}
sc.close();
for(int i = 0;i<n;i++){
System.out.println(Long.toOctalString( Long.parseLong(arr[i],16) ) );
}
}
}
Nice,兄弟,优雅的一批:
但是错了,为啥?看题的数据范围
长度不超过10万!!!转换成十进制根本存不下来,必定有溢出损失。我们看转进制的方法.toXXXString(),也就是说除了十进制之外的其他进制都是String类型,而十进制的存储是数值类型,我们拿十进制作为中间桥梁,十六进制太大的时候,数值就会溢出损失,再去转换八进制时,结果就是错的。
在这里我们插入一个问题,String能存储多大的数据?我查了一下,说法不一,有的说没有限制,和计算机的内存有关。有的说1到2G。无论怎样,字符的存储我们不管了(因为够大)。
我们换种思路,既然不能一下全部把十六进制转换成十进制,那我们一点点的转
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String arr[] = new String[n];
for(int i = 0;i<n;i++){
arr[i] = sc.next();
}
sc.close();
for(int i = 0; i<arr.length;i++){
String s = change(arr[i]);
s = s.replaceFirst("^0+", "");
System.out.println(s);
}
}
public static String change(String s){
char[] arr = s.toCharArray();
String temp = "";
String last = "";
for(int i = 0;i<arr.length;i++){
temp += arr[i];
temp = Integer.toBinaryString(Integer.parseInt(temp, 16));
if(temp.length() ==1)
temp = "000"+temp;
else if(temp.length() == 2)
temp = "00"+temp;
else if(temp.length() == 3)
temp = "0"+temp;
last += temp;
temp = "";
}
int zero = last.length()%3;
int n = last.length()/3;
if (zero == 1){
last = "00"+last;
n += 1;
}else if(zero == 2){
last = "0"+last;
n += 1;
}
String bajinzhi = "";
for(int i = 0;i<n;i++){
temp =last.substring(i*3, i*3+3);
bajinzhi += Integer.toOctalString(Integer.parseInt(temp,2));
}
return bajinzhi;
}
}
我们写一个change方法用于将十六进制转成八进制,先是将十六进制串每个字符转成二进制,再将二进制串转为八进制。这里为什么我们不以十进制做桥梁了呢?将每个十六进制字符转成十进制串,再将十进制串转成八进制串?这是因为我们需要一个对应关系,在我们的学习中,我们知道十六进制,将每个字符按四位二进制展开链接起来,就是十六进制到二进制的转换,而二进制到八进制,即将三位二进制看成一组,转为一位八进制数。这个是众所周知的,但是如果我们以十进制当做桥梁,不存在这个关系,中间还有进位的情况,又会导致结果错误。
上面的方法大家想看就看,不想看就别看了,我说下思路,就是将十六进制转成二进制,再将二进制转成八进制。过程中16-2的转换是四位一组,2-8的是三位一组,中间要补上位数不足的零。在将十六进制转换为二进制完成后,记得算一下长度是不是3的倍数,如果不是记得补齐,不然三位一个转八进制时就会因为位数不足出错。最后输出的时候,记得将八进制前面的0去掉,现在这里说一下去零的方法
s.replaceFirst("^0+", "");是个正则表达式:
将第一个参数的内容替换成后面的内容。简单说一下,^匹配开头,+是指将+之前的单字符扩充1或多次,“^0+”也就是匹配开头的多个零,用“”替换,也就达到了去零的目的。
为什么说不想看就别看了呢。因为:
超时!因为人懒,里面的转换都是调的方法,没得办法,我只能去手动写转进制的方法:
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String arr[] = new String[n];
for(int i = 0;i<n;i++){
arr[i] = sc.next();
}
sc.close();
for(int i = 0; i<arr.length;i++){
String s = change(arr[i]);
s = s.replaceFirst("^0+", "");
System.out.println(s);
}
}
public static String change(String s){
String last = "";
for(int i=0;i<s.length();i++){
switch(s.charAt(i)){
case '0': last += "0000";break;
case '1': last += "0001";break;
case '2': last += "0010";break;
case '3': last += "0011";break;
case '4': last += "0100";break;
case '5': last += "0101";break;
case '6': last += "0110";break;
case '7': last += "0111";break;
case '8': last += "1000";break;
case '9': last += "1001";break;
case 'A': last += "1010";break;
case 'B': last += "1011";break;
case 'C': last += "1100";break;
case 'D': last += "1101";break;
case 'E': last += "1110";break;
case 'F': last += "1111";break;
}
}
if (last.length()/3 == 1)
last = "00"+last;
else if(last.length()/3 == 2)
last = "0"+last;
String bajinzhi = "";
String temp = "";
for(int i=0;i<last.length()/3;i++){
temp = last.substring(i*3, i*3+3);
switch(temp){
case "000": bajinzhi += "0";break;
case "001": bajinzhi += "1";break;
case "010": bajinzhi += "2";break;
case "011": bajinzhi += "3";break;
case "100": bajinzhi += "4";break;
case "101": bajinzhi += "5";break;
case "110": bajinzhi += "6";break;
case "111": bajinzhi += "7";break;
}
}
return bajinzhi;
}
}
肯定要枚举了,本来想着用一堆if来做判定,看到人家写的文章想起了switch方法。这篇文章在这:
https://blog.csdn.net/kevinbetterq/article/details/62886848
思维很简单吧,但是:
不能原谅!我都手写了,你还要我怎样要怎样,连判断我都用switch写的落落大方。
我想到了这里。
这里顺便简单谈一下语言对变量的存储吧。对于c和java这种,我们声明一个变量,就会留下一块地方来存储变量的值。
例如以上面为例,声明了last,我们就有了一块空间存数据,但是对于last的重新赋值,其实是对last那块空间内容的重写,每次赋值都是重写。
返回去我们说下python,你们知道python为什么声明变量的时候不用定义类型吗,那是因为python对于数据的存储机制和java,c等不同。比如python中n = 1这一语句,python是这样做的:
遇到了n,在内存里存储了个n,有了个1,在内存里存了个1,赋值n = 1,ok将n指向1(理解成指针也没什么关系)。后面我们又写了一条语句,n = ‘halo’。同样的:
在内存里存下字符串‘halo’,赋值n,就将n指向‘halo’,原来n指的那个1,后面就会被python的内部机制清理掉。这就是python的处理机制。不用重写,变量不用指明类型。
所以考虑到这里我在想是不是每次重写的时间长了?上面提到的那篇文章中用到了StringBuffer的apped方法。这里对字符串的添加或许快点,我去查了append方法内部实现:
https://blog.csdn.net/guidiannan/article/details/80267435
不太清楚他比我快的原因,但是......不服不行:
看最后代码吧:
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String arr[] = new String[n];
for(int i = 0;i<n;i++){
arr[i] = sc.next();
}
sc.close();
for(int i = 0; i<arr.length;i++){
String s = change(arr[i]);
System.out.println(s.replaceFirst("^0+", ""));
}
}
public static String change(String s){
StringBuffer s1=new StringBuffer("");
for(int i=0;i<s.length();i++) {
switch(s.charAt(i)) {
case '0':s1.append("0000");break;
case '1':s1.append("0001");break;
case '2':s1.append("0010");break;
case '3':s1.append("0011");break;
case '4':s1.append("0100");break;
case '5':s1.append("0101");break;
case '6':s1.append("0110");break;
case '7':s1.append("0111");break;
case '8':s1.append("1000");break;
case '9':s1.append("1001");break;
case 'A':s1.append("1010");break;
case 'B':s1.append("1011");break;
case 'C':s1.append("1100");break;
case 'D':s1.append("1101");break;
case 'E':s1.append("1110");break;
case 'F':s1.append("1111");break;
}
}
s = s1.toString();
if (s.length()%3 == 1)
s = "00"+s;
else if(s.length()%3 == 2)
s = "0"+s;
StringBuffer s2=new StringBuffer("");
for(int i=0;i<s.length();i+=3) {
String s3=s.substring(i, i+3);
switch (s3) {
case "000":s2.append('0');break;
case "001":s2.append('1');break;
case "010":s2.append('2');break;
case "011":s2.append('3');break;
case "100":s2.append('4');break;
case "101":s2.append('5');break;
case "110":s2.append('6');break;
case "111":s2.append('7');break;
}
}
return s2.toString();
}
}
得,到这算是全部问题都解决了,我还是觉得这种方法好蠢,有优雅的方法,希望不惜吝教,评论写下面喽!
最后一个:
序列排序:
问题描述
给定一个长度为n的数列,将这个数列按从小到大的顺序排列。1<=n<=200
输入格式
第一行为一个整数n。
第二行包含n个整数,为待排序的数,每个整数的绝对值小于10000。
输出格式
输出一行,按从小到大的顺序输出排序后的数列。
样例输入
5
8 3 6 4 9
样例输出
3 4 6 8 9
这种应该属于集合操作了吧,我们不要将我们的思维固定在数组上,这里有篇不错的文章:
https://blog.csdn.net/carson_ho/article/details/85043628(值得收藏!)
排序,这里我们尝试着用一个Arrays。Arrays.sort()方法可以对一个数组进行排序,注意这里是原地排序,什么意思。就是对那个数组在数组的存储空间上直接进行排序,那非原地呢?其实就是新生成一个排完序的数组,而对于原数组不进行变动。
示例代码:
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int arr[] = new int[n];
for(int i = 0;i<n;i++){
arr[i] = sc.nextInt();
}
sc.close();
Arrays.sort(arr);
for(int i = 0; i<n;i++){
System.out.printf(arr[i]+" ");
}
}
}
简单到想哭了是不。
排序的方法有很多,选择,插入,快排等等:
https://blog.csdn.net/huosanghuakai1995/article/details/75090370
也许你们有些人觉得这些程序不应该这样写,应该自己去实现,而不是去用写好的方法。嗯......怎么说呢,我觉得要在于你怎么看这个问题,算了,留给你们去评论好了。
就先写到这吧。这次的五道题算是完了,哦对了,要说一句,我不是VIP,后面的题都被封着。所以,后面我们就不说“基础练习”了,进入下一块“算法训练”。
java笔记:
1、字符串转字符数组:String.toCharArray()
2、十进制转其他进制串:Integer.toXXXXString(int)
3、其他进制串转十进制:Integer.parseInt(s,16)或Long.parseLong(s,16),参数说明s为进制串,第二个参数int类型,为进制的基数。
4、字符串转大写:String.toUpperCase()
5、s.replaceFirst("^0+", ""),运用正则表达式替换开头0
6、字符串链接,除了string + "123"之外,StringBuffer.append(string),也是个不错的方法,事实证明,比前面那个快。
7、排序,Arrays.sort(array)可对数组array进行原地排序