leetcode刷题——算法(8):数学

素数分解

整除

最大公约数最小公倍数

1. 生成素数序列

思考后可做出Ok

 

2. 最大公约数

 

 

3. 使用位操作和减法求解最大公约数

 

 

进制转换

1. 7 进制

思考后可做出Ok

 

2. 16 进制

一开始未做出

3. 26 进制

解法可优化

阶乘

1. 统计阶乘尾部有多少个 0

解法可优化

字符串加法减法(2.21)

1. 二进制加法

一开始可做出Ok

 

2. 字符串加法

一开始可做出Ok

 

相遇问题

1. 改变数组元素使所有的数组元素都相等

一开始未做出

多数投票问题

1. 数组中出现次数多于 n / 2 的元素

解法可优化

其它

1. 平方数

一开始可做出,

有其他方法可参考

2. 3 的 n 次方

一开始可做出Ok

 

3. 乘积数组

思考后可做出Ok

 

4. 找出数组中的乘积最大的三个数

一开始未做出

 

素数分解

每一个数都可以分解成素数的乘积,例如 84 = 22 * 31 * 50 * 71 * 110 * 130 * 170 * …

整除

x = 2m0 * 3m1 * 5m2 * 7m3 * 11m4 * …

y = 2n0 * 3n1 * 5n2 * 7n3 * 11n4 * …

如果 x 整除 yy mod x == 0),则对于所有 imi <= ni

最大公约数最小公倍数

x y 的最大公约数为:gcd(x,y) = 2min(m0,n0) * 3min(m1,n1) * 5min(m2,n2) * ...

x y 的最小公倍数为:lcm(x,y) = 2max(m0,n0) * 3max(m1,n1) * 5max(m2,n2) * ...

1. 生成素数序列

204. Count Primes (Easy)

https://leetcode-cn.com/problems/count-primes/

2. 最大公约数

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

最小公倍数为两数的乘积除以最大公约数。

int lcm(int a, int b) {
    return a * b / gcd(a, b);
}

3. 使用位操作和减法求解最大公约数

对于 a 和 b 的最大公约数 f(a, b),有:

  1. 如果 a 和 b 均为偶数,f(a, b) = 2*f(a/2, b/2);
  2. 如果 a 是偶数 b 是奇数,f(a, b) = f(a/2, b);
  3. 如果 b 是偶数 a 是奇数,f(a, b) = f(a, b/2);
  4. 如果 a 和 b 均为奇数,f(a, b) = f(b, a-b);

乘 2 和除 2 都可以转换为移位操作。

public int gcd(int a, int b) {
    if (a < b) {
        return gcd(b, a);
    }
    if (b == 0) {
        return a;
    }
    boolean isAEven = isEven(a), isBEven = isEven(b);
    if (isAEven && isBEven) {
        return 2 * gcd(a >> 1, b >> 1);
    } else if (isAEven && !isBEven) {
        return gcd(a >> 1, b);
    } else if (!isAEven && isBEven) {
        return gcd(a, b >> 1);
    } else {
        return gcd(b, a - b);
    }
}

进制转换

1. 7 进制

504. Base 7 (Easy)

https://leetcode-cn.com/problems/base-7/

2. 16 进制

405. Convert a Number to Hexadecimal (Easy)

https://leetcode-cn.com/problems/convert-a-number-to-hexadecimal/

可使用位运算加快速度!

