JZ11 二進制中1的個數
(中等)
題目
描述
輸入一個整數,輸出該數32位二進制表示中1的個數。其中負數用補碼表示。
示例
輸入:
10
傳回值:
2
解題過程
1 純正數版——方法一
此題我首先是按純正數的情況來進行考慮的,但因為負數涉及補碼,是以這種方式很對負數是行不通的,但是我還是想練習一下針對這種問題的編碼能力,而且如果隻是純正數(當然,0 的情況特殊可考慮,可不考慮),也可以單獨出一道題,也有研究的價值。
對一個十進制正數轉為二進制的形式,簡單來說就是拆成了多個 2^n 的組合(當然,需是先從高位算起的個數最少的組合),在二進制的相應位中用 有效數1 進行标記,是以,我們可以找出數 n 的最高二進制,同時讓 n 減去這個數得到新的 n,再對新的 n 進行重複操作,過程中記錄下 n 執行減法的次數即可得知 n 的二進制形式中有幾個 1 。
【實作】
public class Solution {
public int NumberOf1(int n) {
int num = 0; // 二進制形式中 1 的個數
while (n > 0) {
int i = 2;
while (i < n) {
i *= 2;
}
if (i != 2 && i != n) { //當 while 循環體執行過,并且 i 多乘了一次 2 時
i /= 2;
}
n -= i;
num++;
}
return num;
}
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println("solution.NumberOf1(10) = " + solution.NumberOf1(10));
System.out.println("solution.NumberOf1(8) = " + solution.NumberOf1(8));
System.out.println("solution.NumberOf1(3) = " + solution.NumberOf1(3));
System.out.println("solution.NumberOf1(1) = " + solution.NumberOf1(1));
}
}
2 純正數版——方法二
或是用另一種更簡潔的方式實作,參數 n 對 2 求餘,如果沒有餘數,則可能是正好的 2 的整數倍,也可能不是,是以隻要 n 不等于 0 ,再對 n 進行除以 2 ,在這其中如果出現餘數為 1 的情況,則說明目前的 n 值,用 2 進制表示時,1 的數量肯定是多餘 1 個的,是以要計數上這種情況的一次,并且,之後 n 因為是整除 2 ,是以最後肯定還會出現 1 次求餘為 1 的情況,這也正是目前 n 值(當然不是說初始的 n 值)對應的目前最高位的二進制 1,是以,用這種方法,最終也可以求出正數情況時的二進制中 1 的個數。
【實作】
public class Solution {
public int NumberOf1(int n) {
int ans = 0;
while (n != 0) {
int tmp = n % 2;
if (tmp == 1) ++ans;
n /= 2;
}
return ans;
}
}
3 此題正式版——二進制位移法
直接将整數看成二進制,然後采用與運算、移位的方法。
首先,我們先寫一下正數情況下的實作:
【實作】
public class Solution {
public int NumberOf1(int n) {
int ans = 0;
while (n != 0) {
if ((n & 1) == 1) ans++;
n >>= 1;
}
return ans;
}
}
由于正數情況,右移 1 位,左位是補 0 ,是以,可以終止 while 循環,最終得出正确答案,但是如果我們想處理負數的情況,即左位補 1 ,在上述代碼中就解決不了,而且 while 就終止不了,況且一直左移隻會讓 1 的個數越來越多。
是以,我們換種方式,我們用 1 作為移動方,使用初始的 1 不斷左移,并與參數 n 進行與運算,這樣最終這個初始的 1 是可以将 1 移出左邊界,進而變成 0 ,并且也已經将參數 n 中的 1 全部找出,是以,是可行的,代碼如下:
【實作】
public class Solution {
public int NumberOf1(int n) {
int ans = 0;
int flag = 1;
while (flag != 0) {
if ((n & flag) != 0) ans++;
flag <<= 1;
}
return ans;
}
}
這個算法可以解決此題,但是需要運作32次(int 型為 4 個位元組,是以在記憶體中占 32 位,并且是将 1 從右向左移出)。
4 此題正式版——技巧法
十分巧妙且高效,題解也解釋的十厘清楚,我不再過多贅述,隻能說發明這個算法的人太強了,并且是十分善于觀察和探索的人才能想出來,當然我們也不能排除是偶然的靈感迸發。
JZ12 數值的整數次方
(中等)
題目
描述
給定一個double類型的浮點數base和int類型的整數exponent。求base的exponent次方。
保證base和exponent不同時為0。不得使用庫函數,同時不需要考慮大數問題,也不用考慮小數點後面0的位數。
示例1
輸入:
2.00000,3
傳回值:
8.00000
示例2
輸入:
2.10000,3
傳回值:
9.26100
示例3
輸入:
2.00000,-2
傳回值:
0.25000
說明:
2的-2次方等于1/4=0.25
思路
此題根據指數的情況來劃分即可。
當指數為 0 時,若底數也為 0 ,因 0 的 0 次幂無意義,是以此情況應提示錯誤資訊;
當指數為正數時,将指數個底數相乘傳回結果即可;
當指數為負數時,應将底數轉為其倒數,并且,若在循環計算時借助指數與目前下标大小作為循環終止條件,則指數應提前轉為其相反數。
實作
public class JZ12數值的整數次方 {
public double Power(double base, int exponent) {
if (exponent == 0) {
if (base == 0) {
try {
throw new Exception("0的0次方無意義");
} catch (Exception e) {
e.printStackTrace();
}
}
return 1;
} else if (exponent > 0) { //指數為正數
if (base == 0) {
return 0;
}
} else if (exponent < 0) { //指數為負數
if (base == 0) {
try {
throw new Exception("當指數為負數,底數為0時無意義");
} catch (Exception e) {
e.printStackTrace();
}
}
base = 1 / base;
exponent = -exponent;
}
double result = 1;
for (int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}
public static void main(String[] args) {
JZ12數值的整數次方 s = new JZ12數值的整數次方();
System.out.println("s.Power(2.00000, 3) = " + s.Power(2.00000, 3));
System.out.println("s.Power(2.00000, 0) = " + s.Power(2.00000, 0));
System.out.println("s.Power(2.00000, -2) = " + s.Power(2.00000, -2));
}
}