算法竞赛——进制换算你会了吗?

进制转换

网上查找了很多关于进制转换的博客,发现好多不同进制之间的转换代码实现过于复杂、冗余。而进制换算又是算法竞赛常常考到的基础知识点,清晰的代码实现是十分有必要的!今天我就针对常见的进制换算做一个详细、清晰的总结,希望对你的学习或者竞赛有些许帮助!

一、进制基本介绍

什么是进制?

就是进位制,是人们规定的一种进位方法。 对于任何一种进制–X进制,就表示某一位置上的数运算时是逢X进一位。
二进制就是逢二进一,八进制是逢八进一,十进制是逢十进一,十六进制是逢十六进一。

  • 二进制表示的数中只能由 0~1的数组成
  • 八进制表示的数中只能由 0~7的数组成
  • 十六进制表示的数中只能由 0~9 A~F的数(字符)组成

n进制如何数数?

十进制:0 1 2 3 4 5 6 7 8 9 10 11……..

二进制:0 1 10 11 100 101 110 111 1000 1001 ……

八进制: 0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20 21…….

十六进制: 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 …. 18 19 1A 1B 1C 1D…..

二、十进制与R进制之间的转换

十进制转R进制

十进制转成R进制的整数: 除R取余法,结果倒过来取

注:十进制转16进制时,如果除出来的余数为 10~15
10 ——> A
11 ——> B
12 ——> C
13 ——> D
14 ——> E
15 ——> F

R进制转10进制

R进制转成10进制的整数: 按权展开

算法竞赛——进制换算你会了吗?

0~15转成二进制口算技巧: 8421码

转为4位的二进制表示,4位的二进制数最多表示到15

8:2^3 4:2^2 2:2^1 1:2^0

算法竞赛——进制换算你会了吗?

(一)十进制与二进制之间的转换

1.十进制转二进制

思路:用短除法除2求余,将结果逆序存储字符串string(你用数组逆序存也可以(栈),string其实说白了也是有数组的功能)

【参考代码】

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL n, x;
char c;
string s; // 二进制结果

int main()
{
    cin >> n;
    while(n != 0)
    {
        x = n % 2;// 获取结果
        c = x + '0';// 将数字转成字符
        s = c + s; // 将结果逆序存入字符串
        n /= 2; // 继续短除
    }

    // 这里不能用 n == 0判断特殊情况,因为while介绍 n 最后肯定为0
    if(s == "") cout << 0;
    else cout << s;

    return 0;
}

2.二进制转十进制

题目描述
请将一个25位以内的2进制正整数转换为10进制!
输入
一个25位以内的二进制正整数
输出
该数对应的十进制
样例
输入

111111111111111111111111

输出

16777215

思路:

从最低位开始( size()-1),倒过来计算,按权展开。

字符转成整数: s[i] - '0'

准备变量 t,表示 2n次方, t = 1,每次循环一次 t = t * 2

【参考代码】

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL t = 1, r; // t 表示权重; r 记录二转十的结果
string s; // 存放二进制

int main()
{
    cin >> s;

    for(int i = s.size() - 1; i >= 0; i --)
    {
        r = r + (s[i] - '0') * t;
        t = t * 2;
    }
    cout << r;
    return 0;
}

(二)十进制与十六进制之间的转换

1. 十进制转十六进制

题目描述
请从键盘读入一个非负整数n( n是一个不超过18位的正整数),将n转换为16进制!
注意:16进制即逢16进1,每一位上可以是从小到大为0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F共16个大小不同的数,即逢16进1,其中用A,B,C,D,E,F这六个字母来分别表示10,11,12,13,14,15。
如:60的十六进制为3C。(字母请用大写)
输入
一个不超过18位的非负整数n
输出
该数的十六进制值
样例
输入

100000000000

输出

174876E800

思路:

短除法除16取余,结果逆序存储。逆序存储字符串时要注意:

当余数为:

