1. 程式人生 > >藍橋杯:十六進位制轉八進位制的高效演算法

藍橋杯:十六進位制轉八進位制的高效演算法

總算是在提交了11次都錯誤之後,第12次過了。也是無語。現在的演算法,按照藍橋杯系統給的10個測試數,顯示耗時31ms,記憶體佔用3.589MB。

問題描述
  給定n個十六進位制正整數,輸出它們對應的八進位制數。


輸入格式
  輸入的第一行為一個正整數n (1<=n<=10)。
  接下來n行,每行一個由0~9、大寫字母A~F組成的字串,表示要轉換的十六進位制正整數,每個十六進位制數長度不超過100000。


輸出格式
  輸出n行,每行為輸入對應的八進位制正整數。


  【注意】
  輸入的十六進位制數不會有前導0,比如012A。
  輸出的八進位制數也不能有前導0。


樣例輸入
  2
  39
  123ABC


樣例輸出
  71
  4435274


  【提示】
  先將十六進位制數轉換成某進位制數,再由某進位制數轉換成八進位制。

一開始覺得不難,不過反覆寫程式碼都錯,我也是醉了。結果看了一下它的測試資料,說好的【每個十六進位制數長度不超過100000位】,還真是用盡了,最後兩個測試數真的就是100000位。幾次都沒對就看了一下錦囊:先轉成2進位制,再轉成8進位制。恩,確實,100000位的十六進位制數就算是long long都超了,只能是按照字串處理。那好,就先轉成2進位制,再轉8進位制,一開始我是這樣做的:


看到兩邊的雙引號了嗎?我是想告訴大家,我一開始的想法是:所有的過程都是以字串形式的。每個16進位制數(字串形式)轉成4位二進位制數(字串形式)。第二第三行在記憶體上是一樣的,只是在讀取的時候第二行是從右往左每4位是一起是一個16進位制數;而第三行在讀取得時候是從右往左每三位是一個8進位制數。第二行(在記憶體上也是第三行)也是每一位是一個字元儲存起來的字串。

結果很難處理,字串從後往前遍歷很難看,十六進位制數'0'~'9'和'A'~'F'(注意有單引號,都是字元),要用switch對映成“0000"~”1111“(注意有雙引號,是字串)。直接這樣實現的也不是沒有,正如我找到的這篇:http://www.tuicool.com/articles/22I3Ib

但是這樣的實現確實麻煩,關鍵是二進位制字串佔用記憶體很大,switch對映還要考慮補位,因為假設原來的十六進位制數時14位,那麼前12位是48位二進位制數,也就是16個8進位制數,但是剩下的兩個十六進位制數是8位二進位制數,要變成8進位制數要補一個二進位制位(在字串前面加個'0'),這種就是補位。

有沒有更好的實現方法呢?也是看圖,這是我現在的實現方法:


這幅圖簡明地表達了我的實現流程。相比起一個十六進位制數4位二進位制數,3位二進位制數是一位8進位制數;我決定選擇其最小公倍數12,就可以少考慮一些位數問題。例如我選擇2位十六進位制數一起處理,那麼就是8位二進位制數,這樣我在轉換了2個八進位制數之後就會多2個二進位制位,留給下次?那不是自尋煩惱嗎?!所以如圖第一行,我將字串從右往左一次取出三位,然後注意第二行標號A,型別是int了,可以將每一位用atoi求出對應的int數值,然後注意是乘16,因為這些都是16進位制數。因為3位十六進位制數,正好是12位二進位制數,正好是4位8進位制數,就沒有了多出一些二進位制位留下次的問題。而且一次處理3為十六進位制數之後,num就可以重用,就不需要將整個十六進位制數的二進位制數儲存下來了。

轉成int,也就是數值型別,怎麼轉8進位制呢?這時候就要想一下,整數在記憶體中是以二進位制方式存在的,也就是說int型別的資料本身就是二進位制數,那麼要進行與二進位制數相關的操作,當然是位運算了,所以有了第三行標號B的語句。這裡我每一次都是將num跟7進行位與,7正好是111B,將num的低3位取了出來,而高位的都因為與運算歸0了,然後就是怎麼把數字變回相應的字元,因為八進位制數是在'0'~'7'之間,而ASCII碼的數字是連續編號的,所以加'0'(實際上是加了'0'的ASCII碼),再轉成char型別就是對應的字元了。然後是第四行,num自己右移3位,也就是說將剛才用過的最低3位拋棄了,然後是次低的三位變成最低3為,再進行步驟B,顯然步驟B是執行4次,都說了多少遍3個十六進位制數是對應4個八進位制數。

