Leetcode Question Series (1) - Solving Mathematical Problems Cleverly

1 Introduction

  When answering questions on Leetcode, you will encounter some mathematical problems that cannot be solved using data structures and common algorithms. These problems can be solved quickly by cleverly applying some mathematical knowledge. Below we will introduce some common techniques for solving mathematical problems, including but not limited to: greatest common divisor and least common multiple, sieve method and tabulation, congruence theorem, inclusion-exclusion principle, median theorem, etc.

2. Greatest common divisor and least common multiple

  For two positive integers a and b, the product of their greatest common divisor and least common multiple is equal to the product of the two numbers:

Greatest common divisor × least common multiple = a × b

2.1 Greatest common divisor

  Euclidean division, also known as Euclidean algorithm, is a method of finding the greatest common divisor (GCD) of two numbers. The specific method is: divide the larger number by the smaller number, and then use Divide the divisor from the remainder (the first remainder) that appears, then divide the first remainder from the remainder (the second remainder), and so on until the final remainder is 0. Then the final divisor is the maximum of the two numbers. common divisor. (The kth remainder is the remainder that appears in the kth calculation)

int GCD(int a,int b){
    
    //辗转相除法   被除数/除数=商
	if(a%b==0) return b;//这里的a b大小不重要,因为即使a<b,到了下面又会换回来
	else return GCD(b,a%b);
}

If you want the greatest common divisor of n numbers, you can first find the greatest common divisor of two numbers, then use the greatest common divisor of the two numbers and the third number to find the greatest common divisor, and then use the greatest common divisor of the first three numbers. number and the fourth to find the greatest common divisor, and so on.

2.2 Least common multiple

  You can find the least common multiple (LCM) of two numbers by multiplying them and dividing them by their greatest common divisor:

int LCM(int a,int b){
    
    //辗转相除法   被除数/除数=商
	return (a*b)/GCD(a,b);
}

Finding the least common multiple of n numbers is the same as finding the greatest common divisor of n numbers.

Example: 1979. Find the greatest common divisor of an array (simple)

Problem description:
  Given an integer array nums, return the greatest common divisor of the largest number and the smallest number in the array. The greatest common divisor of the two numbers is the largest positive integer that can be divided by the two numbers.

Input and output examples:

Input: nums = [2,5,6,9,10]
Output: 2
Explanation:
The smallest number in nums is 2
The largest number in nums is 10
The greatest common divisor of 2 and 10 is 2
Hint:

  • 2 <= nums.length <= 1000
  • 1 <= nums[i] <= 1000

Solution:
  You only need to simulate the meaning of the question, find the maximum and minimum values ​​in the array (you can use the C++ built-in function, or you can write your own for loop), and then use the GCD function above to find it.

int GCD(int a,int b){
    
    
     if(a%b==0)return b;
     else return GCD(b,a%b);
}
int findGCD(vector<int>& nums) {
    
    
     int n=nums.size();
     int max = *max_element(nums.begin(),nums.end());
     int min = *min_element(nums.begin(),nums.end());
     return GCD(min,max);
}

PIPIOJ example: 1352. The least common multiple (simple) of multiple numbers.
  For answers, see: Solving Mathematical Problems Cleverly - Links to Exercises and Answers

3. Screening and tabulation

  The Sieve of Ehrlich is a very commonly used method to determine whether an integer is prime. Use the Ehrlich sieve method to filter out prime numbers within n: traverse from 1 to n, assuming that the current traversal reaches i, mark all integers that are less than n and are multiples of i as composite numbers; after the traversal is completed, no integers are marked as The composite number is a prime number. The time complexity is: O(nloglogn).

q[1]=1;//1为合数
for(int i=2;i<n;i++){
    
    
	if(q[i]==0){
    
    //q[i]=0表示i为质数
		for(int j=2*i;j<n;j+=i)q[j]=1;
	}
}

Example: 204 counting prime numbers (medium)

Problem description:
  Given an integer n, return the number of all prime numbers less than a non-negative integer n.

Input and output examples:

Input: n = 10
Output: 4
Explanation: There are 4 prime numbers less than 10, they are 2, 3, 5, 7.
Tip: 0 <= n <= 5*10 6

Solution:
  According to the Sieve of Ehrlich method, the composite numbers within 1~n are marked. Each time the mark is marked, the number of prime numbers is reduced by one.

 int countPrimes(int n) {
    
    
        if(n<=2)return 0;
        int num=n-2;//去除1和n本身
        vector<int> q(n,0);
        q[1]=1;
        for(int i=2;i<n;i++){
    
    
            if(q[i]==0){
    
    //q[i]=0表示i为质数
                for(int j=2*i;j<n;j+=i){
    
    
                    if(q[j]==0){
    
    //避免重复
                    	q[j]=1;
                    	num--;
                    }
                }
            }
        }
        return num;
   }