​ 整数 0~9,转换为字符 '0'~'9'x + '0'

​ 整数 10~15,转换为字符 'A'~'F'x + 'A' - 10

注:
int 最多表达 2^31 – 1, 10位整数;
long long 最多表达 2^63 – 1, 19位整数
当数值超过int范围要开long long

【参考代码】

解法一:

分别判断 n%16的结果在 0~910~15的那个范围,分别转换为对应的字符!

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL n, x;
string s; // 存放二进制
char c;

int main()
{
    cin >> n;
    while(n != 0)
    {
        x = n % 16;
        //将x转为字符逆序存入字符串s
        // 如果余数小于10:'0'~'9'
        // 如果余数10~15:'A'~'F'

        if(x < 10) c = x + '0';
        else c = x + 'A' - 10;

        s = c + s; // 逆序存入字符串

        n /= 16;
    }
    if(s == "") cout << 0;
    else cout << s;

    return 0;
}

解法二:

把0~15的字符结果罗列出来,根据余数直接取到相应的字符: string t = "0123456789ABCDEF"; // 技巧!

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;

LL n, x;
string s; // 存放二进制
string t = "0123456789ABCDEF"; // 技巧!

int main()
{
    cin >> n;
    while(n != 0)
    {
        x = n % 16;

        //将x转为字符逆序存入字符串s
        s = t[x] + s; // 逆序存入字符串

        n /= 16;
    }
    if(s == "") cout << 0;
    else cout << s;

    return 0;
}

2. 十六进制转十进制

题目描述
请将一个不超过10位的十六进制正整数转换为十进制整数!
输入
10位以内的十六进制正整数
输出
该数对应的十进制整数
样例
输入复制

2ECF

输出

11983

思路:逆序计算,按权展开!从s中获取每一位字符s[i],要转换为实际的整数:

​ s[i]: '0'~'9' ——> s[i] - '0'

​ s[i]: 'A~'F'——> s[i] - 'A' + 10

【参考代码】

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL n, r, t = 1;
string s; // 存放二进制