處理完3位十六進位制數,再往前處理三位,直到處理完。而每三位處理,無論前面多出來1位十六進位制數還是2位十六進位制數,他們轉成int之後都是佔用4個位元組,佔用32位(32位二進位制數),而高位沒有的本來就是0,何必自己勞神費心去補呢?

要注意一點,由於是從右往左處理的,最後不能直接輸出資料,要把字串反過來,就有了這段程式碼:

for(;j>=0;j--)
{
	Oct[i] += tmpOct[j];
}

最後貼出成品的程式碼:

#include <iostream>
#include <string>
#include <math.h>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	int n=0;
	cin>> n;
		
	string* Hex = new string[n];
	string tmpOct;
	string* Oct = new string[n];
	
	for(int i=0;i<n;i++)
	{
		int CurBit = 0;
		cin>>Hex[i];
		
		tmpOct = "";
		Oct[i] = "";
		
		for(int j=Hex[i].size()-3;j>=0;j-=3)
		{
			int d = 0;
			for(int k=0;k<3;k++)
			{
				int t = j+k;
				// 16 To 10
				if(Hex[i][t]>='0' && Hex[i][t]<='9')
				{
					CurBit = Hex[i][t]-'0';
				}
				if(Hex[i][t]>='A' && Hex[i][t]<='F')
				{
					CurBit = Hex[i][t]-'A'+10;	
				}
				
				d = d * 16 + CurBit;
			}
			
			// 3bit hex to 4bit oct
			int base = 7; // 111B
			for(int k=0;k<4;k++)
			{
				tmpOct += (char)('0' + (d & base));
				d = d >> 3;
			}
			d = 0;
		} 
		
		// last less three
		int rest = Hex[i].size() % 3;
		if(rest != 0)
		{
			int d = 0;
			for(int k=0;k<rest;k++)
			{
				// 16 To 10
				if(Hex[i][k]>='0' && Hex[i][k]<='9')
				{
					CurBit = Hex[i][k]-'0';
				}
				if(Hex[i][k]>='A' && Hex[i][k]<='F')
				{
					CurBit = Hex[i][k]-'A'+10;	
				}
				
				d = d * 16 + CurBit;
			}
			
			int base = 7; // 111B
			int max = ceil(4.0 / 3.0 * rest);
			// 1bit hex = 4/3 bit oct
			for(int k=0;k<max;k++)
			{
				if(((k==max-1) && (d & base)!=0) || k<max-1)
					tmpOct += char('0' + (d & base));
				d = d >> 3;
			}
		}
		
		int j=tmpOct.size()-1;
		// turn order
		for(;j>=0;j--)
		{
			Oct[i] += tmpOct[j];
		}
	}
	
	for(int i=0;i<n;i++)
	{
		cout<<Oct[i]<<endl;
	}
	
	cin>>n;
	return 0;
}


相關推薦

藍橋高效演算法