PIPIOJ example question: 1044. Chinese Valentine's Day (simple)
  solution, see: Solving Mathematical Problems Cleverly - Practice Question Links and Answers

4. Base conversion

  Any type of base conversion can refer to the decimal to binary form and use short division for conversion. Take 13 and 10 below as examples to show the specific conversion process.

13 converted to binary 10 converted to binary
13/2=6…1 10/2=5…0
6/2=3…0 5/2=2…1
3/2=1…1 2/2=1…0
1/2=0…1 1/2=0…1
1101 1010

The operation ends when the quotient is 0, and the remainders are connected from bottom to top to obtain the final converted binary value.
Example: 504. Seven base numbers (simple)

Problem description:
  Given an integer num, convert it into a hexadecimal number and output it in the form of a string.

Input and output examples:

Input: num = 100
Output: "202"
Explanation: The hexadecimal representation of 100 is: 100=2 * 7 2 +0 * 7 1 +2 * 7 0
Hint:

  • -107 <= num <= 107

Solution:
  According to short division, record the remainder each time, and finally reverse the string to get the answer.

string convertToBase7(int num) {
    
    
        string ans;
        int tmp = abs(num);
        if(num==0)return "0";
        while(tmp){
    
    
            int remainder=tmp%7;//记录余数
            ans+='0'+remainder;//将整数转换为字符类型
            tmp/=7;
        }
        reverse(ans.begin(),ans.end());
        return num<0 ? "-"+ans : ans;
}

Example: 1017. Negative Binary Conversion (Medium)
  For solutions, see: Solving Math Problems Cleverly - Practice Question Links and Solutions

5. Angle problem (1rad=180°/π)

  Regarding the angle issue, here are some notes:
(1) The three functions sin, cos, and tan can only be used in radians, not angles.
(2) The return values ​​of the three functions asin, acos, and atan are all in radians.
(3) PI = acos(-1), if it is used in the OJ question, please use this formula to find π.
Example: PIPIOJ1154. Radius and volume of a sphere (simple)

Question description:
  Input the center point of the ball and the coordinates of a point on the ball, and calculate the radius and volume of the ball.

Input and output examples:

Input: The input contains multiple sets of test cases. For each set of test cases, input the center point of the ball and the coordinates of a point on the ball, input in the following form: x0 y0 z0 x1 y1 z1
Output: For each set of input, output the radius and volume of the ball, and the results are retained to three decimal places. .Explanation
: Input: 0 0 0 1 1 1 Output: 1.732 21.766

Solution:
  Pay attention to the expression of π and the accuracy issue. Radius of a sphere: Euclidean distance in three dimensions. The volume of the sphere: V=4/3 π R 3 , the surface area of ​​the sphere: S=4 π R 2 .

#include<bits/stdc++.h> 
using namespace std;
const double PI = acos(-1);
int main(){
    
    
    double x0,y0,z0,x1,y1,z1;
    while(scanf("%lf%lf%lf%lf%lf%lf",&x0,&y0,&z0,&x1,&y1,&z1)!=EOF){
    
    
        double r,v; 
        r = sqrt((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1)+(z0-z1)*(z0-z1));
        v = 4.0/3 * PI * pow(r,3);
        printf("%.3f %.3f\n",r,v); 
    }
    return 0;
}

6. Equality theorem

  (1) (a±b)%mod = (a%mod±b%mod)%mod. Note: If it is subtraction, a%mod-b%mod may be a negative number, so the following + mod: (a%mod-b%mod+mod)%mod (2) (a b)%mod = (a
  % mod b%mod)%mod.
Example question: PIPIOJ1103.PIPI math question 1 (simple)

Problem description:
  PIPI now has a large number N, and he wants to know the result of this number modulo p.

Input and output examples:

Input: The input contains multiple sets of test cases. For each group of test cases, it contains a positive integer N (N<10 10000 ) and a modulus p (0<p<2 32 )
. Output: For each group of test cases, output N%p
. Explanation:
Sample input:
10 30
30 10
100 33Sample
output:
10
0
1

Solution:
  Note that the input is a large number, which needs to be read in as a string. It can be easily solved by using the congruence theorem.

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
char s[N];
int main()
{
    
    
	long long p;
	while(scanf("%s%lld",s,&p)!=EOF){
    
    
		int n=strlen(s);
		long long tmp=0;
		for(int i=0;i<n;i++){
    
    
			tmp = (tmp*10+s[i]-'0')%p;
		}
		printf("%lld\n",tmp);
	}
	return 0;
}

7.Principle of inclusion and exclusion

  (1) The formula of the inclusion-exclusion relationship between two sets:

|A∪B| = |A|+|B| - |A∩B |(∩: overlapping part)

  (2) The inclusion-exclusion relationship formula of three sets:

|A∪B∪C| = |A|+|B|+|C| - |A∩B| - |B∩C| - |C∩A| + |A∩B∩C|

Example: PIPIOJ1341.PIPI Learning Tolerance and Exclusion (Medium)

Problem description:
  Given positive integers n, a, b, c. Let you find the number of numbers from 1 to n that can be divided by a or b or c.

Input and output examples:

Input: Input contains multiple sets of data. Each set of data contains three numbers n, a, b, c. (1<=a, b, c, n <=1e9).
Output: For each set of test cases, output the number of numbers from 1 to n that can be divided by a, b, or c.
Explanation:
Sample input:
1000 2 3 5
100 2 3 5
Sample output:
734
74

  The number of numbers in 1~n that can be divided by a is: n/a, and the number of numbers that can be divided by a or b at the same time is: n/ (the least common multiple of a and b).

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b){
    
    
	if(a%b==0)return b;
	else return gcd(b,a%b);
}
ll lcm(ll a,ll b){
    
    
	return a/gcd(a,b) * b;
}
int main()
{
    
    
	ll n,a,b,c;
	while(scanf("%lld%lld%lld%lld",&n,&a,&b,&c)!=EOF){
    
    
		ll ans=0;
		ans = n/a + n/b + n/c - n/lcm(a,b)- n/lcm(a,c)- n/lcm(b,c) + n/lcm(a,lcm(b,c));
		printf("%lld\n",ans);
	}
	return 0;
}

8. Distance measurement formula

  For two points (x1, y1) and (x2, y2) on the plane coordinates:
(1) Euclidean distance calculation formula: sqrt((x1-x2) (x1-x2)+(y1-y2) (y1-y2) )
(2) Manhattan distance calculation formula: |x1-x2|+|y1-y2| has nothing to do with the calculation order of rows and columns.
Example: PIPIOJ1025: Shortest distance (simple)

Title description:
  Xiao Wang and Xiao Ming are good friends. They each have an initial position p and a constant speed v at the beginning. Starting from time 0, they start walking at a constant speed from the initial position. Please tell me the two steps during walking. What is the shortest distance between people.

Input and output examples:

输入 :
第一行输入T代表测试样例数目。
对于每个样例,第一行包含四个整数 x1,y1,x2,y2,表示人的起点(x1,y1),(x2,y2)。
第二行是四个整数u1,v1,u2,v2,表示人的初始速度(u1,v1),(u2,v2)(分别为x轴和y轴方向的分速度)。
T <= 1000 , x1,y1,x2,y2,u1,v1,u2,v2的绝对值不大于1000。
输出: 对于每个样例,输出一行。“Case i: d”。i 代表案例编号,d代表答案,四舍五入到小数点后6位。
解释:
样例输入:
1
1 1 2 2
1 1 2 2
样例输出:
Case 1: 1.414214

  直接计算两个人的欧氏距离:小王:(x1+u1t,y1+v1t),小明:(x2+u2t,y2+v2t)

#include<bits/stdc++.h>
using namespace std;
int main()
{
    
    
	int T;
	scanf("%d",&T);
	int id=1;
	while(T--){
    
    
		double x1,x2,y1,y2,v1,v2,u1,u2,ans;
		scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
		scanf("%lf%lf%lf%lf",&u1,&v1,&u2,&v2);
		// ans=sqrt((x1+u1*t-x2-u2*t)^2+(y1+v1*t-y2-v2*t)^2) 
		// 整理得:ans = sqrt(((x1-x2)+(u1-u2)*t)^2+((y1-y2)+(v1-v2)*t)^2) 
		// 化简       =[(u1-u2)^2+(v1-v2)^2]*t^2+ 2*((x1-x2)*(u1-u2)+(y1-y2)*(v1-v2))+(x1-x2)^2+(y1-y2)^2
		double a,b,c;
		a = (u1-u2)*(u1-u2)+(v1-v2)*(v1-v2);
		b = 2*((x1-x2)*(u1-u2)+(y1-y2)*(v1-v2));
		c = (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
		if(a==0||-b/(2*a)<=0)ans=c;
		else ans = c-b*b/(4*a);
		printf("Case %d: %.6f\n",id++,sqrt(ans));
	}
	return 0;
}

9.中位数定理

  现在已知数轴上有n个点 x1,x2 … xn,如何找到一个点x,使得|x-x1|+|x-x2|+…+|x-xn| (或者是|x1-x|+|x2-x|+…+|xn-x|) 的值最小?
  答案:其实这个点x就是这些数的中位数。证明网上有很多,这里就不证明了
例题:PIPIOJ1018: 士兵排阵(中等)

题目描述:
  在一个划分成网格的操场上, n个士兵散乱地站在网格点上。 网格点由整数坐标(x,y)表示。士兵们可以沿网格边上、 下、 左、 右移动一步, 但在同一时刻任一网格点上只能有一名士兵。按照军官的命令,士兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),…,(x+n-1,y)。如何选择 x 和 y的值才能使士兵们以最少的总移动步数排成一列。 计算使所有士兵排成一行需要的最少移动步数。
输入

输入输出样例:

输入 :
多组测试用例。对于每一组测试用例,第1行是士兵数 n, 1≤n≤10000。 接下来 n行是士兵的初始位置, 每行有2个整数 x和 y,-10000≤x, y≤10000。
输出: 数据的输出为一行, 表示士兵排成一行需要的最少移动步数。
解释:
样例输入:
5
1 2
2 2
1 3
3 -2
3 3
样例输出:
8

  该题我们首先应该看出士兵在 x 轴和 y轴的移动是无关的(行列无关)。士兵只能横着移动和竖着移动,所以在 x 轴上的移动和 y 轴上的移动是无关的。所以我们对行列分开考虑。
  假设n个士兵的原始位置为 : (X1,Y1), (X2,Y2), (X3,Y3), (X4,Y4)… (Xn,Yn),士兵的最终位置为: (X,Y), (X+1,Y), (X+2,Y), (X+3,Y), (X+4,Y)… (X+n-1,Y)。
  对于y轴: 先对所有的Y坐标从小到大排序,排序后,为了方便描述,依然用Y1,Y2,Y3…Yn,Yi代表士兵的位置(已经排好序的),假如最后所有士兵都在y轴为Y的坐标上,则变成求|Y1-Y|+|Y2-Y|+|Y3-Y|+……|Yn-1-Y|+|Yn-Y|的最小值,根据中位数定理,我们知道 Y 取 Y1,Y2…Yn中位数时能够得到表达式的最小值。
  对于x轴: 先对所有的X坐标从小到大排序,排序后,为了方便描述,依然用X1,X2,X3…Xn,Xi代表士兵的位置(已经排好序的),最终士兵站的位置为X,X+1,X+2……X+n-1,那么即是求|X1-X|+|X2-(X+1)|+|X3-(X+2)|+……|Xn-(X+n-1)|的最小值。变形,即为|X1-X|+|(X2-1)-X|+|(X3-2)-X|+…+|(Xn-(n-1))-X|,利用中位数定理,X即为X1,X2-1,X3-2……Xn-(n-1)的中位数,据此可以求得X方向的最小移动步数。
  X轴方向移动步数和Y轴方向移动步数加起来即为最终结果。

#include<bits/stdc++.h>
using namespace std;
const int N=10003;
int x[N],y[N];
int main(){
    
    
    int n;
    while(scanf("%d",&n)!=EOF){
    
    
        int ans=0;
        for(int i=0;i<n;i++) scanf("%d%d",&x[i],&y[i]);
        sort(y,y+n);
        for(int i=0;i<n;i++) ans+=abs(y[i]-y[n/2]);
        sort(x,x+n);
        for(int i=0;i<n;i++) x[i]=x[i]-i;
        sort(x,x+n);
        for(int i=0;i<n;i++) ans+=abs(x[i]-x[n/2]);
        printf("%d\n",ans);
    }
    return 0;
}

每日古诗一首

如梦令·昨夜雨疏风骤
宋·李清照
昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,
却道海棠依旧。知否,知否?应是绿肥红瘦。

——2023.03.23

渔家傲·秋思骤
宋·范仲淹
塞下秋来风景异,衡阳雁去无留意。
四面边生连角起,千嶂里,长烟落日孤城闭。
浊酒一杯家万里,燕然未勒归无计。
羌管悠悠霜满地,人不寐,将军白发征夫泪。

——2023.04.08

Guess you like

Origin blog.csdn.net/Ratib/article/details/129730097