给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,
找出 0 .. n 中没有出现在序列中的那个数。
示例 1:
输入: [3,0,1]
输出: 2
示例 2:
输入: [9,6,4,2,3,5,7,0,1]
输出: 8
思路1:求和后求差值
先求0~n的和,再减去“nums数组求和”,差值即为缺失的值
但是由于求和容易溢出,所以边加边减可以从一定程度上解决这个问题
即每次加上一个nums[i]的同时减去i
思路2:位运算——异或
利用异或的性质:A ^ A = 0, 0 ^ A = A;
那么nums数组内元素全部拿来和0~n异或
由于大多数一一对应的值因为A^A=0而被消掉
所以得到0去和0~n中缺失的B相异或,结果即为所求
这里异或的作用:消去相同元素
int missingNumber(int* nums, int numsSize) {
/*-----思路1-----*/
int sum = 0;
for (int i = 0; i < numsSize; i++) {
sum += nums[i] - i; //边加边减 //这里是反过来减,即nums求和-“0~n的和”
} return abs(sum - numsSize); //由于反过来减,所以要abs反转
//由于for循环执行的边界条件导致最后一次-i没有实现,所以补上漏减的numsSize
/*-----思路2-----*/
int ret = numsSize; //这里还异或了numsSize,与上面同理
for(int i=0; i<numsSize; i++){
ret ^= nums[i] ^ i;
} return ret;
}
.
.
.
给定一个整数,编写一个算法将这个数转换为十六进制数
不能使用任何由库提供的将数字直接转换或格式化为十六进制的方法
示例 1:
输入: 26
输出: “1a”
示例 2:
输入: -1
输出: “ffffffff”
思路1:位运算
编程中遇到的数我们都可以把它看做是一个二进制数
比如char是8bit的二进制,int是32bit的
而把二进制转化成十六进制,只需要每4位取出来转化成十进制即可
所以我们对num取低4位,然后转换成十六进制,然后num移位4,循环操作,直到num为0
这里要注意的是,由于我们是从低位开始取,所以需要逆序输出
思路2:格式化输出
就是利用sprintf然后%x格式化输出,当然这是违规的,题目不允许这么做
char* toHex(int num) {
//思路1:
if (0 == num)return "0";
char* p = "0123456789abcdef";
char* ans = (char*)calloc(9, sizeof(char));
for (int i = 8 - 1; i > 0 - 1; i--) {
ans[i] = p[num & 0xf]; //妙用字符串p //取出低4位
num >>= 4; //右移4位
} char* s = ans;
//到这里,我们得到的是以0开头的字符串,所以需要滤去0
while (*s == '0') {
s++;
} return s;
//思路2:
// sprintf(ans, "%x\0", num);
// return ans;
}
.
.
.
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 2^0 = 1
示例 2:
输入: 16
输出: true
解释: 2^4 = 16
示例 3:
输入: 218
输出: false
思路1:位运算:计算1的位数
因为是2的幂次,所以肯定最先自然而然想到的就是位运算
然后我们知道2的幂次只有一个1,其他位都为0(从二进制的角度来看数字)
于是就有了本思路:计算1的位数——每次判断最低位是否为1并且向右移位一位,直到n等于0,判断1的个数。
思路2:位运算:奇技淫巧
根据思路1,知道2的幂次只有一个1,
那么如果是2的幂次,减1之后,原本1所占位为0,所有前置位为1
那么再将得到的结果与原来的n做按位与,结果为0
而如果不是2的幂次,则相与结果不为0
e.g.
4: 0100
4-1: 0011
&: 0000
5: 0101
5-1: 0100
&: 0100
bool isPowerOfTwo(int n) {
//思路1:判断1的位数是否为1
if (n <= 0)return false;
int cnt = 0;
while (n != 0) {
if (n & 1)cnt++;
n >>= 1;
} return (cnt > 1) ? false : true;
//思路2:判断n&(n-1)的值
if(n<=0)return false;
return !(n&(n-1));
}
.
.
.
不使用运算符 + 和 - ,计算两整数 a 、b 之和。
示例 1:
输入: a = 1, b = 2
输出: 3
示例 2:
输入: a = -2, b = 3
输出: 1
思路1:位运算:不进位加法+进位
众所周知,异或能够实现不进位加法,即a^b
但是丢失了进位,所以要想办法得到进位
然后我们发现a&b能得到进位的位
于是我们只要把进位的位左移1位之后加上a^b就可以了
即,不进位加法+进位
但是,由于题目要求不能用+、-,所以得到两个数之后还是不能直接相加
所以再反复进行这项操作:求异或(不进位加法)、求按位与(进位),然后二者反复…
int getSum(int a, int b){
while(b){ //还有进位,则还要继续加
int carry = ((unsigned int)a&b)<<1;
a ^= b; //a = a^b; 得到不进位的加法
b = carry; //更新进位
} return a;
}
思路2:直接return a+b
虽然题目不允许,但是编译器通过了,实在想不出来第一种就只有狗急跳墙了