LeetCode 數學專題

268. Missing Number

Given an array containing n distinct numbers taken from 0, 1, 2, …, n, find the one that is missing from the array.

Example 1:

Input: [3,0,1]
Output: 2
Example 2:

Input: [9,6,4,2,3,5,7,0,1]
Output: 8
Note:
Your algorithm should run in linear runtime complexity. Could you implement it using only constant extra space complexity?

  • 思路

如果常數空間複雜度,可以用求和思想。

class Solution {
public:
    int missingNumber(vector<int>& nums) {
        int res = nums.size()*(nums.size()+1)/2;
        for(auto item:nums) res -= item;
        return res;
    }
};

62. Unique Paths

A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).

How many possible unique paths are there?

Above is a 7 x 3 grid. How many possible unique paths are there?

Example 1:

Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:

  1. Right -> Right -> Down
  2. Right -> Down -> Right
  3. Down -> Right -> Right
    Example 2:

Input: m = 7, n = 3
Output: 28

Constraints:

1 <= m, n <= 100
It’s guaranteed that the answer will be less than or equal to 2 * 10 ^ 9.

  • 思路

簡單的動態規劃問題。

class Solution {
public:
    int uniquePaths(int m, int n) {
        int dp[110][110];
        memset(dp,sizeof dp,0);
        for(int i=0;i<110;i++) dp[i][0] = 1;
        for(int i=0;i<110;i++) dp[0][i] = 1;
        for(int i=1;i<m;i++)
            for(int j=1;j<n;j++)
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
        return dp[m-1][n-1];
    }
};

還有一種組合數學的方法,其實結果就爲C(n-1,m+n-2),即在總步數m+n-2中選擇任意n-1步向着同一個方向。

記住求C(n-1,m+n-2),就想像自己在求楊輝三角!

class Solution {
public:
    int dp[110][110];
    int c(int m,int n){
        if(m == n || n == 0) return 1;
        if(dp[m][n] == 0) dp[m][n] = c(m-1,n) + c(m-1,n-1);
        return dp[m][n];
    }

    int uniquePaths(int m, int n) {
        return c(m+n-2,n-1);
    }
};

462. Minimum Moves to Equal Array Elements II – important

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]

  • 思路

這裏關鍵是如何選取要變化的目標值。

可以畫圖看,兩個數的話目標值必定在兩數之間纔可以保證操作次數最小。

那麼對於一組數,可以排序後最大值和最小值一組,第二大值和第二小值一組。。。如果保證每組操作次數都最小,那麼最終結果也就最小。

因此目標值就是中位數!

class Solution {
public:
    int minMoves2(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int mid = nums[nums.size()>>1];
        if(!nums.size()&1) mid = (mid + nums[nums.size()>>1-1])/2;
        
        int res = 0;
        for(auto item:nums) res += abs(item-mid);
        return res;
    }
};

458. Poor Pigs – important

There are 1000 buckets, one and only one of them is poisonous, while the rest are filled with water. They all look identical. If a pig drinks the poison it will die within 15 minutes. What is the minimum amount of pigs you need to figure out which bucket is poisonous within one hour?

Answer this question, and write an algorithm for the general case.

General case:

If there are n buckets and a pig drinking poison will die within m minutes, how many pigs (x) you need to figure out the poisonous bucket within p minutes? There is exactly one bucket with poison.

Note:

A pig can be allowed to drink simultaneously on as many buckets as one would like, and the feeding takes no time.
After a pig has instantly finished drinking buckets, there has to be a cool down time of m minutes. During this time, only observation is allowed and no feedings at all.
Any given bucket can be sampled an infinite number of times (by an unlimited number of pigs).

  • 思路

參考了評論大神的思路。對於兩個小豬,喝完毒藥15min 死去,在1h最多能檢驗多個水桶?答案是25桶,如下圖所示:
在這裏插入圖片描述
對於一隻豬,可以在1h之內最多喝 4次水(60/15),但是可以檢驗5個桶,如果前四次沒死,說明第5個桶有毒。

對於2只豬,現在可以讓一隻豬一下喝5桶水,如圖所示的一隻豬喝的五個,一隻豬喝的五個,這樣就可以確定哪個桶有毒。

對於3只豬,就是三維的 5 X 5 X 5 ,可以檢測125個桶。。。

class Solution {
public:
    int poorPigs(int buckets, int minutesToDie, int minutesToTest) {
        int pigs = 0;
        int d = minutesToTest / minutesToDie + 1;
        while(pow(d,pigs) < buckets) pigs ++;
        return pigs;
    }
};

319. Bulb Switcher

