1. 程式人生 > >藍橋杯(java):特殊迴文數,十進位制轉十六進位制,十六進位制轉十進位制,十六進位制轉八進位制,數列排序

藍橋杯(java):特殊迴文數,十進位制轉十六進位制,十六進位制轉十進位制,十六進位制轉八進位制,數列排序

人生不易,生活無趣。一起來找點樂子吧。

 

 

特殊迴文數:

問題描述
  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方法,StringBuffer我們前面用到過,對字串的倒置.reserve()方法。這裡對字串的新增或許快點,我去查了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進行原地排序