2

「算法刷题」数学情景专项汇总(力扣版)

 1 year ago
source link: https://magicdeveloperdrl.github.io/2022/06/13/%E7%AE%97%E6%B3%95%E5%88%B7%E9%A2%98-%E6%95%B0%E5%AD%A6%E6%83%85%E6%99%AF%E4%B8%93%E9%A1%B9%E6%B1%87%E6%80%BB-%E5%8A%9B%E6%89%A3%E7%89%88.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

「算法刷题」数学情景专项汇总(力扣版)

Jun 13, 2022 • MRL Liu

本文记录作者刷题过程中与数学情景相关的题目。

一、实现函数

50. Pow(x, n)(中等函数)

剑指 Offer 16. 数值的整数次方(中等函数)

class Solution {
public:
    // x的n次幂等于n个x相乘,请注意,n可能为负数
    // 直接使用while循环,n非常大时会超时,所以需要用快速幂的位运算
    // 同时注意n可能是一个极大的负数,转换为long
    double myPow(double x, int n) {
        if(x==0.0f) return 0.0f;// 0的任何幂都设为0
        if(x==1.0f) return 1.0f;// 1的任何幂都设为1
        double res=1.0f;
        // 特殊情况:n为负数
        long b = n;//排除n为极大的负数
        if(b<0){
            x=1/x;
            b=-b;
        }
        // 快速幂算法的位运算版本
        while(b){
            if(b&1==1) res=res*x;//如果b是奇数,则res直接*x
            x=x*x;//x自乘
            b>>=1;//b右移1位,相当于/2
        }
        return res;
    }
};

剑指 Offer 67. 把字符串转换成整数(中等难度)

8. 字符串转换整数 (atoi)(中等难度)

class Solution {
public:
    /*本题是要将字符串转为有符号的32位整数。
    根据示例,字符串可能存在前端空格、正负号、后缀字母、首字符非数字、数字越界共计5种情况,
    这也是本题的难点*/
    bool isDigit(char c){
        return c-'0'>=0&&c-'0'<=9;
    }
    int strToInt(string str) {
        int n=str.length();
        if(n==0) return 0;//非有效转换输出0
        int start=0;
        int negative=false;
        // 去掉前端空格
        for(char c:str){
            if(c==' ') start++;
            else break;
        }
        if(start==n)return 0;//去掉前导空格后到了末尾
        // // 判断非空首字符
        if (str[start] == '-') {
            negative = true;
            start++;
        }
        else if (str[start] == '+') 
        {
            negative = false;
            start++;
        }
        else if (!isDigit(str[start])){
            return 0;//非数字
        } 
        // 判断
        int ans = 0;
        while (start < n && isDigit(str[start])) {
            int digit = str[start] - '0';
            if (ans > (INT_MAX - digit) / 10) {
                // 本来应该是 ans * 10 + digit > Integer.MAX_VALUE
                // 但是 *10 和 + digit 都有可能越界,所有都移动到右边去就可以了。
                return negative? INT_MIN : INT_MAX;
            }
            ans = ans * 10 + digit;
            start++;
        }
        return negative? -ans : ans;
    }
};

剑指 Offer 20. 表示数值的字符串

二、N位数

剑指 Offer 17. 打印从1到最大的n位数(简单难度)

class Solution {
public:
    /*本题的难点在于n的增加,会让结果数组指数级增加:
    n=1,只有9个数;n=2,就有99个数;n=3,就有999个数
    所以n=n时,推理有n个9位数的数
    这道题返回一个int数组,测试数据也没有溢出
    如果让返回一个int数,可能存在溢出的情况,则难度会提升。
    */
    vector<int> printNumbers(int n) {
        // 计算需要多少个数
        int sum = 1;
        for (int i = 0; i < n; i++) sum *= 10;
        // 向结果数组中添加数字
        vector<int> res(sum - 1);
        for(int i = 0; i < sum - 1; i++) res[i] = i + 1;
        return res;
    }
};

400. 第 N 位数字

class Solution {
public:
    /*题意:将整数序列看做一个大整数,返回其第n位的数字*/
    int findNthDigit(int n) {
        if(n<=9) return n;
        //先确定第n位数字到了几位数,每种数字分别占用字符:9*1,90*2,900*3 等等
        long num=9;
        int d=1;//第n位所在的数字的位数
        while(n>num*d){
            n-=num*d;
            d++;
            num*=10;
        }
        //即为d位数,注意n此时一定大于0,因为若n归0,则在上一while循环不会减
        int m=(n-1)/d+1;
        int p=n-(m-1)*d;//所求即为d位数的第m个数字的第p位
        int k=(int)(num/9+m-1);//所求数字所在的那个数
        return (k/(int)pow(10,d-p))%10;
    }
};

剑指 Offer 43. 1~n 整数中 1 出现的次数

233. 数字 1 的个数

class Solution {
public:
    int countDigitOne(int n) {
        return dfs(n);
    }
    //下面我们都用 1234 和 2345 来举例
    long dfs(int n){
        // 上一级递归 n = 20、10之类的整十整百之类的情况;以及n=0的情况
        if(n== 0) return 0;
        // n < 10 即为个位,这样子只有一个1
        if(n < 10) return 1;
        string s = to_string(n);
        //长度:按例子来说是4位
        int length = s.length();
        //这个base是解题速度100%的关键,本例中的是999中1的个数:300
        // 99的话就是20 ; 9的话就是1 ;9999就是4000 这里大家应该发现规律了吧。
        long base = (length-1)*(int)pow(10,length-2);

        //high就是最高位的数字
        int high = s[0] - '0';
        //cur就是当前所数量级,即1000
        int cur = (int)pow(10,length -1);
        if(high == 1){
            // 最高位为1,1+n-cur就是1000~1234中由千位数提供的1的个数
            // 剩下的f函数就是求1000~1234中由234产生的1的个数
            return base + (1+n-cur)+dfs(n-high*cur); 
        }else{
            // 这个自己思考
            return base*high+cur+dfs(n-high*cur);
        }
    }
};

一、扑克牌相关

剑指 Offer 61. 扑克牌中的顺子(简单难度)

class Solution {
public:
    /*解析:本题要求判断一个5个元素的数组是否是顺子
    稍微思考下,明白首先要从小到大排序,然后判断是否有除0以外的重复数,有则肯定不是顺子
    难点在于0可以看做然后数来填补顺子,如何判断几张0填补顺子是算法的难点?
    解决方案:找到minVal(非0)和maxVal,通过maxVal-minVal的差来判断需要几张0填补
    */
    bool isStraight(vector<int>& nums) {
        int zeroCnt=0;//0的数组
        int n=nums.size();//此题固定为5
        sort(nums.begin(),nums.end());//从小到大排序
        // 遍历数组,记录0的个数并判断是否存在重复数
        for(int i=0;i<n;i++){
            if(nums[i]==0)zeroCnt++;
            else if(i+1<n&&nums[i]==nums[i+1]) return false;
        }
        // maxVal-minVal<5时必定可以
        return nums[n-1]-nums[zeroCnt]<5;
    }
};

「算法刷题」位运算专项汇总(力扣版)

「算法刷题」数组之大数相加专项汇总(力扣版)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK