总结:这六道题目中,题目4是找寻规律,题目5是栈的应用,其余四道均是使用位运算来解决问题。关于位运算在算法中的一些应用,可以参考之前总结过的一篇文章《程序中位运算的妙用》,有时在程序设计加入一些位运算可以有效提升程序运行的速度,优化算法,位运算并不是鸡肋,要能够合理应用。
题目1:位1的个数
编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
思路:每次都判断n的最后一位是不是1,如果是就在count上加1,之后将n向右移动一位,直到将32位全部遍历完。以下有两种写法去完成位运算,一种是直接使用位运算符,一种是用普通运算符号来代替位运算符完成操作。
int hammingWeight(uint32_t n)
{
int count = 0;
uint32_t num = n;
for(int i=0;i<32;i++)
{
count += num&1;
num >>= 1;
}
return count;
}
int hammingWeight(uint32_t n)
{
int count = 0;
uint32_t num = n;
while(num!=0)
{
count += num%2;
num = num/2;
}
return count;
}
题目2:汉明距离
两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。
给出两个整数 x 和 y,计算它们之间的汉明距离。
注意:
0 ≤ x, y < 231.
示例:
输入: x = 1, y = 4
输出: 2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑
上面的箭头指出了对应二进制位不同的位置。
思路:先让两个数字异或产生一个新的数字temp,因为异或的逻辑是同0异1,两个数的相同位在新数字中对应位置全是0,不同位在新数字中对应位置全是1,最后通过移位判断temp中1的个数即可。同样也有两种写法来解决问题。
int hammingDistance(int x, int y)
{
int count = 0;
int temp = x^y;
for(int i=0;i<32;i++)
{
count += temp&1;
temp >>= 1;
}
return count;
}
int hammingDistance(int x, int y)
{
int count = 0;
int temp = x^y;
while(temp!=0)
{
count += temp%2;
temp = temp/2;
}
return count;
}
题目3:颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。
示例 1:
输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
示例 2:
输入:11111111111111111111111111111101
输出:10111111111111111111111111111111
解释:输入的二进制串 11111111111111111111111111111101 表示无符号整数 4294967293,
因此返回 3221225471 其二进制表示形式为 10101111110010110010011101101001。
思路:从低位开始遍历n,每次遍历得到n的一位,先将result左移一位为新得到的位留出空间,之后将得到的位放入result中,执行以上步骤直到n的32位全部遍历完。
uint32_t reverseBits(uint32_t n)
{
uint32_t result = 0;
for(int i=0;i<32;i++)
{
result <<= 1;
//n%2是为了得到n此时的最后一位
//此时result最后一位是0,0跟0异或是0,0跟1异或是1
result = result^(n%2);
n >>= 1;
}
return result;
}
题目4:帕斯卡三角形
给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
在杨辉三角中,每个数是它左上方和右上方的数的和。
示例:
输入: 5
输出:
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
思路:第n层有n个元素,每一层的第一个和最后一个元素的都是1,第n层的第i个元素是第n-1层的第i-1个元素和第i个元素之和。
vector<vector<int> > generate(int numRows)
{
vector<vector<int> > result;
if(numRows==0)
return result;
//i是层数
for(int i=0;i<numRows;i++)
{
vector<int> level;
//j是每层元素下标
for(int j=0;j<=i;j++)
{
if(j==0||j==i)
level.push_back(1);
else
level.push_back(result[i-1][j-1]+result[i-1][j]);
}
result.push_back(level);
}
return result;
}
题目5:有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
1.左括号必须用相同类型的右括号闭合。
2.左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true
示例 2:
输入: "()[]{}"
输出: true
示例 3:
输入: "(]"
输出: false
示例 4:
输入: "([)]"
输出: false
示例 5:
输入: "{[]}"
输出: true
思路:利用栈的特性来解决问题。遍历给定字符串,遇到前半部分括号就入栈,遇到后半部分括号就和栈顶字符匹配,如果匹配成功则栈顶元素出栈,继续遍历;如果匹配不成功或者栈为空则返回false。当遍历完字符串后,栈中仍有剩余括号,说明没有匹配成功,返回false,否则返回true。
bool judge(char c1,char c2)
{
if(c1=='(')
return c2==')';
if(c1=='{')
return c2=='}';
if(c1=='[')
return c2==']';
return false;
}
bool isValid(string s)
{
int len = s.size();
if(len==0)
return true;
stack<int> bracket;
for(int i=0;i<len;i++)
{
if(s[i]=='('||s[i]=='{'||s[i]=='[')
bracket.push(s[i]);
else
{
if(bracket.size()==0)
return false;
if(!judge(bracket.top(),s[i]))
return false;
bracket.pop();
}
}
if(bracket.size()!=0)
return false;
return true;
}
题目:6:缺失数字
给定一个包含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,那么就是缺少0;如果遇到后一个数比前一个数大2的情况,那么缺少两个数中间那个数;如果没有遇到前面两种情况,那么缺少n。
int missingNumber(vector<int>& nums)
{
int len = nums.size();
if(len==0)
return 0;
sort(nums.begin(),nums.end());
if(nums[0]!=0)
return 0;
for(int i=1;i<len;i++)
{
if(nums[i]-nums[i-1]==2)
return nums[i]-1;
}
return nums[len-1]+1;
}
思路2:将0到n和nums中所有元素全部异或进result,因为相同数字异或会为0,那么最后result代表的就是缺失的数字。
int missingNumber(vector<int>& nums)
{
int len = nums.size();
if(len==0)
return 0;
int result = 0;
for(int i=0;i<=len;i++)
{
if(i<len)
result ^= nums[i];
result ^= i;
}
return result;
}