Leetcode题解-算法-数学

每一个数都可以分解成素数的乘积。

令 x = 2m0 * 3m1 * 5m2 * 7m3 * 11m4 * …
令 y = 2n0 * 3n1 * 5n2 * 7n3 * 11n4 * …
如果 x 整除 y(y mod x == 0),则对于所有 i,mi <= 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、进制转换

1.1 小于 n 的所有素数

204. Count Primes(Easy)
Count the number of prime numbers less than a non-negative number, n.

Example:

Input: 10
Output: 4
Explanation: There are 4 prime numbers less than 10, they are 2, 3, 5, 7.

问题分析:
从 2 开始,每碰见一个素数,就将该素数的所有整数倍的数排除。

class Solution {
public:
    int countPrimes(int n) {
        vector<bool>prime(n+1,true);
        int cnt=0;
        for(int i=2;i<n;i++)
        {
            if(prime[i])
            {
                cnt++;
                for(int j=2;j*i<n;j++)
                    prime[j*i]=false;
            }
        }
        return cnt;
    }
};

1.2 7进制

504. Base 7(Easy)
Given an integer, return its base 7 string representation.

Example 1:

Input: 100
Output: “202”

Example 2:

Input: -7
Output: “-10”

Note: The input will be in range of [-1e7, 1e7].

问题分析:
将十进制的数转化为七进制的数,每次将原数取余,再除以十,这里需要考虑负数,负号单独考虑。

class Solution {
public:
    string convertToBase7(int num) {
        if(num==0)
            return "0";
        string str="";
        bool isNegative=false;
        while(num<0)
        {
            num=-num;
            isNegative=true;
        }
        while(num>0)
        {
            str=to_string(num%7)+str;;
            num=num/7;
        }
        if(isNegative)
            str="-"+str;
        return str;
    }
};

1.3 16进制

405. Convert a Number to Hexadecimal(Easy)
Given an integer, write an algorithm to convert it to hexadecimal. For negative integer, two’s complement method is used.

Note:

  1. All letters in hexadecimal (a-f) must be in lowercase.
  2. The hexadecimal string must not contain extra leading 0s. If the number is zero, it is represented by a single zero character ‘0’; otherwise, the first character in the hexadecimal string will not be the zero character.
  3. The given number is guaranteed to fit within the range of a 32-bit signed integer.
  4. You must not use any method provided by the library which converts/formats the number to hex directly.

Example 1:

Input:
26
Output:
“1a”

Example 2:

Input:
-1
Output:
“ffffffff”

class Solution {
public:
    string toHex(int num) {
        if(num==0)
            return "0";
        char a[]= {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        unsigned int num_uns = (num >= 0) ? num : INT_MAX*2 + 2 + num;//转为为无符号数
        string result;
        while(num_uns>0)
        {
            result=a[num_uns%16]+result;
            num_uns=num_uns/16;
        }
        return result;
    }
};

可以不创建数组,用ASCII码操作选取字符。

class Solution {
public:
    string toHex(int num) {
        if(num==0)
            return "0";
        unsigned int num_uns = (num >= 0) ? num : INT_MAX*2 + 2 + num;//转为为无符号数
        string result;
        while(num_uns>0)
        {
            int tmp=num_uns%16;
            result=(tmp<=9?(char)('0'+tmp):(char)('a'+tmp-10))+result;//ASCII码操作
            num_uns=num_uns/16;
        }
        return result;
    }
};

1.4 26进制

168. Excel Sheet Column Title(Easy)
Given a positive integer, return its corresponding column title as appear in an Excel sheet.

For example:

1 -> A
2 -> B
3 -> C

26 -> Z
27 -> AA
28 -> AB

Example 1:

Input: 1
Output: “A”

Example 2:

Input: 28
Output: “AB”

Example 3:

Input: 701
Output: “ZY”

问题分析:
可以理解为将一个数转化为26进制的数,这里用递归进行操作,因为是从 1 开始计算的,而不是从 0 开始,因此需要对 n 执行 -1 操作。

class Solution {
public:
    string convertToTitle(int n) {
    if (n == 0)
		return "";
        n--;
	return convertToTitle(n/26)+(char)('A' + n % 26);//注意这里的ASCII码操作
    }
};

写成循环也是可以的

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

2、阶乘

2.1 阶乘的尾部有多少0

172. Factorial Trailing Zeroes(Easy)
Given an integer n, return the number of trailing zeroes in n!.
Example 1:

Input: 3
Output: 0
Explanation: 3! = 6, no trailing zero.

Example 2:

Input: 5
Output: 1
Explanation: 5! = 120, one trailing zero.

Note: Your solution should be in logarithmic time complexity.

问题分析:
尾部的 0 由 2 * 5 得来,2 的数量明显多于 5 的数量,因此只要统计 5 的个数。

对于 N 的阶乘,N!=1×2×3×4×5×6×……×N