class Solution {
public:
    string s[16]={"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
    string toHex(int num) {
        if(num==0) return "0";
        string res;
        while(num&&res.size()<8){   //注意限制长度:针对负数
            res=s[num&0xf]+res;
            num>>=4;                  
        }
        return res;
    }
};

3. 26 进制

168. Excel Sheet Column Title (Easy)

https://leetcode-cn.com/problems/excel-sheet-column-title/

class Solution {
public:
    string convertToTitle(int n) {
        string res;
        while(n--){
            res=(char)('A'+n%26)+res;
            n/=26;
        }
        return res;
    }
};

阶乘

1. 统计阶乘尾部有多少个 0

172. Factorial Trailing Zeroes (Easy)

https://leetcode-cn.com/problems/factorial-trailing-zeroes/

尾部的 0 2 * 5 得来,2 的数量明显多于 5 的数量,因此只要统计有多少个 5 即可。

对于一个数 N,它所包含 5 的个数为:N/5 + N/52 + N/53 + ...,其中 N/5 表示不大于 N 的数中 5 的倍数贡献一个 5N/52 表示不大于 N 的数中 52 的倍数再贡献一个 5 ...

class Solution {
public:
    int trailingZeroes(int n) {
        int five=0;
        while(n/=5)
            five+=n;
        return five;
    }
};

字符串加法减法

1. 二进制加法

67. Add Binary (Easy)

https://leetcode-cn.com/problems/add-binary/

2. 字符串加法

415. Add Strings (Easy)

https://leetcode-cn.com/problems/add-strings/

相遇问题

1. 改变数组元素使所有的数组元素都相等

462. Minimum Moves to Equal Array Elements II (Medium)

https://leetcode-cn.com/problems/minimum-moves-to-equal-array-elements-ii

移动距离最小的方式是所有元素都移动到中位数。

设 m 为中位数。a 和 b 是 m 两边的两个元素,且 b > a。要使 a 和 b 相等,它们总共移动的次数为 b - a,这个值等于 (b - m) + (m - a),也就是把这两个数移动到中位数的移动次数。

设数组长度为 N,则可以找到 N/2 对 a 和 b 的组合,使它们都移动到 m 的位置。

1.	先排序
class Solution {
public:
    int minMoves2(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int sum=0;
        for(int l=0,h=nums.size()-1;l<h;l++,h--)
            sum+=nums[h]-nums[l];
        return sum;
    }
};
2.	快排
class Solution {
public:
    void swap(int &a,int &b){
        int t=a;
        a=b;
        b=t;
    }
    int partition(vector<int>& nums,int left,int right){
        int privot=nums[right];
        int i=left,j=right-1;
        while(true){
            while(i<right&&nums[i]<privot) i++; //重要
            while(j>=left&&nums[j]>=privot) j--;
            if(i>=j) break;
            swap(nums[i],nums[j]);
        }
        swap(nums[i],nums[right]);
        return i;
    }
    int select(vector<int>& nums,int k){
        int l=0,r=nums.size()-1;
        while(l<r){
            int index=partition(nums,l,r);
            if(index==k) break;
            else if(index<k) l=index+1;
            else r=index-1;
        }
        return nums[k];
    }
    int minMoves2(vector<int>& nums) {
        int mid=select(nums,nums.size()>>1),sum=0;
        for(int num:nums) 
           sum+=abs(num-mid);
        return sum;
    }
};

多数投票问题

1. 数组中出现次数多于 n / 2 的元素

169. Majority Element (Easy)

https://leetcode-cn.com/problems/majority-element/

  1. 先排序,取中位数

用库函数/快排,同上一题。

  1. 剔除元素法

在原序列中去除两个不同的元素后,原序列中的多数元素在新序列中还是多数元素。

1)将数组的第一个元素设置为多数元素P,并记录count = 1

2)将数组后面的数与P比较,若相等count+1,不相等count-1,

3)若count减到0,便表示该元素出现次数太少,将其和后面一个不相等的元素剔除,再次重置c和count

4)继续此操作,直到比较到最后count都不为0,则c就为多数元素。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int major=nums[0],cnt=0;
        for(int num:nums){
            if(cnt==0) major=num;
            if(major==num) cnt++;
            else cnt--;
        }
        return major;
    }
};

其它

1. 平方数

367. Valid Perfect Square (Easy)

https://leetcode-cn.com/problems/valid-perfect-square/

1.	直接计算:时间复杂度为O(logN)
class Solution {
public:
    bool isPerfectSquare(int num) {
        for(int i=1;i<=num/i;i++)
            if(i*i==num) return true;
        return false;
    }
};
2.	减法:时间复杂度为O(logN)
平方序列:1,4,9,16,..
间隔:3,5,7,...
间隔为等差数列,使用这个特性可以得到从 1 开始的平方序列。
class Solution {
public:
    bool isPerfectSquare(int num) {
        for(int i=1;num>0;i+=2)
            num-=i;
        return num==0;
    }
};

2. 3 的 n 次方

326. Power of Three (Easy)

https://leetcode-cn.com/problems/power-of-three/

3. 乘积数组

238. Product of Array Except Self (Medium)

https://leetcode-cn.com/problems/product-of-array-except-self/

4. 找出数组中的乘积最大的三个数

628. Maximum Product of Three Numbers (Easy)

https://leetcode-cn.com/problems/maximum-product-of-three-numbers/

1.	先排序
我们将数组进行升序排序,
	如果数组中所有的元素都是非负数,那么答案即为最后三个元素的乘积。
	如果数组中出现了负数,那么我们还需要考虑乘积中包含负数的情况,显然选择最小的两个负数和最大的一个正数是最优的,即为前两个元素与最后一个元素的乘积。
class Solution {
public:
    int maximumProduct(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        return max(nums[0]*nums[1]*nums[nums.size()-1],nums[nums.size()-3]*nums[nums.size()-2]*nums[nums.size()-1]);        
    }
};
2.	线性扫描
在方法一中,我们实际上只要求出数组中最大的三个数以及最小的两个数,因此我们可以不用排序,用线性扫描直接得出这五个数。
class Solution {
public:
    int maximumProduct(vector<int>& nums) {
        int min1=INT_MAX,min2=INT_MAX,max1=INT_MIN,max2=INT_MIN,max3=INT_MIN;
        for(int num:nums){
            if(num<min1){
                min2=min1;
                min1=num;
            }else if(num<min2)
                min2=num;
            if(num>max1){
                max3=max2;
                max2=max1;
                max1=num;
            }else if(num>max2){
                max3=max2;
                max2=num;
            }else if(num>max3)
                max3=num;
        }
        return max(min1*min2*max1,max3*max2*max1);
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值