There are n bulbs that are initially off. You first turn on all the bulbs. Then, you turn off every second bulb. On the third round, you toggle every third bulb (turning on if it’s off or turning off if it’s on). For the i-th round, you toggle every i bulb. For the n-th round, you only toggle the last bulb. Find how many bulbs are on after n rounds.

Example:

Input: 3
Output: 1
Explanation:
At first, the three bulbs are [off, off, off].
After first round, the three bulbs are [on, on, on].
After second round, the three bulbs are [on, off, on].
After third round, the three bulbs are [on, off, off].

So you should return 1, because there is only one bulb is on.

  • 思路

每盞燈被按的次數就是編號的約數和。所以答案就是約數和爲奇數的數。
而約數和爲奇數的數就是平方數。所以問題轉化爲求1-n中的平方數個數。

而1-n中的平方數就是11,22,…,sqrt(n)*sqrt(n),那個數不就是sqrt(n)嗎!

class Solution {
public:
    int bulbSwitch(int n) {
        return sqrt(n);
    }
};

343. Integer Break

Given a positive integer n, break it into the sum of at least two positive integers and maximize the product of those integers. Return the maximum product you can get.

Example 1:

Input: 2
Output: 1
Explanation: 2 = 1 + 1, 1 × 1 = 1.
Example 2:

Input: 10
Output: 36
Explanation: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36.
Note: You may assume that n is not less than 2 and not larger than 58.

  • 思路

我還是無腦暴力流,當然還是用了dp數組保存了中間結果,因爲當n<=4的時候結果是小於n的,所以特殊考慮。

其他一旦分到n<=4時,直接返回n。

class Solution {
public:
    int dp[100010];
    
    int integerBreakL(int n){
    	if(n <= 4) return n;
    	if(dp[n]) return dp[n];
        int res = 0;
        for(int i=1;i<n;i++) 
			res = max(res,integerBreakL(i) * integerBreakL(n-i));
        dp[n] = res;
        return res;
    }
    
    int integerBreak(int n) {
        if(n == 2) return 1;
        if(n == 3) return 2;
        if(n == 4) return 4;
        return integerBreakL(n);
    }
};

或者這樣:

class Solution {
public:
    int dp[100010];
    int integerBreak(int n) {
        if(n == 2) return 1;
        if(n == 3) return 2;
        if(n == 4) return 4;
        for(int i=1;i<=4;i++) dp[i] = i;
        for(int i=5;i<=n;i++)
            for(int j=2;j<i;j++)
                dp[i] = max(dp[i],dp[j]*(i-j));
        return dp[n];
    }
};

評論大神的解法(咱們用點正常算法行不 orz)。求函數 y=(n/x)x(x>0) 的最大值,可得x=e時y最大,但只能分解成整數,故x取2或3,由於6=2+2+2=3+3,顯然23=8<9=32,故應分解爲多個3。

class Solution {
public:
	int integerBreak(int n) {
	    if(n == 2) return 1;
	    if(n == 3) return 2;
	    int a = 1;
	    while(n > 4){
	        n = n - 3;
	        a = a * 3;
	    }
	    return a * n;
	}
};

650. 2 Keys Keyboard – important

Initially on a notepad only one character ‘A’ is present. You can perform two operations on this notepad for each step:

Copy All: You can copy all the characters present on the notepad (partial copy is not allowed).
Paste: You can paste the characters which are copied last time.

Given a number n. You have to get exactly n ‘A’ on the notepad by performing the minimum number of steps permitted. Output the minimum number of steps to get n ‘A’.

Example 1:

Input: 3
Output: 3
Explanation:
Intitally, we have one character ‘A’.
In step 1, we use Copy All operation.
In step 2, we use Paste operation to get ‘AA’.
In step 3, we use Paste operation to get ‘AAA’.

Note:

The n will be in the range [1, 1000].

  • 思路

再次硬鋼。/_ \

class Solution {
public:
    int res = 99999999;
    void minStepsL(int n,int nowPaste,int nowChar,int tempStep){
        if(nowChar == n){
            res = min(res,tempStep);
            return;
        } 
        if(nowChar > n || nowPaste > n) return;
        if(nowPaste == 0) minStepsL(n,1,nowChar,tempStep+1);
        else{
        	// 複製粘貼
            minStepsL(n,nowChar,nowChar*2,tempStep+2);
            // 只粘貼
            minStepsL(n,nowPaste,nowChar+nowPaste,tempStep+1);
        } 
    }

    int minSteps(int n) {
        minStepsL(n,0,1,0);
        return res;
    }
};

看了大神評論沒想到上面的代碼還可以優化,優先複製粘貼,這樣得到的一定是最優的!

