- 多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
示例 2:
输入:[2,2,1,1,1,2,2]
输出:2
位运算c++
class Solution {
public:
int majorityElement(vector<int>& nums) {
int res = 0;
for(int i = 0 ; i < 32; ++i)
{
int ones = 0;
for(int n : nums)
ones += (n >> i) & 1; //位运算法统计每个位置上1出现的次数,每次出现则ones+1
res += (ones > nums.size()/2) << i; //如果1出现次数大于1/2数组的长度,1即为这个位置的目标数字
}
return res;
}
};
摩尔投票法
候选人(cand_num)初始化为nums[0],票数count初始化为1。
当遇到与cand_num相同的数,则票数count = count + 1,否则票数count = count - 1。
当票数count为0时,更换候选人,并将票数count重置为1。
遍历完数组后,cand_num即为最终答案。
为何这行得通呢?
投票法是遇到相同的则票数 + 1,遇到不同的则票数 - 1。
且“多数元素”的个数> ⌊ n/2 ⌋,其余元素的个数总和<= ⌊ n/2 ⌋。
因此“多数元素”的个数 - 其余元素的个数总和 的结果 肯定 >= 1。
这就相当于每个“多数元素”和其他元素 两两相互抵消,抵消到最后肯定还剩余至少1个“多数元素”
无论数组是1 2 1 2 1,亦或是1 2 2 1 1,总能得到正确的候选人。
public int majorityElement(int[] nums) {
if(nums.length <= 0) return 0;
int res = nums[0];
int count =1;
for(int i =1; i< nums.length; i++){
if(res == nums[i]){
count++;
}else if(--count ==0){
res = nums[i];
count = 1;
}
}
return res;
}
思路
public int majorityElement(int[] nums) {
if(nums.length <= 0) return 0;
int res = nums[0];
int count =1;
for(int i =1; i< nums.length; i++){
if(res == nums[i]){
count++;
}else{
count -=1;
count = 1;
}
}
if(count >=1 ) return res;
return 0;
}
- 颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。
示例 1:
输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
public class Solution {
public int reverseBits(int n) {
public int reverseBits(int n) {
int res =0;
for(int i=0; i < 32;i++){
res <<= 1;
res += n&1;
n >>= 1;
}
return res;
}
}
- 2的幂
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。
示例 1:
输入: 1
输出: true
解释: 20 = 1
示例 2:
输入: 16
输出: true
解释: 24 = 16
class Solution {
public boolean isPowerOfTwo(int n) {
if (n == 0) return false;
long x = (long) n;
return (x & (-x)) == x;
}
}
- 丢失的数字
给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。
进阶:你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?
示例 1:
输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。
示例 2:
输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。
由于异或运算(XOR)满足结合律,并且对一个数进行两次完全相同的异或运算会得到原来的数,
因此我们可以通过异或运算找到缺失的数字。
class Solution {
public int missingNumber(int[] nums) {
int missing = nums.length;
for (int i = 0; i < nums.length; i++) {
missing ^= i ^ nums[i];
}
return missing;
}
}
- 4的幂
给定一个整数,写一个函数来判断它是否是 4 的幂次方。如果是,返回 true ;否则,返回 false .整数 n 是 4 的幂次方需满足:存在整数 x 使得 n == 4x
示例 1:
输入:n = 16
输出:true
示例 2:
输入:n = 5
输出:false
位操作
算法:
我们首先检查 num 是否为 2 的幂:x > 0 and x & (x - 1) == 0。
现在的问题是区分 2 的偶数幂(当 xx 是 4 的幂时)和 2 的奇数幂(当 xx 不是 4 的幂时)。
在二进制表示中,这两种情况都只有一位为 1,其余为 0。
有什么区别?在第一种情况下(4 的幂),1 处于偶数位置:第 0 位、第 2 位、第 4 位等;
在第二种情况下,1 处于奇数位置。
因此 4 的幂与数字 (101010...10)_2(101010...10)2
向与会得到 0。即 4^a \land (101010...10)_2 == 04
a∧(101010...10) 2==0。
(101010...10)_2(101010...10)2
用十六进制表示为 :(aaaaaaaa)_{16}(aaaaaaaa)16
public boolean isPowerOfFour(int n) {
if(n ==0 ) return false;
return (n &(-n)) == n && (n& 0xaaaaaaaa) ==0;
}
- 两整数之和
不使用运算符 + 和 - ,计算两整数 a 、b 之和。
示例 1:
输入: a = 1, b = 2
输出: 3
同样我们可以用三步走的方式计算二进制值相加: 5—101,7—111
第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,101^111。
第二步:计算进位值,得到1010,相当于各位进行与操作得到101,再向左移一位得到1010,(101&111)<<1。
第三步重复上述两步,各位相加 010^1010=1000,进位值为100=(010 & 1010)<<1。
继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。
结束条件:进位为0,即a为最终的求和结果。
class Solution {
public int getSum(int a, int b) {
while(b != 0){
int temp = a ^ b;
b = (a & b) << 1;
a = temp;
}
return a;
}
}
- 找不同
给定两个字符串 s 和 t,它们只包含小写字母。
字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。
请找出在 t 中被添加的字母。
示例 1:
输入:s = “abcd”, t = “abcde”
输出:“e”
解释:‘e’ 是那个被添加的字母。
示例 2:
输入:s = “”, t = “y”
输出:“y”
思路
public char findTheDifference(String s, String t) {
if(s.length() ==0) return t.charAt();
Set<char> set = new HashSet<>();
char sh = s.charAt();
set.put(ch);
char th = t.charAt();
if(!set.countains(th)) return th;
}
class Solution {
public char findTheDifference(String s, String t) {
int ret = 0;
for (int i = 0; i < s.length(); ++i) {
ret ^= s.charAt(i);
}
for (int i = 0; i < t.length(); ++i) {
ret ^= t.charAt(i);
}
return (char) ret;
}
}
面试题 05.01. 插入
给定两个整型数字 N 与 M,以及表示比特位置的 i 与 j(i <= j,且从 0 位开始计算)。
编写一种方法,使 M 对应的二进制数字插入 N 对应的二进制数字的第 i ~ j 位区域,不足之处用 0 补齐。具体插入过程如图所示。
题目保证从 i 位到 j 位足以容纳 M, 例如: M = 10011,则 i~j 区域至少可容纳 5 位。
示例1:
输入:N = 1024(10000000000), M = 19(10011), i = 2, j = 6
输出:N = 1100(10001001100)
示例2:
输入: N = 0, M = 31(11111), i = 0, j = 4
输出:N = 31(11111)
先把数N的j到i之间的位置0
M左移i位
再用N或运算M
例 N = 1011 1111, M = 101, i = 2, j = 4
(1<<(j-i+1))-1)<<i = 0001 1100
取反后
1110 0011
对N于运算
1011 1111 & 1110 0011 = 1010 0011
M左移动i位
101 << i = 0001 0100
最后M|N
0001 0100 | 1010 0011 = 1011 0111 = 183
public int insertBits(int N, int M, int i, int j) {
int mask=((1<<(j-i+1))-1)<<i;
mask=~mask;
N&=mask;
M=M<<i;
return M|N;
}