LeetCode初级算法——其他——算法总结
PS:算法并非原创,总结的本意在于温故知新、巩固知识。侵删。
1、位1的个数
使用C++解答,代码如下:
#include <stdint.h>
using namespace std;
class Solution {
public:
//方法1:O(32)
int hammingWeight1(uint32_t n) {
int result = 0;
for (int8_t i = 0; i < 32; i++)
{
if (n & (1 << i)) {
++result;
}
}
return result;
}
//方法2:O(m),m为n的二进制的位数
//减1操作将最右边的符号从0变到1,从1变到0,与操作将会移除最右端的1。如果最初n有X个1,那么经过X次这样的迭代运算,n将减到0。
int hammingWeight2(uint32_t n) {
int count = 0;
while (n != 0) {
n = n & (n - 1);
count++;
}
return count;
}
// 方法3:汉明重量,O(1)
//https://blog.csdn.net/sword52888/article/details/86513023 超详细解释
//但要注意溢出问题,有可能报错,需要将溢出的进行处理!!!
//0x55555555 == = >> 0101 0101 0101 0101 0101 0101 0101 0101,每两位为一组
//0x33333333 == = >> 0011 0011 0011 0011 0011 0011 0011 0011,每四位为一组
//0x0F0F0F0F == = >> 0000 1111 0000 1111 0000 1111 0000 1111,每八位为一组
//0x01010101 == = >> 0000 0001 0000 0001 0000 0001 0000 0001,将4组8位累加,刚好是32位的前8位,后面24位可以舍去,前面溢出的更可以舍去
int hammingWeight(int32_t i)
{
i = (i & 0x55555555) + ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
i = (i & 0x0F0F0F0F) + ((i >> 4) & 0x0F0F0F0F);
i = (i * (0x01010101) >> 24);
return i;
}
};
算法解析:
算法一:n & (1 << i)表示进行对应位的与运算,详情可见此链接,如果当前位是1的话则亦或运算结果为非0,如果不是的话则结果为0,只需要一直对1左移并判断,循环32次即可。
算法二:减1操作将最右边的符号从0变到1,从1变到0,这个可以理解。而与操作将会移除最右端的1(可自行演算)。如果最初n有X个1,那么经过X次这样的迭代运算,n将减到0。
算法三:汉明重量 (variable-precision SWAR 算法),第一次与0x55555555的运算将数据分成2位1组,得到的结果表示每组的1的数量。原因是i&0x55555555得到的是每组偶数位的1的数量,(i>>1)&0x55555555得到的是每组奇数位的1的数量,最后两两相加,得到每组的1的数量。
之后与0x33333333的操作,将上一操作的结果进行4位1组,得到的结果需要将组内的值进行相加,得到每4位的1的个数结果。上一轮操作,得到2位1组的1的个数,此处将每两组的1的个数相加。具体操作是通过0x0011进行取值,取出前2位和后2位的结果进行相加。每四位都进行这样的操作。
之后再和0x0f0f0f0f进行操作,得到8位1组的1的个数,思想和上述类似,不赘述。
最后一步,得到算法的结果,乘法的乘数为0x01010101,根据通过摆出乘法的竖式得出最后结果,只有在最高位的0x01才能进行每个低四位的相加操作。
算法占用时空间资源:
2、汉明距离
使用C++解答,代码如下:
class Solution {
public:
int hammingDistance(int x, int y) {
int res = 0;
for (int i = 0; i < 32; ++i) {
if ((x & (1 << i)) ^ (y & (1 << i))) {
++res;
}
}
return res;
}
};
算法解析:
按位分别取出两个数对应位上的数并异或(如何取位可参考上一题的算法一)我们知道异或的性质上相同的为0,不同的为1,我们只要把为1的情况累加起来就是汉明距离了。
算法占用时空间资源:
3、颠倒二进制位
使用C++解答,代码如下:
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
int A[32];
for(int i=0;i<32;i++){
if(n>=1){
A[i]=n%2;
n=n/2;
}
else{
A[i]=0;
}
}
uint32_t number=0;
for(int i=0;i<32;i++){
number += A[i]*pow(2,31-i);
}
return number;
}
};
算法解析:
采用长度为32的数组A存储颠倒结果,然后在通过进值转换运算得出number的结果。在颠倒的过程中,采用的是二进制转换的思想。十进制转为二进制的转换过程中,我们通过对应数据进行除二操作,得到的余数颠倒得到一个十进制数的二进制表示。那么现在即可直接进行除二操作,存储余数,得到的即是颠倒的二进制结果。
算法占用时空间资源:
4、杨辉三角
使用C++解答,代码如下:
class Solution {
public:
vector<vector<int>> generate(int numRows)
{
vector<vector<int>> nums1;
for(int i=1;i<=numRows;i++) //对于第i行,存i个元素,先赋值为0,后期存入其他值覆盖
nums1.push_back(vector<int>(i,0));
for(int i=0;i<numRows;i++) //遍历每个位置存值
{
for(int j=0;j<=i;j++)
{
if(j==0 || j==i)
{
nums1[i][j]=1; //边界赋值为1
}
else
{
nums1[i][j]=nums1[i-1][j-1]+nums1[i-1][j];
}
}
}
return nums1;
}
};
算法解析:
定义一个int型的二维数组nums1存储结果,然后进行初始化,同时确定数组的形状(塔形),之后遍历指定数量的行,边缘赋值为1,内部元素通过杨辉三角的运算规律进行计算,每一层都依赖于上一层的元素结果。
算法占用时空间资源:
5、有效的括号
使用JAVA解答,代码如下:
class Solution {
public boolean isValid(String s) {
if(s==null || "".equals(s)) {
return true;
}
//用栈保存 (,[,{
Stack<Character> stack = new Stack<Character>();
//map中保存的是 ):(, ]:[,}:{
//当遍历到 )时候就会去map中找对应的value,也就是(
//再用这个value和stack弹出的元素比较,如果相等则匹配上,不等则返回false
//这里也可以用数组来存,为了简单就用map表示了
HashMap<Character,Character> map = new HashMap<Character,Character>();
map.put(')','(');
map.put(']','[');
map.put('}','{');
for(int i=0;i<s.length();i++) {
char c = s.charAt(i);
//如果map中不包含 (,[,{,就将这个字符放入栈中
if(!map.containsKey(c)) {
stack.add(c);
} else {
//如果遍历的字符不在map中,也就是说这个字符是),],},那么就要跟栈中的元素比较
//首先要判断栈是否为空,如果输入的字符是 )() ,那么当遍历到第一个)时,栈为空
if(stack.size()==0) {
return false;
}
//取出栈顶的元素
Character tmp = stack.pop();
//假设当前遍历到的元素是 ],那么从map中取到的value就是 [
//如果栈顶的元素是 (,则不匹配返回false,否则继续
if(map.get(c)!=tmp) {
return false;
}
}
}
//返回的时候还要判断栈是否为空
//如果输入的字符串是 (((,那么最后栈就不为空
return (stack.empty()? true : false);
}
}
算法解析:
算法采用栈进行操作,当遍历到这三个字符的时候,就将其保存到栈中。遇到左括号则压入栈,遇到右括号则检查栈顶元素是否与该括号对应。如果对应,那么栈顶元素出栈,进行后续操作,如果不匹配,直接可知表达式无效。遍历到表达式末尾,如果栈内仍然元素,那么可知表达式无效。
算法占用时空间资源:
6、缺失数字
使用C++解答,代码如下:
class Solution {
public:
int missingNumber(vector<int>& nums) {
int n=nums.size();
int i;
sort(nums.begin(),nums.begin()+n);
for( i=0;i<n;i++){
if(nums[i]!=i){
// return i;
break;
}
}
return i;
}
};
算法解析:
先通过sort函数将函数进行大小排序,然后进行遍历,如果下标和元素值不对应,那么即可确定缺失的数字。
算法占用时空间资源: