目錄
以下算法題均來自leetCode題庫 https://leetcode-cn.com/
本篇難度爲簡單
1.將數字變成 0 的操作次數
給你一個非負整數 num ,請你返回將它變成 0 所需要的步數。 如果當前數字是偶數,你需要把它除以 2 ;否則,減去 1 。
class Solution {
//正數變成0的步驟數 ,偶數除以2,奇數減去1
public int numberOfSteps (int number) {
if (number == 0) return 0;
return zeroNextValue(number, 0);
}
//二進制末尾是1的便是奇數
private int zeroNextValue(int number, int step) {
if (number == 0) return step;
if ((number & 1) != 0) {
step++;
return zeroNextValue(number - 1, step);
} else {
step++;
return zeroNextValue(number >> 1, step);
}
}
}
思路:二進制末尾爲1的是奇數,爲0的是偶數
2.二進制鏈表轉整數
給你一個單鏈表的引用結點 head。鏈表中每個結點的值不是 0 就是 1。已知此鏈表是一個整數數字的二進制表示形式。
請你返回該鏈表所表示數字的 十進制值 。
// Definition for singly-linked list.
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
class Solution {
public int getDecimalValue(ListNode head) {
int val = head.val;
while (head.next != null) {
head = head.next;
//左移一位相當於乘以2,下一位有1的直接或運算添加到二進制裏
val = head.val == 0 ? val << 1 : (val << 1) | 1;
}
return val;
}
}
思路:構造鏈表同結構的二進制表示數
3.二進制中1的個數
請實現一個函數,輸入一個整數,輸出該數二進制表示中 1 的個數。例如,把 9 表示成二進制是 1001,有 2 位是 1。因此,如果輸入 9,則該函數輸出 2。
public class Solution {
//我這按32位去計算二進制,應該沒問題吧
public int hammingWeight(int number) {
int count = 0;
for (int i = 0; i < 32; i++) {
if ((number & 1 << i ) != 0) count++;
}
return count;
}
}
思路:對整數的每個位置都進行是否是1的判斷
4.最大數值
編寫一個方法,找出兩個數字a和b中最大的那一個。不得使用if-else或其他比較運算符。
public class Solution {
public int maximum(int a, int b) {
//等於1是負數,即a<b;反之是a>b ,可能涉及兩個正負最大值相減,超過int的最大範圍
//取符號位進行判斷,long是64位,int是32位
int val = ((int)(((long)a - (long)b) >> 63)) & 1;
return a + (b - a) * val;
}
}
思路:取差值,根據符號位判斷大小值
5.數字的補數
給定一個正整數,輸出它的補數。補數是對該數的二進制表示取反。
public int findComplement(int num) {
int origin = num;
int val = 0;
//一直往右位移,直到0爲止,可以得出該數的二進制長度
//構建一個等長的全1的二進制,進行異或運算
while (num > 0) {
num = num >> 1;
val = val == 0 ? 1 : (val << 1) | 1;
}
return origin ^ val;
}
思路:查找整數的爲1的最高位,與同長度的全1二進制進行異或運算
6. 配對交換
配對交換。編寫程序,交換某個整數的奇數位和偶數位,儘量使用較少的指令(也就是說,位0與位1交換,位2與位3交換,以此類推)
//10101010101010101010101010101010 = 0xaaaaaaaa
//01010101010101010101010101010101 = 0x55555555
public int exchangeBits(int num) {
return (num << 1 & 0xaaaaaaaa) | (num >> 1& 0x55555555);
}
思路:左右分別位移一位,最後的結果疊加
7.根據數字二進制下 1 的數目排序
給你一個整數數組 arr 。請你將數組中的元素按照其二進制表示中數字 1 的數目升序排序。
如果存在多個數字二進制中 1 的數目相同,則必須將它們按照數值大小升序排列。
請你返回排序後的數組。
public int[] sortByBits(int[] arr) {
Integer integers[] = new Integer[arr.length];
for (int i = 0; i < arr.length; i++) {
integers[i] = new Integer(arr[i]);
}
Arrays.sort(integers, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
int bitCount1 = Integer.bitCount(o1);
int bitCount2 = Integer.bitCount(o2);
if (bitCount1 == bitCount2) {
return o1 - o2;
}
return bitCount1 - bitCount2;
}
});
int[] result = new int[integers.length];
for (int i = 0; i < integers.length; i++) {
result[i] = integers[i].intValue();
}
return result;
}
思路:使用比較器進行比較
Integer.bitCount() 方法返回的是二進制1的個數
8.只出現一次的數字
給定一個非空整數數組,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。
public int singleNumber(int[] nums) {
int result = 0;
for (int item : nums) {
result ^= item;
}
return result;
}
思路:異或運算和參與運算的兩個數位置無關;
任何數和0異或等於該數本身;
兩個相同數字異或運算等於0
9.找不同
給定兩個字符串 s 和 t,它們只包含小寫字母。
字符串 t 由字符串 s 隨機重排,然後在隨機位置添加一個字母。
請找出在 t 中被添加的字母。
public char findTheDifference(String s, String t) {
char res = 0 ;
char[] chars = s.toCharArray();
char[] chart = t.toCharArray();
for (char item : chart) {
res ^= item;
}
for (char item : chars) {
res ^= item;
}
return res;
}
思路:和題8的思路一樣,異或兩個相同的數等於0,最終剩下的就是多出來的
10.缺失的數字
給定一個包含 0, 1, 2, …, n 中 n 個數的序列,找出 0 … n 中沒有出現在序列中的那個數。
public int missingNumber(int[] nums) {
int result = 0;
for (int i = 0; i < nums.length; i++) {
result = result ^ nums[i] ^ i;
}
return result^nums.length;
}
思路:同上
11.交替位二進制數
給定一個正整數,檢查他是否爲交替位二進制數:換句話說,就是他的二進制數相鄰的兩個位數永不相等。
public boolean hasAlternatingBits(int n) {
int temp = n ^ (n >> 1);
return (temp & (temp + 1)) == 0;
}
思路:交替位合併如果是正確的會組成全1的二進制
12.顛倒二進制位
顛倒給定的 32 位無符號整數的二進制位。
public int reverseBits(int n) {
int result = 0;
for (int i = 0; i < 32; i++) {
int last = n & 1;
result = result << 1 | last;
n = n >>> 1;
}
return result;
}
思路:逆向位移輸出
13.兩整數之和
不使用運算符 + 和 - ,計算兩整數 a 、b 之和。
public int getSum(int a, int b) {
if (b == 0) return a;
int temp = (a & b) << 1; //算出所有需要進行進位+1的位置
int resultTemp = a ^ b;
return getSum(resultTemp, temp);
}
思路:算出進位的位置,循環遞歸至沒有進位爲止
14.整數轉換
整數轉換。編寫一個函數,確定需要改變幾個位才能將整數A轉成整數B。
public int convertInteger(int A, int B) {
int count = 0;
for (int i = 0; i < 32; i++) {
if (((1 & A) ^ (1 & B)) == 1) count++;
A = A >> 1;
B = B >> 1;
}
return count;
}
思路:遍歷比較每一個位置的差異
15.4的冪
給定一個整數 (32 位有符號整數),請編寫一個函數來判斷它是否是 4 的冪次方。
public boolean isPowerOfFour(int num) {
if (num == 1) return true;
if (num < 0 || (num & (num - 1)) != 0) return false;
return (num & 0x55555555) != 0;
}
思路:4的二進制是100,往前推10000,1000000也都是4的冪,就是除末尾外奇數位是1,且只有一位是1的二進制數都是4的冪,同時要算上4的0次冪1
4-1=3 = 011 , 16-1=15=01111,64-1=63=0111111
16.2的冪
給定一個整數,編寫一個函數來判斷它是否是 2 的冪次方。
public boolean isPowerOfTwo(int num) {
if (num <= 0 || (num & (num - 1)) != 0) return false;
return (num & 1) == 0 || num == 1;
}
思路:同上題,只是2的冪是除末尾外只有一位是1的二進制數
17.翻轉數位
給定一個32位整數 num,你可以將一個數位從0變爲1。請編寫一個程序,找出你能夠獲得的最長的一串1的長度。
public int reverseBits(int num) {
int preCount = 0;
int tempCount = 0;
int result = 0;
for (int i = 0; i < 32; i++) {
if ((num & 1<< i) != 0) {
preCount++;
} else {
result = Math.max(result, preCount + tempCount + 1);
tempCount = preCount;
preCount = 0;
}
}
return Math.max(result, preCount + tempCount + 1);
}
思路:
1.統計1的連續個數
2.遇到第一個不爲1的二進制位時,保存上次的值,並把之前的值清空;同時計算此時的最大長度
18.數字轉換爲十六進制數
給定一個整數,編寫一個算法將這個數轉換爲十六進制數。對於負整數,我們通常使用 補碼運算 方法。
注意:
1.十六進制中所有字母(a-f)都必須是小寫。
2.十六進制字符串中不能包含多餘的前導零。如果要轉化的數爲0,那麼以單個字符’0’來表示;對於其他情況,十六進制字符串中的第一個字符將不會是0字符。
3.給定的數確保在32位有符號整數範圍內。
4.不能使用任何由庫提供的將數字直接轉換或格式化
public String toHex(int num) {
if (num == 0) return "0";
int compare = 0xf; //0xf
char regex[] = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
StringBuilder sb = new StringBuilder();
while (num != 0 && sb.length() < 8) {
int temp = num & compare;
sb.append(regex[temp]);
num >>= 4;
}
return sb.reverse().toString();
}
思路:二進制4位對應16進制的一位