  • 从能拿出 5 的每个数中拿出一个 5,可以拿出 5 的数为,5,10,15,20,25……,也就是说能拿出5的数有N/5个,这些数拿出一个 5,变为1,2,3,4,5,6,……N/5
  • 再从这些数中能拿出 5 的每个数中拿出一个 5,能拿出5的数有N/52个,这些数变为1,2,3,4,5,6,……N/52
  • 继续拿,直到所有的数都拿不出5,即N/5n<=0

所以能拿出的 5 的总数为N/5 + N/52 + N/53 + …

class Solution {
public:
    int trailingZeroes(int n) {
        int sum=0;
        for(int i=n;i>0;i=i/5)
            sum+=i/5;
        return sum;
    }
};

3、字符串加法减法

3.1 二进制加法

67. Add Binary(Easy)
Given two binary strings, return their sum (also a binary string).The input strings are both non-empty and contains only characters 1 or 0.

Example 1:

Input: a = “11”, b = “1”
Output: “100”

Example 2:

Input: a = “1010”, b = “1011”
Output: “10101”

给另个字符串表示两个二进制数,计算二进制加法的和。
问题分析
从买两个二进制数的最后一位开始计算,计算每一位二者相加的值(包括进位)。

class Solution {
public:
    string addBinary(string a, string b) {
        string res="";
        int cur=0;
        int i=a.size()-1,j=b.size()-1;
        while(cur>0||i>=0||j>=0)
        {
            if(i>=0 && a[i--]=='1')
                cur++;
            if(j>=0 && b[j--]=='1')
                cur++;
            if(cur%2)
                res+='1';
            else
                res+='0';
            cur=cur/2;
        }
        for(int i=0,j=res.size()-1;i<j;i++,j--)
            swap(res[i],res[j]);
        return res;
    }
};

3.2 字符串加法

415. Add Strings(Easy)
Given two non-negative integers num1 and num2 represented as string, return the sum of num1 and num2.

给定两个字符串,表示两个非负的整数,求两个字符串相加的整数和。

class Solution {
public:
    string addStrings(string num1, string num2) {
        string res="";
        int i=num1.size()-1,j=num2.size()-1;
        int cur=0;
        while(cur>0||i>=0||j>=0)
        {
            if(i>=0)
                cur+=num1[i--]-'0';
            if(j>=0)
                cur+=num2[j--]-'0';
            res+=to_string(cur%10);
            cur=cur/10;
        }
        for(int i=0,j=res.size()-1;i<j;i++,j--)
            swap(res[i],res[j]);
        return res;
    }
};

4、相遇问题

4.1 移动最少的次数使所有的数组元素都相等

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

Given a non-empty integer array, find the minimum number of moves required to make all array elements equal, where a move is incrementing a selected element by 1 or decrementing a selected element by 1.

You may assume the array’s length is at most 10,000.

Example:

Input:
[1,2,3]
Output:
2
Explanation:
Only two moves are needed (remember each move increments or decrements one element):
[1,2,3] => [2,2,3] => [2,2,2]

方法一:排序
将元素排序,最终肯定是要将所有的元素移动到中间的位置,首位两个数移动的距离之和为 nums[j]-nums[i]。

class Solution {
public:
    int minMoves2(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int i=0,j=nums.size()-1;
        int sum=0;
        for(;i<j;i++,j--)
            sum+=(nums[j]-nums[i]);
        return sum;
    }
};

复杂度:O(nlogn)

方法二:快速排序找中位数

class Solution {
public:
    int minMoves2(vector<int>& nums) {
        int sum=0;
        int k=findKthSmallest(nums,nums.size()/2);
        for(int num:nums)
            sum+=abs(num-k);
        return sum;
    }
    
    int findKthSmallest(vector<int>& nums, int k) {
        int location=k;
        int left=0,right=nums.size()-1;
        while(left<right)
        {
            int privot=paititio(nums,left,right);
            if(privot==location)
                break;
            else if(privot>location)
                right=privot-1;
            else
                left=privot+1;
        }
        return nums[location];
    }
    
    int paititio(vector<int>& nums,int left,int right)
    {
        int i = left, j = right + 1;
        while (true) 
        {
            while (nums[++i] < nums[left] && i < right);
            while (nums[--j] > nums[left] && j > left);
            if (i >= j)
                break;
            swap(nums[i], nums[j]);
        }
        swap(nums[left], nums[j]);
        return j;
    }
};

复杂度:O(n)

5、多数投票问题

5.1找出数组中出现次数大于 n/2 的元素

169. Majority Element(Easy)
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.You may assume that the array is non-empty and the majority element always exist in the array.
Example 1:

Input: [3,2,3]
Output: 3

Example 2:

Input: [2,2,1,1,1,2,2]
Output: 2

方法一:排序,取中间的元素

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        return nums[nums.size()/2];
    }
};

复杂度:O(nlogn)

方法二:抵消不相等的两个数
把不相等的数抵消,剩下的一定是出现次数大于 n/2 的数。