class Solution {
public:
    int res;
    bool minStepsL(int n,int nowPaste,int nowChar,int tempStep){
        if(nowChar == n){
            res = tempStep;
            return true;
        }
        if(nowChar > n) return false;
        if(minStepsL(n,nowChar,nowChar*2,tempStep+2)) return true;
        return minStepsL(n,nowPaste,nowChar+nowPaste,tempStep+1);
    }

    int minSteps(int n) {
        minStepsL(n,0,1,0);
        return res;
    }
};

這道題的正確數學解法應該是(還是參考了評論大神的解法):

class Solution {
public:
    int minSteps(int n) {
        if (n == 1) return 0; // 1不用操作
        int maxfactor = 1;
        
        // 這裏找出n大於1的最小公因數,打個比方
        // 18的最小公因數是3,那麼只用把6經過三次操作就可以變成18了
        for (int i = 2; i <= sqrt(n); i++) {
            if (n%i == 0) {
                maxfactor = i;
                break;
            }
        }
        if (maxfactor == 1) return n; //maxfactor爲1代表n是質數,質數沒有公因式,直接返回本身就ok
        return maxfactor + minSteps(n / maxfactor);//還是拿18做例子,變成18所需要的次數=3+變成6所需要的次數。
        //變成6所需要的次數=2+變成3所需要的次數。
        //3是質數,直接返回3,所以答案就是3+2+3=8
    }
};

223. Rectangle Area

Find the total area covered by two rectilinear rectangles in a 2D plane.

Each rectangle is defined by its bottom left corner and top right corner as shown in the figure.

Rectangle Area

Example:

Input: A = -3, B = 0, C = 3, D = 4, E = 0, F = -1, G = 9, H = 2
Output: 45
Note:

Assume that the total area is never beyond the maximum possible value of int.

  • 思路
class Solution {
public:
    int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
        int s1 = (A-C)*(B-D), s2 = (E-G)*(F-H);
        int topx = min(C,G), topy = min(D,H);
        int butx = max(A,E), buty = max(B,F);
        if(topx<butx || topy<buty) return s1+s2;
        int s3 = s1 - (topx-butx)*(topy-buty) + s2;
        return s3;
    }
};

829. Consecutive Numbers Sum – important

Given a positive integer N, how many ways can we write it as a sum of consecutive positive integers?

Example 1:

Input: 5
Output: 2
Explanation: 5 = 5 = 2 + 3
Example 2:

Input: 9
Output: 3
Explanation: 9 = 9 = 4 + 5 = 2 + 3 + 4
Example 3:

Input: 15
Output: 4
Explanation: 15 = 15 = 8 + 7 = 4 + 5 + 6 = 1 + 2 + 3 + 4 + 5
Note: 1 <= N <= 10 ^ 9.

  • 思路

繼續暴力,不過這次是真的超時了!43156417 這個數據是真的過不了了!
雙指針O(N2)的複雜度。(提前break了下,所以過了 130 / 170 個)

class Solution {
public:
    int consecutiveNumbersSum(int N) {
        int res = 0;
        for(int i=1;i<=N;i++)
            for(int j=i;j<=N;j++){
                int sum = 1ll*(i+j)*(j-i+1)/2;
                if(sum > N) break;
                if(sum == N) res++;
            }
        return res;
    }
};

891. Sum of Subsequence Widths

Given an array of integers A, consider all non-empty subsequences of A.

For any sequence S, let the width of S be the difference between the maximum and minimum element of S.

Return the sum of the widths of all subsequences of A.

As the answer may be very large, return the answer modulo 10^9 + 7.

Example 1:

Input: [2,1,3]
Output: 6
Explanation:
Subsequences are [1], [2], [3], [2,1], [2,3], [1,3], [2,1,3].
The corresponding widths are 0, 0, 0, 1, 1, 2, 2.
The sum of these widths is 6.

Note:

1 <= A.length <= 20000
1 <= A[i] <= 20000

  • 思路

完全沒思路,參考大神的題解:
https://leetcode-cn.com/problems/sum-of-subsequence-widths/solution/pai-xu-shu-xue-by-lucifer1004/

class Solution {
public:
    const int N = 1e9+7;
    int sumSubseqWidths(vector<int>& A) {
        vector<int> vec(A.size()+1);
        vec[0] = 1;
        for(int i=1;i<=A.size();i++) vec[i] = (vec[i-1] << 1) % N;
        
        sort(A.begin(),A.end());
        int res = 0;
        for(int i=0;i<A.size();i++){
            int temp = vec[i] - vec[A.size()-i-1];
            res = (res + 1ll * temp * A[i] % N) % N;
        }
        return res;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章