力扣刷题笔记:数学推导、算法(11)

7. 整数反转(逐位运算)

先判断当前反转后的数是否超过范围,若在范围内则逐位反转

    int reverse(int x) {
     
        int rev = 0;
        while (x != 0) {
     
            if (rev < INT_MIN / 10 || rev > INT_MAX / 10) 
                return 0;
            int digit = x % 10;
            x /= 10;
            rev = rev * 10 + digit;
        }
        return rev;
    }

9. 回文数(逐位运算)

1、先进行边界判断,为0或者末位为0则返回
2、只反转一半即可,防止全部反转超过上限
3、直接判断反转后的数是否相等,不用按位判断

    bool isPalindrome(int x) {
     
        // 特殊情况:
        // 如上所述,当 x < 0 时,x 不是回文数。
        // 同样地,如果数字的最后一位是 0,为了使该数字为回文,
        // 则其第一位数字也应该是 0
        // 只有 0 满足这一属性
        if (x < 0 || (x % 10 == 0 && x != 0)) 
            return false;
        int revertedNumber = 0;
        while (x > revertedNumber) {
     
            revertedNumber = revertedNumber * 10 + x % 10;
            x /= 10;
        }
        // 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
        // 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
        // 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
        return x == revertedNumber || x == revertedNumber / 10;
    }
};

50. Pow(x, n)(快速幂)

直接求n次方复杂度太高,可以使用平方减小复杂度,每次n为奇数时先多乘一个x再平方,这就是快速幂的方法

    double myPow(double x, int n) {
     
       if(n == 0) return 1;
        double ans = 1;
        //必须用num,n是32位有符号整数,int存不下
        long num = n;
        if(n < 0) {
     
            //必须将n存为整数,不然无法移位
            num = -num;
            x = 1/x;
        }
        while(num){
     
            if(num%2==1) ans *= x;
            x *= x;
            num=num/2;
        }
        return ans;
    }

66. 加一(逐位运算)

从后往前遍历数组,依次加1,到不进位为止返回,如果遍历到开始时,用vector的insert方法插入一个1

    vector<int> plusOne(vector<int>& digits) {
     
        for(int i=digits.size()-1; i>=0; i--) {
     
            digits[i]++;
            if(digits[i] == 10)  digits[i] = 0;
            else  return digits;
        }
        digits.insert(digits.begin(), 1);
        return digits;
    }

136. 只出现一次的数字(位运算)

一个数和自己异或运算等于0,和0异或运算等于自己,并且异或运算满足交换律,所以对所有数字从头到尾异或运算一遍,出现两次的数都会变为0,最后只剩下只出现一次的数字,这个解法相比于哈希表没有额外的空间复杂度

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

剑指 Offer 56 - I. 两个只出现一次的数组(位运算)

1、本题与上一题的区别是,多了一个只出现一次的数字,直接异或不行,需要采用分组异或
2、首先过一遍异或,得到结果中找到第一个为1的数字,这个数字表示两个数结果肯定不一样
3、根据这一位数字与所有数进行且运算,将数组分为两组,再分别进行异或,得到两个答案

class Solution {
     
public:
    vector<int> singleNumbers(vector<int>& nums) {
     
        int x = 0, y = 0, n = 0, m = 1;
        for(int num : nums)         // 1. 遍历异或
            n ^= num;
        while((n & m) == 0)         // 2. 循环左移,计算 m
            m <<= 1;
        for(int num : nums) {
            // 3. 遍历 nums 分组
            if(num & m) x ^= num;   // 4. 当 num & m != 0
            else y ^= num;          // 4. 当 num & m == 0
        }
        return vector<int> {
     x, y};  // 5. 返回出现一次的数字
    }
};

172. 阶乘后的零(找规律)

1-4没有0,5-9有1个0,10-14有2个0,每隔5个数增加一个0,计算有多少个5即可

    int trailingZeroes(int n) {
     
        int ans=0;
        while(n>0){
     
            ans+=n/5;
            n/=5;
        }
        return ans;
    }

