以下算法题均来自leetCode题库 https://leetcode-cn.com/
本篇难度为简单
给你一个非负整数 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的是偶数
给你一个单链表的引用结点 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;
}
}
思路:构造链表同结构的二进制表示数
请实现一个函数,输入一个整数,输出该数二进制表示中 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的判断
编写一个方法,找出两个数字a和b中最大的那一个。不得使用if-else或其他比较运算符。
public class Solution {
public int maximum(int a, int b) {
//等于1是负数,即ab ,可能涉及两个正负最大值相减,超过int的最大范围
//取符号位进行判断,long是64位,int是32位
int val = ((int)(((long)a - (long)b) >> 63)) & 1;
return a + (b - a) * val;
}
}
思路:取差值,根据符号位判断大小值
给定一个正整数,输出它的补数。补数是对该数的二进制表示取反。
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二进制进行异或运算
配对交换。编写程序,交换某个整数的奇数位和偶数位,尽量使用较少的指令(也就是说,位0与位1交换,位2与位3交换,以此类推)
//10101010101010101010101010101010 = 0xaaaaaaaa
//01010101010101010101010101010101 = 0x55555555
public int exchangeBits(int num) {
return (num << 1 & 0xaaaaaaaa) | (num >> 1& 0x55555555);
}
思路:左右分别位移一位,最后的结果叠加
给你一个整数数组 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的个数
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
public int singleNumber(int[] nums) {
int result = 0;
for (int item : nums) {
result ^= item;
}
return result;
}
思路:异或运算和参与运算的两个数位置无关;
任何数和0异或等于该数本身;
两个相同数字异或运算等于0
给定两个字符串 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,最终剩下的就是多出来的
给定一个包含 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;
}
思路:同上
给定一个正整数,检查他是否为交替位二进制数:换句话说,就是他的二进制数相邻的两个位数永不相等。
public boolean hasAlternatingBits(int n) {
int temp = n ^ (n >> 1);
return (temp & (temp + 1)) == 0;
}
思路:交替位合并如果是正确的会组成全1的二进制
颠倒给定的 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;
}
思路:逆向位移输出
不使用运算符 + 和 - ,计算两整数 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);
}
思路:算出进位的位置,循环递归至没有进位为止
整数转换。编写一个函数,确定需要改变几个位才能将整数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;
}
思路:遍历比较每一个位置的差异
给定一个整数 (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
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
public boolean isPowerOfTwo(int num) {
if (num <= 0 || (num & (num - 1)) != 0) return false;
return (num & 1) == 0 || num == 1;
}
思路:同上题,只是2的幂是除末尾外只有一位是1的二进制数
给定一个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的二进制位时,保存上次的值,并把之前的值清空;同时计算此时的最大长度
给定一个整数,编写一个算法将这个数转换为十六进制数。对于负整数,我们通常使用 补码运算 方法。
注意:
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进制的一位