例子:[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]
假设第一个数为出现次数大于 n/2 的数,计算该数出现的次数比其他数出现的次数多多少,每当全部抵消时,重新假设出现次数大于 n/2 的数。
初始化:major=7,cnt=0
在下标为 5 的时候抵消,重新赋值major=5,cnt=0
在下标为 7 的时候抵消,重新赋值major=5,cnt=0
在下标为 11 的时候抵消,重新赋值major=7,cnt=0
最终major=7,cnt=4

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

复杂度:O(n)

6、其他

6.1 判断一个数是不是整数的平方

367. Valid Perfect Square(Easy)
Given a positive integer num, write a function which returns True if num is a perfect square else False.
Note: Do not use any built-in library function such as sqrt.

Example 1:

Input: 16
Output: true

Example 2:

Input: 14
Output: false

方法一:二分

class Solution {
public:
    bool isPerfectSquare(int num) {
        int left=1,right=num;
        double mid;
        while(left<=right)
        {
            mid=left+(right-left)/2;
            double tmp=num/mid;
            if(tmp==mid)
                return true;
            else if(mid>tmp)
                right=mid-1;
            else
                left=mid+1;
        }
        return false;
    }
};

方法一
平方数序列为:1,4,9,16,25……
两数间隔为:3,5,7,9……

两个平方数之间的间隔为等差数列
对目标数依次减 1,3,5,7,9……,如果可以减到 0,说明是平方数。

class Solution {
public:
    bool isPerfectSquare(int num) {
        int cnt=1;
        while(num>0)
        {
            num-=cnt;
            cnt+=2;
        }
        return num==0?true:false;
    }
};

6.2 判断一个数是不是 3 的 n 次方

326. Power of Three(Easy)

class Solution {
public:
    bool isPowerOfThree(int n) {
        if(n<1)return false;
        while(n>1)
        {
            if(n%3)return false;
            n=n/3;
        }
        return true;
    }
};

6.3 乘积数组

238. Product of Array Except Self(Medium)
给一个 n 个整数的数组,返回一个数组,使得 output [i] 等于除 nums [i] 之外的所有 nums 元素的乘积。

要求时间复杂度为 O(n),不能使用除法,空间复杂度为 O(1),不包括返回的而数组。

Example:

Input: [1,2,3,4]
Output: [24,12,8,6]

方法一:分别构造左右乘积数组

先介绍一种空间复杂度为 O(n) 的方法,定义两个数组 left[] 和 right[],left[i] 表示 i 元素之前的所有元素的乘积,right[i] 表示 i 元素之后的所有的元素乘积。则 left[] * right[] 就是除 i 元素外所有元素的乘积。
在这里插入图片描述

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n = nums.size();
        vector<int>left(n, 1);
        vector<int>right(n, 1);
        vector<int>res(n, 1);
        for(int i = 1; i < n; i++)
            left[i] = left[i-1] * nums[i-1];
        for(int i = n-2; i >= 0; i--)
            right[i] = right[i+1] * nums[i+1];
        for(int i = 0; i < n; i++)
            res[i] = left[i] * right[i];
        return res;
    }
};

方法二:空间优化
将返回数组计算为左乘积数组,left[i] 就表示 i 元素之前的所有元素的乘积,从右向左遍历数组,每到一个位置,令整数right = right * nums[i+1],保证 right 等于该位置之后所有元素乘积。

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n = nums.size();
        vector<int>res(n, 1);
        for(int i = 1; i < n; i++)
            res[i] = res[i-1] * nums[i-1];
        int right = 1;
        
        for(int i = n-2; i >= 0; i--){
            right *= nums[i+1];
            res[i] = res[i] * right;
        }
        return res;
    }
};

6.4 数组中乘积最大的三个数

628. Maximum Product of Three Numbers(Easy)
Example 1:

Input: [1,2,3]
Output: 6

Example 2:

Input: [1,2,3,4]
Output: 24

解题思路:数组中可能会出现负数,找出数组中最大的三个数 a1,a2,a3 和最小的两个数 b1,b2,结果为 max(a1a2a3, a1b1b2)

class Solution {
public:
    int maximumProduct(vector<int>& nums) {
        int n = nums.size();
        int res = 1;
        vector<int>big(3,INT_MIN);
        vector<int>small(2,INT_MAX);
        for(int i = 0; i <n; i++){
            if(nums[i] > big[2]){
                if(nums[i] > big[0]){
                    big[2] = big[1];
                    big[1] = big[0];
                    big[0] = nums[i];
                }
                else if(nums[i] > big[1]){
                    big[2] = big[1];
                    big[1] = nums[i];
                }
                else if(nums[i] > big[2])
                    big[2] = nums[i];
            }
            if (nums[i] < small[1]){
                if(nums[i] < small[0]){
                    small[1] = small[0];
                    small[0] = nums[i];
                }
                else if(nums[i] < small[1])
                    small[1] = nums[i];
            }
        }
        return max(big[0]*big[1]*big[2], big[0]*small[0]*small[1]);
    }
};
发布了248 篇原创文章 · 获赞 115 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/happyjacob/article/details/89291147
今日推荐