且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

更新时间:2022-10-02 20:32:55

371.两整数之和

1.两整数之和 [小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数


1.两整数之和 

int getSum(int a, int b){
    return a + b;
}

2,位运算

预备知识:有符号的整数通常使用补码来表示和存储。补码具有以下特性:

  1. 正整数的补码与原码相同;负整数的补码为其原码除符号位外的所有位取反后+1
  2. 可以将减法运算转换为补码的加法运算来实现
  3. 符号位与数值位可以一起参与运算[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

异或相当于一次无进位加法。来看一个例子[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

 a ^ b得到了一个无进位加法运算结果,如果要得到 a + b 的结果的最终值,我们还要找到进位的数,把这二者相加

我们可以用操作获得进位

[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

由计算结果可见,0100 并不是我们想要的进位,1 + 1所获得的进位应该放在它的更高位,即在左侧位上,因此我们还要将 0100 左移一位,这才是我们所要的进位结果

总结一下:

  1. a + b 的问题拆分为(a + b 的无进制位结果)( a + b 的进制位结果)
  2. 无进位加法使用异或计算得出
  3. 进位结果使用与运算移位运算得出
  4. 循环此过程,直到进位为 0 
int getSum(int a, int b){
    int c = 0;
    while(b)
    {
        c = (unsigned int)(a & b) << 1;
        a ^= b;
        b = c;
    }
    return a;
}

面试题 17.01. 不用加号的加法 - 力扣(LeetCode) (leetcode-cn.com)

1,正常做法[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数2,位运算 [小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

int Add(int a, int b){
    int c = 0;
    while(b)
    {
        c = (unsigned int)(a & b) << 1;
        a ^= b;
        b = c;
    }
    return a;
}

思路参考第一题

剑指 Offer 65. 不用加减乘除做加法 - 力扣(LeetCode) (leetcode-cn.com)

此题的解法也类似上面两道题


面试题 08.05. 递归乘法 - 力扣(LeetCode) (leetcode-cn.com)

[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

对于这一题,我们可以采用暴力的方法直接 return a * b

不过,我们也可以按照题目的意思来操作一下下。[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

int multiply(int A, int B){
    int result; 
    if (B > 1)
    result = multiply(A, B - 1) + A;
    else
    result = A;
    return result;
}

递归使用乘法函数,相当于b次的a相加

方法二 

基本情况:

  1. B = 0 , 结果 == 0
  2. B = 1 , 结果 == A

考虑B为偶数的情况

res = A * ( B / 2) +  A * ( B / 2)

B为奇数时,只要在原本的结果上再加上 A 即可 

int multiply(int A, int B){
    if(B == 0) return 0;
    if(B == 1) return A;
    int C = 0;
    if(B & 1 > 0) //表示B为奇数
    {
        C = A;
    }
    return multiply(A , B >> 1) + multiply(A , B >> 1) + C;
}

29. 两数相除 - 力扣(LeetCode) (leetcode-cn.com)[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

题目规定了【只能存储32位整数】,如果我们使用64位整数,可以极大地方地方便我们的代码,但这是违反题目规则的。

如果除法结果溢出,我们需要返回  2(31)- 1

  1. 当除数为32位有符号整数的最小值-2(31) - 1时,如果除数为1,我们直接返回         -2(31)  ||   如果除数为-1,那么答案为 2(31),产生了溢出,我们需要返回的值为2(31) - 1
  2. 当被除数为0时,我们可以直接返回0

 于是,年幼的我们选择了

向大佬学习

int divide(int dividend, int divisor){
    int cnt = 0;
    int sign = 1;
    if ((dividend ^ divisor) < 0) { // 两数任意一个为负数
        sign = -1;
    }
    if (divisor == INT_MIN) { // 除数边界值特殊处理
        if (dividend == INT_MIN) {
            return 1;
        } else {
            return 0;
        }
    }
    if (dividend == INT_MIN) { // 被除数边界值特殊处理
        if (divisor == -1) {
            return INT_MAX;
        } else if (divisor == 1) {
            return INT_MIN;
        }
        dividend += abs(divisor); // 先执行一次加操作,避免abs转换溢出
        cnt++;
    } 
    int a = abs(dividend);
    int b = abs(divisor);
    while (a >= b) {
        int c = 1;
        int s = b;
        // 需指数级快速逼近,以避免执行超时
        while (s < (a >> 1)) { // 逼近至一半,同时避免溢出
            s += s;
            c += c;
        }
        cnt += c;
        a -= s;
    }
    return (sign == -1) ? -cnt : cnt;
}

50. Pow(x, n) - 力扣(LeetCode) (leetcode-cn.com)[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

我尝试使用了常规的思路如下

double myPow(double x, int n){
    double sum = 1;
    int i = 0;
    if(n == 0)
    return 1.0;
    if(n > 0)
    {
        for(i = 1;i <= n;i++)
        sum *= x;
    }
    if(n < 0)
    {
        x = 1.0 / x;
        for(i = 1;i <= -n;i++)
        sum *= x;
    }
    return sum;
}

不过时间复杂度太高,运行超时。后来去学习了大佬的解法如下:

方法一 :递归

double myPow(double x, int n){
    if (n == 0) return 1;
    if (n == 1) return x;
    if (n ==-1) return 1/x;
    double temp = myPow(x, n / 2);
    return temp * temp * myPow(x, n % 2);
}

方法二:迭代

double myPow(double x, int n){
    double res = 1.0;
    if (n < 0) x = 1/x;
    while (n) {
        if (n & 1) res = res * x;   //括号内等同(n % 2)
        x = x * x;
        n = n / 2;
    }
    return res;
}

方法三:快速幂 

快速幂的本质是分治算法 。

 举个例子:

[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

从x开始,直接将上一次的结果进行平方,计算6次就能得到x(64)次方,而不需要对x*63次x[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数从左到右进行推导看上去比较困难,因为在每一步中,我们不知道在将上一次的结果平方后是否还需要*x。如果我们从右往左看,分治的思想就很明显了。


当我们要计算 时,我们可以先递归计算出 y =  ,其中[n /2 ]表示对a进行向下取整

根据递归的结果,如果n为偶数,你们  =  ;如果n为奇数,那么 = * x

递归的边界为 n = 0,任意数的 0次方 为1

class Solution {
public:
    double quickMul(double x, long long N) {
        if (N == 0) {
            return 1.0;
        }
        double y = quickMul(x, N / 2);
        return N % 2 == 0 ? y * y : y * y * x;
    }
 
    double myPow(double x, int n) {
        long long N = n;
        return N >= 0 ? quickMul(x, N) : 1.0 / quickMul(x, -N);
    }
};

69. Sqrt(x) 题解 - 力扣(LeetCode) (leetcode-cn.com)

[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

(卷不动了)

[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数


面试题 16.07. 最大数值 - 力扣(LeetCode) (leetcode-cn.com)[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数没什么好说的了,三目操作符yyds

[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数


今天的LeetCode之旅到此结束,希望能跟英雄哥继续努力学习,不断提高自己!!

[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数

[小玄的刷题日记]《LeetCode零基础指南》(第二讲) 函数