7.反轉整數
題目:
給定一個 32 位有符號整數,將整數中的數字進行反轉。
示例 1:
輸入: 123
輸出: 321
示例 2:
輸入: -123
輸出: -321
示例 3:
輸入: 120
輸出: 21
注意:
假設我們的環境只能存儲 32 位有符號整數,其數值範圍是 [−231, 231 − 1]。根據這個假設,如果反轉後的整數溢出,則返回 0。
代碼:
class Solution {
public:
int reverse(int x) {
int a, rev=0;
while(x){
a = x%10;
x = x/10;
if(rev>INT_MAX/10 || (rev==INT_MAX/10 && a>7)){
return 0;
}
if(rev<INT_MIN/10 || (rev==INT_MIN/10 && a<(-8))){
return 0;
}
rev = rev*10 + a;
}
//或者如下操作:
// while(x){
// a = x%10;
// x = x/10;
// int tmp = rev*10 + a;
// if(tmp/10 != rev){//若新改變後的tmp已經溢出,則tmp/10不會等於之前的rev
// return 0;
// }
// rev = tmp;
// }
return rev;
}
};
方法:彈出和推入數字 & 溢出前進行檢查
思路
我們可以一次構建反轉整數的一位數字。在這樣做的時候,我們可以預先檢查向原整數附加另一位數字是否會導致溢出。
算法
反轉整數的方法可以與反轉字符串進行類比。
我們想重複“彈出” xx 的最後一位數字,並將它“推入”到 rev 的後面。最後,rev 將與 xx 相反。
要在沒有輔助堆棧 / 數組的幫助下 “彈出” 和 “推入” 數字,我們可以使用數學方法。
//pop operation:
pop = x % 10;
x /= 10;
//push operation:
temp = rev * 10 + pop;
rev = temp;
但是,這種方法很危險,因爲當 temp=rev⋅10+pop 時會導致溢出。
幸運的是,事先檢查這個語句是否會導致溢出很容易。
爲了便於解釋,我們假設 \text{rev}rev 是正數。
- 如果 temp=rev⋅10+pop 導致溢出,那麼一定有 rev≥INT_MAX / 10。
- 如果 rev>INT_MAX / 10,那麼 temp=rev⋅10+pop 一定會溢出。
- 如果 rev==INT_MAX / 10,那麼只要 pop>7,temp=rev⋅10+pop 就會溢出。
當 rev 爲負時可以應用類似的邏輯。
複雜度分析
- 時間複雜度:O(log(x)),xx 中大約有log10(x) 位數字。
- 空間複雜度:O(1)。
備註:(知識點)
C中常量INT_MAX和INT_MIN分別表示最大、最小整數,定義在頭文件limits.h中。
1. INT_MAX,INT_MIN數值大小
因爲int佔4字節32位,根據二進制編碼的規則,INT_MAX = 2^31-1,INT_MIN= -2^31.C/C++中,所有超過該限值的數,都會出現溢出,出現warning,但是並不會出現error。如果想表示的整數超過了該限值,可以使用長整型long long 佔8字節64位。
2. 關於INT_MAX INT_MIN的運算
由於二進制編碼按原碼、補碼和反碼的規則進行運算,所有程序中對INT_MAX和INT_MIN的運算應當格外注意,在出現溢出的時候,不遵循數學規則。
INT_MAX + 1 = INT_MIN
INT_MIN - 1 = INT_MAX
abs(INT_MIN) = INT_MIN
比較有趣的是,INT_MAX + 1 < INT_MAX, INT_MIN - 1 > INT_MIN, abs(INT_MIN) < 0.