總算是在提交了11次都錯誤之後,第12次過了。也是無語。現在的演算法,按照藍橋杯系統給的10個測試數,顯示耗時31ms,記憶體佔用3.589MB。 問題描述   給定n個十六進位制正整數,輸出它們對應的八進位制數。 輸入格式   輸入的第一行為一個正整數n (1<

藍橋 基礎練習

問題描述   給定n個十六進位制正整數,輸出它們對應的八進位制數。 輸入格式   輸入的第一行為一個正整數n (1<=n<=10)。   接下來n行,每行一個由0~9、大寫字母A~F組成的字串,表示要轉換的十六進位制正整數,每個十六進位制數長度不超過100000。 輸出格式   輸出n行,每行

藍橋(java)特殊迴文數,十進位制十進位制,,數列排序

人生不易,生活無趣。一起來找點樂子吧。     特殊迴文數: 問題描述   123321是一個非常特殊的數,它從左邊讀和從右邊讀是一樣的。   輸入一個正整數n, 程式設計求所有這樣的五位和六位十進位制數,滿足各位數字之和等於n 。 輸入格式   輸入一行,包

藍橋BASIC-12

問題描述: 給定n個十六進位制正整數,輸出它們對應的八進位制數。 輸入格式: 輸入的第一行為一個正整數n (1<=n<=10)。 接下來n行,每行一個由0~9、大寫字母A~F組成的字串,表示要轉換的十六進位制正整數,每個十六進位制數長度不超過100000。 輸出格式:

藍橋

問題描述  給定n個十六進位制正整數,輸出它們對應的八進位制數。輸入格式  輸入的第一行為一個正整數n (1<=n<=10)。  接下來n行,每行一個由0~9、大寫字母A~F組成的字串,表示要轉換的十六進位制正整數,每個十六進位制數長度不超過100000。輸出格式  輸出n行,每行為輸入對應的八進

藍橋 基礎練習

   基礎練習 十六進位制轉八進位制   時間限制:1.0s   記憶體限制:512.0MB        問題描述   給定n個十六進位制正整數,輸出它們對應的八進位制數。輸入格式

藍橋 基礎練習

 基礎練習 十六進位制轉八進位制   時間限制:1.0s   記憶體限制:512.0MB 問題描述   給定n個十六進位制正整數,輸出它們對應的八進位制數。輸入格式   輸入的第一行為一個正整數n (1<=n<=10)。   接下來n行,每行一個由0~

藍橋題解--BASIC-12

原題地址:十六進位制轉八進位制 問題描述 給定n個十六進位制正整數,輸出它們對應的八進位制數。 輸入格式 輸入的第一行為一個正整數n (1<=n<=10)。   接下來n行,每行一個由09、大寫字母AF組成的字串,表示要轉換的十六進位制正整數,每個十六進位制數長度

藍橋題解-十進位制-BASIC-11

原題地址:十六進位制轉十進位制 問題描述 從鍵盤輸入一個不超過8位的正的十六進位制數字符串,將它轉換為正的十進位制數後輸出。   注:十六進位制數中的10~15分別用大寫的英文字母A、B、C、D、E、F表示。 樣例輸入 FFFF 樣例輸出 655

2016藍橋假期任務之《

問題描述  給定n個十六進位制正整數,輸出它們對應的八進位制數。輸入格式  輸入的第一行為一個正整數n (1<=n<=10)。  接下來n行,每行一個由0~9、大寫字母A~F組成的字串,表示要轉換的十六進位制正整數,每個十六進位制數長度不超過100000。輸出格

藍橋 基礎練習 (5)超長字串處理

 基礎練習 十六進位制轉八進位制   時間限制:1.0s   記憶體限制:512.0MB 問題描述   給定n個十六進位制正整數,輸出它們對應的八進位制數。輸入格式   輸入的第一行為一個正整數n (1<=n<=10)。   接下來n行,每行一個由

藍橋-- 基礎練習 (大數操作)

  基礎練習 十六進位制轉八進位制   時間限制:1.0s   記憶體限制:512.0MB 問題描述   給定n個十六進位制正整數,輸出它們對應的八進位制數。 輸入格式   輸入的第一行為一個正整數n (1<=n<=10)。   接下來n

藍橋 練習 Java

第一次寫部落格,有不足之處還請大家多指正 import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = n

藍橋 基礎練習 BASIC-12

info div for 限制 class 輸入 字符 字母 res 基礎練習 十六進制轉八進制 時間限制:1.0s 內存限制:512.0MB 問題描述  給定n個十六進制正整數,輸出它們對應的八進制數。輸入格式  輸入的第一行為一個正整數n (1<=n

藍橋 基礎練習

spa tro rgs number 解決 ann ret else if ger import java.util.*;public class Main { public static void main(String[] args) { Scann

p1102

題目 描述 Description 輸入一個不超過100,000位的16進位制數,請轉換成8進位制數。 注:16進位制數中,字母0-9還對應表示數字0-9,字母"A"(大寫)表示10,"B"表示11,…"F"表示15. 比如:16進位制數A10B表示的10進位制數是:1016^

問題描述    給定n個十六進位制正整數,輸出它們對應的八進位制數。 輸入格式    輸入的第一行為一個正整數n (1<=n<=10)。    接下來n行,每行一個由0~9、大寫字母A~F組成的字串,表示要轉換的十六進位制正整數,每個十六進位制數長度不

的快捷方法——巧用格式化輸入輸出

    最近刷題的時候遇到一個基礎題,就是將16進位制數轉為8進位制數。咋一看極其簡單,用二進位制做中介即可,簡單規劃了一下就開始動手了。 問題描述  給定n個十六進位制正整數,輸出它們對應的八進位制數。輸入格式  輸入的第一行為一個正整數n (1<=n<=10)。  接下來n行,每行一個由0~

兩種方法

#include "stdafx.h" #include <iostream> #include <string> using namespace std; int main() {  int n=0;  cin >> n;  str

BASIC-12 基礎練習 (c++)兩種解法,轉換2或10

 基礎練習 十六進位制轉八進位制   時間限制:1.0s   記憶體限制:512.0MB        錦囊1 使用二進位制。 錦囊2 先把十六進位制轉成二進位制,每位十六進位制正好