LeetCode题解之数学运算题(包括位运算)(一)

171 阅读2分钟

7. 整数反转

class Solution {
public:
    int reverse(int x) {
        int rev = 0;
        while(x != 0)
        {
            if(rev > INT_MAX / 10 || rev < INT_MIN / 10)//用rev*10>INT会溢出,改用除法就好
                return 0;
            rev = rev * 10 + x % 10;//负数会余负数,做乘法加法都是负数
            x /= 10;
        }
        return rev;
    }
};

9. 回文数

class Solution {
public:
    bool isPalindrome(int x) {
        if(x < 0 || x % 10 == 0 && x != 0) return false;
        int half = 0;
        while(half < x)
        {
            half = half * 10 + x % 10;
            x = x / 10;
        }
        return x == half || x == half / 10;//奇数的话可能是十倍关系

    }
};

78. 子集

class Solution {
public: 
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> res;
        int n = nums.size();
        for(int i = 0; i < 1 << n; i ++)//用移位实现n次方
        {
            vector<int> tmp;
            for(int j = 0; j < n; j ++)
                if(i >> j & 1) {tmp.push_back(nums[j]);}
            res.push_back(tmp);
        }
        return res;
    }
};

136. 只出现一次的数字

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int tmp = 0;
        for(auto x : nums) tmp ^= x;
        return tmp;
    }
};

剑指 Offer 14- I. 剪绳子(剑指 Offer 14- II. 剪绳子 II)

class Solution {
public:
    int cuttingRope(int n) {
        /*  N=n1+n2+n3... 
        1.最优拆分不包含>=5的,因为假如ni>=5,拆出一个3后3*(ni-3)=3*ni-9>=ni,因为2*ni>=9肯定成立
        2.最优解不包含4,y因为4=2*2没变化
        3.最优解不包含1,因为乘1没变化
        4.最后只剩最优解包含2和3
            4.1 最优解不会包含3个2,因为2*2*2<3*3,所以只有2个2
        */
        //边界情况
        if(n <= 3) return 1 * (n - 1);//至少拆成2个数
        int res = 1;
        if(n % 3 == 1) res *= 4, n -= 4;//拆出2个2
        if(n % 3 == 2) res *= 2, n -= 2;//拆出1个2
        while(n)
        {
            res *= 3;//res %=1000000007;要求取模时
            n -= 3;
        }
        return res;

    }
};

剑指 Offer 15. 二进制中1的个数

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int res = 0;
        for(int i = 31; i>= 0; i --)
        {
            res += n >> i & 1;
        }
        return res;
    }
};

剑指 Offer 17. 打印从1到最大的n位数

class Solution {
public:
    vector<int> printNumbers(int n) {
        int max = 1;
        while(n --)
        {
            max *= 10;
        }
        vector<int> res;
        for(int i = 1;i < max; i ++)
        {
            res.push_back(i);
        }
        return res;
    }
};

剑指 Offer 56 - I. 数组中数字出现的次数

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int res = 0;
        for(auto x : nums)
            res ^= x;
        int n = 0;
        while((res & 1)==0) n ++, res >>= 1;//n移位,找到一个1位,说明a、b在这一位上不同
        int a = 0, b = 0;
        for(auto x : nums)
        {
            if(x >> n & 1) a ^= x;//不同位是1 的分在一边
            else b ^= x;
        }
        return {a,b};

    }
};

剑指 Offer 56 - II. 数组中数字出现的次数 II

class Solution {
public:
    int singleNumber(vector<int>& nums) {
     //对32位二进制数每一位%3看余数,拼起来就是这个数字,时间复杂度32n
     //看起来是o(n),实际logn<32,所以32n>nlogn
     int ans = 0;
        for (int i = 31; i >= 0; i --) {
            int cnt = 0;
            for (int x : nums) {
                if (x >> i & 1) {
                    cnt ++;
                }
            }
            if (cnt % 3 == 1) {
                ans = (ans * 2) + 1;
            }
            else {
                ans = ans * 2;
            }
        }
        return ans;

    }
};

剑指 Offer 65. 不用加减乘除做加法

class Solution {
public:
    int add(int a, int b) {
        //异或:不进位加法
        int x = ~(1 << 31);//把负数移位的符号为的1去掉
        while(b)
        {
            int c = (a & b & x) << 1;//进位的值,左移再与非进位的相加,b = ((unsigned int)(a & b) << 1);也可以
            a = a ^ b;//非进位的值
            b = c;//最终c的进位为0时停止
        }
        return a;
    }
};

剑指 Offer 66. 构建乘积数组(238. 除自身以外数组的乘积)

//方法一
class Solution {
public:
    vector<int> constructArr(vector<int>& nums) {
        if(nums.empty()) return {};
        int n = nums.size();
        vector<int> a(n);
        vector<int> b(n);
        vector<int> res(n);
        a[0] = 1;
        b[n - 1] = 1; 
        //分别算前后数的乘积数组,再对应相乘
        for(int i = 1; i < n; i ++)
            a[i] = a[i - 1] * nums[i - 1];
        for(int i = n - 2; i >= 0; i --)
            b[i] = b[i + 1] * nums[i + 1];
        for(int i = 0; i < n; i ++)
            res[i] = a[i] * b[i];
        return res;
    }
};
//或者方法二
class Solution {
public:
    vector<int> constructArr(vector<int>& A) {
        if(A.empty()) return vector<int>();
        int n = A.size();

        vector<int> B(n);
        //先算0~i-1的基
        for(int i = 0, p = 1; i < n; i ++)
        {
            B[i] = p;//b0=1,b1=a0,b2=a0a1
            p *= A[i];//p=a0,p=a0a1
        }
        //从最后一个数开始,算n-1~i,
        for(int i = n - 1, p = 1; i>=0; i --)
        {
            B[i] *= p;//bn-1不用多乘,bn-2需要多乘an-1,bn-3需要an-1an-2;
            p *= A[i];
        }
        return B;
    }
};

461. 汉明距离

class Solution {
public:
/*
直接先异或,然后求异或的结果中1的位数
*/
    int hammingDistance(int x, int y) {
        int n = x ^ y;
        int counter = 0;
        while( n > 0)
        {
            counter += n & 1;
            n >>= 1;
        }
        return counter;
    }
};

448. 找到所有数组中消失的数字

class Solution {
public:
    vector<int> findDisappearedNumbers(vector<int>& nums) {
        int n = nums.size();
        vector<int> res;
        //把对应的索引值变成负数来标记这个索引是有对对应的数值的
        for(int i = 0; i < n; i ++)
        {
            int index = abs(nums[i]) - 1;
            nums[index] = -abs(nums[index]);
        }
        for(int i = 0; i < n; i ++)
        {
            if(nums[i] > 0) res.push_back(i + 1);
        }
        return res;
    }
};