int main()
{
    cin >> s;
    for(int i = s.size() - 1; i >= 0; i --)
    {
        // 如果s[i]是字符数字
        if(s[i] >= '0' && s[i]

三、二进制与八/十六进制的转换

我们知道二进制转为八/十六进制,可以先将二进制转为十进制,再用短除法求八/十六进制,但这样就比较麻烦,添加代码量!我们可以直接进行转换,就相当于一个模板!

原理:每位八进制数相当于 3&#x4F4D;二进制数(07),每位十六进制数相当于4位二进制数(015)。 在转换时,中间的0不能省略,开头不够时可以补零。

二进制转8/16进制:

算法竞赛——进制换算你会了吗?

8/16进制转二进制:

算法竞赛——进制换算你会了吗?

1.二进制转十六进制

题目描述
请将一个不超过 100位的二进制数转换为十六进制数!
输入
一个不超过100位的二进制整数
输出
该数对应的十六进制数!
样例
输入

11001001111011111000001000010011

输出

C9EF8213

思路:

算法竞赛——进制换算你会了吗?

第一步:判断字符串的长度是否为4的倍数,如果不是则补0。

s:字符数组

s.size() % 4 == 1,补3个0

s.size() % 4 == 2,补2个0

s.size() % 4 == 3,补1个0

第二步: 每四位2进制数转换成1位的16进制数(借助10进制在转)输出。

“1101”转换为对应的十进制整数 –> 13,注意判断转换的结果如果是 0~9,转换为 '0'~'9',如果转换的结果是 10~15,转换为 'A'~'F'

将四位的二进制转换为1位的16进制:

char num(string s)
{
    ...

}

【参考代码】

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;

// 将4位的二进制转成10进制整数 在对应变为16进制符号:0~9 -> '0'~'9'; 10~15 -> 'A'~'F'
char num(string s)
{
    LL r = 0, t = 1; // r = 0, t = 1;别忘了
    // 从最低位按权展开,转换为10进制
    // 10进制在转为16进制
    for(int i = s.size() - 1; i >= 0; i --)
    {
        r = r + (s[i] - '0') * t;
        t = t * 2;
    }

    //10进制转16进制: 0~9 -> '0'~'9'; 10~15 -> 'A'~'F'
    char c; // 存放结果
    if(r < 10) c = r + '0';
    else c = r + 'A' - 10;

    return c;
}

int main()
{
    string s, t; // 存放二进制
    cin >> s;

    // 看是否需要补零
    if(s.size() % 2 == 1) s = "000" + s;
    else if(s.size() % 2 == 2) s = "00" + s;
    else if(s.size() % 2 == 3) s = "0" + s;

    // 每每截取4位二进制数:substr(i, 4)截取字符串,i += 4
    for(int i = 0; i < s.size(); i += 4)
    {
        t = s.substr(i, 4);
        // 将4位二进制转换为16进制,输出
        cout << num(t);
    }

    return 0;
}

2.十六进制转二进制

思路:将每一位的16进制数,转换位4位的二进制数!

算法竞赛——进制换算你会了吗?

第一步:将每位的16进制转换为4位的2进制,连接到字符串上!

第二步:清除前导0,也就是要从第一个非0开始输出。注:当16进制为0000时,转成二进制后也为0,此时不能把0000全部清除掉,要保留一个0!

【参考代码】

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
// 技巧:
string t[16] = {"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"};

//求: 将每位16进制转为对应的4为二进制
//1. 将s[i]转换为0~15对应的整数,再求对应的4位2进制(技巧:通过数组下标获取对应二进制)
//2. 最终清除二进制字符串的前导0
int main()
{
    string s, r; // s存放16进制; r存放2进制
    cin >> s;

    for(int i = 0; i < s.size(); i ++)
    {
        //1. 将s[i]转换为0~15对应的整数
        int x;
        if(s[i] >= '0' && s[i]  1)
    {
        r.erase(0,1);
    }

    cout << r;

    return 0;
}

C++ STL中的:erase()函数的功能是用来删除容器中的元素
erase(first,last);——>左闭右开: [first,last)

3.二进制转八进制

题目描述
请将一个100位以内的二进制整数转换为8进制整数!
输入
100位以内的二进制整数
输出
该数对应的八进制整数
样例
输入

111100001111000011110000

输出

74170360

思路:同上述二进制转16进制

第一步:判断字符串的长度是否为3的倍数,如果不是则补0。

s:字符数组

s.size() % 3 == 1,补2个0

s.size() % 4 == 2,补1个0

第二步: 每三位2进制数转换成1位的8进制数(07)输出。(每3位的二进制数是:08,9的话是1001四位了!),即转成对应10进制即可

【参考代码】

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;

// 将3位的二进制(一定是0~7) 转成 10进制整数 对应的8进制必定也是:0 ~ 7
LL num(string s)
{

    LL t = 1, r = 0;
    // 从最低位按权展开,转换为10进制
    for(int i = s.size() - 1; i >= 0; i --)
    {
        r = r + (s[i] - '0') * t;
        t = t * 2;
    }

    return r;
}

int main()
{
    string s, t; // s存放二进制
    cin >> s;

    // 看是否需要补0
    if(s.size() % 3 == 1) s = "00" + s;
    else if(s.size() % 3 == 2) s = "0" + s;

    // 截取3位二进制,转为对应的八进制,输出
    for(int i = 0; i < s.size(); i += 3)
    {
        t = s.substr(i, 3);

        // 将每每3位二进制转为八进制并输出
        cout << num(t);
    }

    return 0;
}

4.八进制转二进制

题目描述
请将一个 100位以内的8进制整数转换为2进制整数!
输入
100位以内的8进制整数
输出
该数对应的2进制整数
样例
输入

12376532347173217361

输出

1010011111110101011010011100111001111011010001111011110001

思路:同16进制转二进制:将每一位的8进制数,转换为3位的二进制数!

第一步:将 每位8进制(0~7)转换为 3位的2进制,连接到字符串上!

第二步:清除前导0,也就是要从第一个非0开始输出。注:当8进制为000时,转成二进制后也为0,此时不能把000全部清除掉,要保留一个0!

【参考代码】

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;

// 存储0~7 八进制对应的 3位二进制
string t[8] = {"000","001","010","011","100","101","110","111"};

int main()
{
    string s, r; // s存放八进制,r存放二进制

    cin >> s;

    // 8进制 ——> 2 进制:将每一位8进制转换为3位的2进制(通过数字对应数组直接获取!)然后拼接
    for(int i = 0; i < s.size(); i ++)
    {
        int x = s[i] - '0'; // 找到每一位8进制所对应的2进制表示
        r += t[x]; // 拼接
    }

    // 清除前导0
    while(r[0] == '0' && r.size() > 1)
    {
        r.erase(0, 1);
    }

    cout << r;

    return 0;
}

进制转换应用例题:小丽找半个回文数

算法竞赛——进制换算你会了吗?

求这个数在十进制下不是回文数,但在2进制或者16进制下是回文数,则这个数是半个回文数!

思路:

朴素的想法,判断这个 十进制数是否是回文数,如果不是则将其转为2进制数和16进制数,再判断是否是回文数!

我们发现一个很相似的操作, 那就是这个数在d进制表示下,是否是回文数,我们知道10进制数转为其它进制使用的是 短除法!,我们不必用进制表示的最终结果来判断是否是回文,我们可以将每一位余数存到一个数组中,判断它的余数是否为回文即可!——因此,我们可以写个判断函数进行判断统一判断就可以啦!

【参考代码】

#include
#include
#include
#include

using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
LL n, x;
int a[N]; // 存储n转为d进制的每一位对应的余数,用来判断是否是回文数

// 将 十进制数 n 转换为 d进制数 并判断它是不是回文!
bool huiwen(int n, int d)
{
    int k = 0;
    while(n != 0)
    {
        x = n % d;
        a[k ++] = x; // 存储余数
        n /= d;
    }
    // 判断回文:对称位是否相等,出现不等则不是回文数
    for(int i = 0; i < k / 2; i ++)
    {
        //0 --> k - 1
        //1 --> k - 2
        //2 --> k - 3... i --> k - i - 1
        if(a[i] != a[k - i -1])
        {
            return false;
            break;
        }
    }

    return true;
}

int main()
{
    cin >> n;
    while(n --)
    {
        int x;
        cin >> x;
        if(huiwen(x, 10) == false && (huiwen(x, 2) == true || huiwen(x, 16) == true))
        {
            cout << x << endl;
        }
    }

    return 0;
}

四、总结

进制转换可以通过类比10进制计算机制来换算,清楚转换的原理公式即可。再8/16进制转2进制时,使用一个字符串数组记录对应的8/16每一位的3/4位二进制表示,转换时直接使用,加快效率!

注:如果文章有任何错误或不足,请各位大佬尽情指出,评论留言留下您宝贵的建议!如果这篇文章对你有些许帮助,希望可爱亲切的您点个赞推荐一手,非常感谢啦

算法竞赛——进制换算你会了吗?

Original: https://www.cnblogs.com/lwtyyds/p/15645176.html
Author: 时间最考验人
Title: 算法竞赛——进制换算你会了吗?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/584059/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 【题解】HDU5371 Hotaru’s proble

    Problem Description Hotaru Ichijou recently is addicated to math problems. Now she is play…

    数据结构和算法 2023年6月12日
    070
  • Python 中的异常 (Exception)

    以下 Python 版本为 Python 3.8.10 . 初探异常 错误: 语法错误 . 逻辑错误 . 异常:程序运行过程中,出现的意料之外的错误(大概类似 corner cas…

    数据结构和算法 2023年6月7日
    0111
  • 题解 AcWing 2236. 伊基的故事 I-道路重建

    先对原图跑一遍最大流,再依次增加每条边的容量后重新求最大流,如果增加某条边的容量后最大流变大了,说明它就是关键边。 这个智障东西的时间复杂度大概是 (O(n^2 m^2)) 的(如…

    数据结构和算法 2023年6月12日
    068
  • Goobye, cnblogs

    转 typecho 了,个人网站的客制化程度当然不是 cnblogs 能比得上的。 Original: https://www.cnblogs.com/orchid-any/p/1…

    数据结构和算法 2023年6月12日
    067
  • 雑用 2

    平面旋转。应该是比较好理解的版本。 我们对一个平面(逆时针)旋转 (\beta) 度,无非就是对每一个有意义的向量 (\boldsymbol a = (x, y)) 进行旋转。不妨…

    数据结构和算法 2023年6月12日
    082
  • 近五个月的流水账

    好好规划,离梦想更近些! 近五个月的流水账 自4个月以来,我努力了许多,也收获了许多。2021年12月之前,处于省人民币还人民币之路。冰箱啊,钢琴啊,各种电器啊,都是负债得到的,但…

    数据结构和算法 2023年6月12日
    095
  • spark调度原理描述

    spark调度的几个概念 集群 一个spark集群可以同时运行多个spark应用 应用 1、main方法、spark-shell、spark-submit能够运行的spark程序 …

    数据结构和算法 2023年6月7日
    078
  • 高级语言程序设计实验四

    高级语言程序设计实验四 A B C D E A 编程序,实现如下功能:(1)定义两个一维数组x,y,不超过50个元素。(2)从键盘输入k个整数到数组x中。(3)计算x中数据的平均值…

    数据结构和算法 2023年6月16日
    0126
  • 并查集 ( Disjoint-Set or Union-Find data structure )

    什么是并查集 1.将n个 不重复的元素 ( distinct elements ), 分配到几个 不相交集合 ( disjoint sets )的应用。 换句话说,一个不相交的集合…

    数据结构和算法 2023年6月7日
    088
  • CF1468F Full Turn 题解

    注意到只要两个人初始的朝向相反就可以看到对方,否则不行。直接把斜率搞成一个 pair 压到 map 里存个数就行了。 点击查看代码 #include #include #inclu…

    数据结构和算法 2023年6月12日
    082
  • 数论-模数是素数的同余式(拉格朗日定理)

    Th1:设p是素数,f(x)=an(xn)+an-1(x*n-1)+…+a1x+a0,n≥1,an≠0 (mod p) (f(x)∈Z[x]),则f(x)≡ 0 (mo…

    数据结构和算法 2023年6月7日
    079
  • 搭建 Redis 的主从

    在master和slave分别执⾏info命令,查看输出信息 进入主客户端 redis-cli -h 192.168.26.128 -p 6379 Original: https:…

    数据结构和算法 2023年6月7日
    090
  • CF 793 div2

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    数据结构和算法 2023年6月12日
    054
  • 费解的开关

    这种题较少见也较难想 按一个开关,会影响上下左右四个方向的数 先可以考虑,只有一排灯的情况 那么一排灯的情况,只有32种按法即(2^5)次,可以用(1~32)每个数的二进制数表示方…

    数据结构和算法 2023年6月7日
    079
  • 初识设计模式-适配器模式

    适配器在生活中经常见到,如手机、笔记本电脑的电源适配器,USB 转接头都是常见的适配器。 在设计模式当中,适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。 在类适配器模…

    数据结构和算法 2023年6月8日
    097
  • 算法: 整数中 1 出现的次数

    问题 输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。 例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。 解决 //1、…

    数据结构和算法 2023年6月12日
    090
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球