#7 Reverse Integer [E]

Description

tags: Math
Given a 32-bit signed integer, reverse digits of an integer.

Example:

Input: 123 Output: 321
Input: -123 Output: -321
Input: 120 Output: 21

Note:
Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [−2^31, 2^31 − 1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

Solution

class Solution {
public:
    int reverse(int x) {
        int ret = 0;
        if (x == 0) return x;
        
        while (x != 0) {
            int digit = x % 10;
            int newResult = ret * 10 + digit;
            // 替身变量还原法,检查乘法溢出
            if ((newResult - digit) / 10 != ret)
                return 0;
            ret = newResult;
            // 方法结束
            x /= 10;
        }
        return ret;
    }
};

Analysis

需要处理三个点:

  1. 负数的情况
  2. 末尾的零
  3. 溢出检查(Overflow)
    1)不能使用 int整数*10 > Integer.MAX_VALUE 这样的if判断,因为乘法后已经溢出,判断已经没有意义了。
    2)使用已做操作的还原步骤检查溢出(从“数值内容”上检查)

前两种情况其实都可以被算法涵盖,无需单独讨论。最后一种情况需要重点关注。

  • Time Complexity: O(logx). There are roughly log 10(x) digits in x.
  • Space Complexity: O(1).

Knowledge

补码

计算机中数值采用补码表示。
使用补码,可以将符号位和其它位统一处理;同时,减法也可按加法来处理。另外,两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。
32-bits int型:首位符号位(0表示正数,1表示负数),其余位表示数值。

  1. 正数的补码和原码相同
  2. 负数的补码为原码的数值位取反加一。

-1
原码:1000 0000 0000 0001
取反:1111 1111 1111 1110
加1: 1111 1111 1111 1111(此即为补码)

int 的取值范围:-2^31 ~ (2^31-1)
INT_MIN是-2^31的原因是:规定了1000 0000 0000 0000 这个数表示-2^31(本来是-0),所以负数多出来一个。

C++中int最大值表示为INT_MAX,int最小值表示为INT_MIN

模除运算

取模运算(又称模除,求模,modulus,modulo),a mod n

C++中的取模运算

  1. 同号取模(同正或同负结果相同)
    5 % 2 = 1
    9 % 3 = 0
    (-5) % (-2) = 1
  2. 异号取模。
    被除数和除数有一个为负数:余数符号与被除数相同
    -5 % 2 = -1 (5 % 2 = 1,-5为负数,所以结果为-1)

取模与取余

取余,遵循尽可能让商向0靠近的原则
取模,遵循尽可能让商向负无穷靠近的原则

符号相同时,两者不会冲突。比如,7 / 3 = 2.3,产生了两个商2和3。7 = 3 * 2 + 17 = 3 * 3 + (-2)。取模和取余都选择2为商,因此,7 rem 3 = 17 mod 3 = 1
符号不同时,两者会产生冲突。比如,7 / (-3) = -2.3,产生了两个商-2和-3。7 = (-3) * (-2) + 17 = (-3) * (-3) + (-2)。因此,7 rem (-3) = 17 mod (-3) = (-2)

归纳为

对于整型数a,b来说,取余和取模的运算方法为:
1、求整数商:c = a / b;
2、取余和取模:r = a - c * b;
当a和b符号一致时,求模运算和求余运算所得的c的值一致,因此结果一致。
当符号不一致时,求模运算结果的符号和除数b一致,求余运算结果的符号和被除数a一致。

所以,C++中的%运算,其实是取余运算。

整型溢出

  1. 什么是整型溢出
    只有同号整型的相加有可能出现溢出(overflow)
    假设用k个字节表示一个整型变量, 那么这个变量可以表示的有符号整数的范围是-2^(8k-1) ~ 2^(8k-1) – 1两个正整数或者两个负整数相加就有可能超过这个整型变量所能表示的范围,向上超出>2^(8k-1) – 1我们称之为向上溢出,向下超出<-2^(8k-1), 我们称之为向下溢出。 注意这里两个整数符号相同是整型相加溢出(overflow)的必要条件,也就是说只有符号相同的两个整数相加才有可能产生溢出(overflow)问题。

1) unsigned无符号整型溢出
对于unsigned整型溢出,C的规范是有定义的——“溢出后的数会以2^(8*sizeof(type))作模运算”,也就是说,如果一个unsigned char(1字符,8 bits)溢出了,会把溢出的值与256求模。

unsigned char x = 0xff;
printf("x: %d", ++x);

上面的代码会输出:0 (因为0xff + 1是256,与2^8求模后就是0)
2)signed有符号整型溢出
对于signed整型的溢出,C的规范定义是“undefined behavior”,也就是说,编译器爱怎么实现就怎么实现。对于大多数编译器来说,算得啥就是啥。

char x = 0x7f;
printf("x: %d", ++x);

上面的代码会输出:-128,因为0x7f + 0x01得到0x80,也就是二进制的1000 0000,符号位为1,负数,后面为全0,就是负的最小数,即-128。signed 整型溢出有可能是负数也有可能是正数。

  1. 整型溢出的危害
    1)整型溢出导致死循环
    2)整形转型时的溢出
    3)内存分配
    4)缓冲区溢出导致安全问题
    5)size_t 的溢出

  2. 整型溢出的检查
    “在整型溢出之前,一定要做检查,不然,就太晚了”

int AddInt(int a, int b) {
    if (a > 0 && b > 0 && a > INT_MAX - b) throw overflow_exception;
    if (a < 0 && b < 0 && a < INT_MIN - b) throw overflow_exception;
    return (a + b);
}

// for multiplication
#include <limits.h>
int a = <something>;
int x = <something>;
if (a > INT_MAX / x) /* `a * x` would overflow */;
if ((a < INT_MIN / x)) /* `a * x` would underflow */;
// there may be need to check for -1 for two's complement machines
if ((a == -1) && (x == INT_MIN)) /* `a * x` can overflow */
if ((x == -1) && (a == INT_MIN)) /* `a * x` (or `a / x`) can overflow */

除了INT_MIN和-1特殊情况外,不可能超过INT_MIN或INT_MAX。

二分查找中的溢出
计算mid = (low + high) / 2有可能发生溢出。应为

int mid = low + (high - low) / 2;

Reference

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 第七题: reverse integer 题目概述:English:Reverse digits of an i...
    LeoSpring阅读 207评论 2 1
  • 进制基本概念 什么是进制?进制是一种计数的方式,数值的表示形式 常见的进制十进制、二进制、八进制、十六进制 进制书...
    极客江南阅读 1,992评论 0 11
  • 算法很简单 主要考虑的是题目溢出问题和100这类的解决方案。有点小忘负数的二进制表达方法 于是复习了一下反码补码 ...
    KedAyA阅读 121评论 0 0
  • 1.编译程序(1)gcc xx.c,他会默认生成一个a.out的可执行文件,在a.out所在目录,执行./a.o...
    萌面大叔2阅读 1,260评论 0 1
  • 32位整数反转int(十进制整数),注意保留符号。 划重点: 1. java中的int类型存储长度为32bit,即...
    夏臻Rock阅读 259评论 0 0