191. 位1的个数(位运算)

1、移位运算符<<代表:需要移位的数字 << 移位的次数
2、通过1不停的移位,和原数字进行与操作,判断二进制下1的个数

class Solution {
     
public:
    int hammingWeight(uint32_t n) {
     
    //位运算,移位运算符<<
    int num=0;
    for(int i=0;i<32;i++)
    if(n&(1<<i))
        num++;
    return num;
    }
};

384. 打乱数组(洗牌算法)

洗牌算法,从后往前遍历,每个位置和前面的随机交换即可

class Solution {
     
private:
    vector<int> original;
public:
    Solution(vector<int>& nums) {
     
        original = nums;
    }
    vector<int> reset() {
     
        return original;
    }  
    vector<int> shuffle() {
     
        vector<int> nums(original);                    //用原数组来初始化新数组
        for (int i = nums.size() - 1; ~i; i -- )       //从后往前遍历
            swap(nums[i], nums[rand() % (i + 1)]);     //rand()能随机生成0到最大随机数的任意整数                          
        return nums;                                   //rand() % (i + 1)能随机生成0到i中的任意整数
    }
};

468. 验证IP地址(正则表达式)

class Solution {
     
public:
    string validIPAddress(string IP) {
     
        regex ipv4("(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])");
        regex ipv6("([0-9a-fA-F]{1,4}\\:){7}[0-9a-fA-F]{1,4}");
        if (regex_match(IP, ipv4)) return "IPv4";
        else if (regex_match(IP, ipv6)) return "IPv6";
        else return "Neither";
    }
};
class Solution {
     
public:
    bool validIPv4(string IP) {
     
        if (IP.empty() || IP.back() == '.' || IP.front() == '.')
            return false;
        int digit = 0,dot_ind = -1,dot_num = 0;
        for (int i = 0; i < IP.size(); ++i) {
     
            if (IP[i] == '.') {
     
                if (i - dot_ind == 1)
                    return false;
                digit = 0;
                dot_ind = i;
                ++dot_num;
            } else if (IP[i] >= '0' && IP[i] <= '9') {
     
                if (i - dot_ind > 1 && digit == 0)
                    return false;
                digit = 10 * digit + IP[i] - '0';
                if (digit > 255)
                    return false;
            } else {
     
                return false;
            }
        }
        return dot_num == 3;
    }
    bool validHex(char c) {
     
        return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
    }
    bool validIPv6(string IP) {
     
        if (IP.empty() || IP.back() == ':' || IP.front() == ':')
            return false;
        string elem;
        int colon_ind = -1;
        int colon_num = 0;
        for (int i = 0; i < IP.size(); ++i) {
     
            if (IP[i] == ':') {
     
                if (elem.empty())
                    return false;
                elem.clear();
                colon_ind = i;
                ++colon_num;
            } else if (validHex(IP[i])) {
     
                elem += IP[i];
                if (elem.size() > 4)
                    return false;
            } else {
     
                return false;
            }
        }
        return colon_num == 7;
    }
    string validIPAddress(string IP) {
     
        if (validIPv4(IP))
            return "IPv4";
        if (validIPv6(IP))
            return "IPv6";
        return "Neither";
    }
};

470. 用 Rand7() 实现 Rand10()(拒绝采样)

用拒绝采样法,两个rand7不能直接相乘,会导致生成的数概率不相等
用rand7算出1-49,拒绝41-49,保留1-40算出rand10

    int rand10() {
     
        int add;
        do{
     
            int row=rand7();
            int col=rand7();
            //两个rand7不能直接相乘,会导致数概率不相等
            add=(row-1)*7+col;
        }while(add>40) ;
        
        return 1+(add-1)%10;
    }

你可能感兴趣的:(力扣刷题)