Tag Archives: 数学

LeetCode Rectangle Area

223. Rectangle Area 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. 223. Rectangle Area


给定两个矩形,要求这两个矩形的面积和,如果有重叠区域,需要减去重叠区域的面积。因为这两个矩形的关系是rectilinear的,也就是像图中互相平行分布的,不会出现一个矩形斜着和另一个矩形相交(这样重叠区域可能是三角形或梯形)。 此题的难点是怎样判断两个矩形是否相交,肉眼很容易判断,但是怎样写一个通用程序呢。我原来的思路是先判断哪个矩形面积更小,然后判断小面积矩形是否有顶点落在大面积矩形内部,如果有则相交,否则不想交。 网上有一种比较简单的判断方法,它不判断两个矩形是否相交,而是判断两个矩形是否不相交,方法是判断一个矩形是否完全落在另一个矩形的上、下、左、右侧。因为矩形是rectilinear的,所以每侧判断只需一语句就行,比如判断图中右边那个矩形是否完全在左边矩形的右边,只需判断E>=C是否成立。 还有一种判断方法是,把两个矩形的顶点分别投影到x轴和y轴,如果投影到两个轴上的两条线段都不相交,则矩形没有重叠。 重叠之后求交集区域的面积也不难,比如上图,交集矩形x轴左端点是A,E的较大值,右端点是C,G的较小值,y轴类似。 完整代码如下:

class Solution {
public:
    int computeArea(int A, int B, int C, int D, int E, int F, int G, int H)
    {
        int area = (C – A) * (D – B) + (G – E) * (H – F);
        if (E >= C || // 右
            H <= B || // 下
            G <= A || // 左
            F >= D) // 上
            return area;
        return area – (min(C, G) – max(A, E)) * (min(D, H) – max(B, F));
    }
};

本代码提交AC,用时22MS。

二刷。方法相同,代码如下:

typedef long long ll;
class Solution {
public:
	int computeArea(int A, int B, int C, int D, int E, int F, int G, int H) {
		ll area1 = (C - A)*(D - B);
		ll area2 = (G - E)*(H - F);
		ll area3 = 0;
		if (E >= C || F >= D || G <= A || H <= B) {
			//没有重叠
		}
		else {
			int ae = max(A, E), cg = min(C, G);
			int bf = max(B, F), dh = min(D, H);
			area3 = abs(cg - ae)*abs(dh - bf);
		}
		return area1 + area2 - area3;
	}
};

本代码提交AC,用时12MS。

LeetCode Integer Break

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.


给定一个数n,要求把其拆分成至少两个数的和,使得他们的乘积最大。 数学题,没啥思路,参考网上题解。 把0~10的结果先列出来找找规律:

  • 0:0
  • 1:0
  • 2:1=1*1
  • 3:2=2*1
  • 4:4=2*2
  • 5:6=3*2
  • 6:9=3*3
  • 7:12=3*4
  • 8:18=3*3*2
  • 9:27=3*3*3
  • 10:36=3*3*4

可以发现,n从5开始,都至少分解出来一个3,可以推断的是,当n=11时,在10的基础上,把最后一个4改成5,然后5又可以分解成3*2,所以11=3+3+3+2使得乘积最大。 4只能分解出2+2,1+3的乘积是3小于2*2;5可以分解出3+2,所以也有3。也就是说,当n大于4时,不断分解出3来,直到剩余的数小于4为止。所以有如下代码:

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

本代码提交AC,用时0MS。
再次观察上述规律,n=10的结果是n=7=10-3的结果乘以3;n=9的结果也是n=6=9-3的结果乘以3。可以推断,n的结果是(n-3)的结果乘以3。所以先列出前几个结果,后面的结果通过其前3的结果乘以3推导得到。代码如下:

class Solution {
public:
    int integerBreak(int n)
    {
        vector<int> dp = { 0, 0, 1, 2, 4, 6, 9 };
        for (int i = 7; i <= n; ++i)
            dp.push_back(dp[i – 3] * 3);
        return dp[n];
    }
};

本代码提交AC,用时3MS。

LeetCode Perfect Squares

279. Perfect Squares

Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.

Example 1:

Input: n = 12
Output: 3 
Explanation: 12 = 4 + 4 + 4.

Example 2:

Input: n = 13 Output: 2 Explanation: 13 = 4 + 9. 279. Perfect Squares 

本题问一个数n最少能由多少个完全平方数加和得到。 使用动态规划,设dp[i]表示数i最少能由多少个完全平方数加和得到,那么由i再加一个平方数j得到的数i+j*j可以由dp[i]+1个平方数组成。即递推公式为:
$$dp[i+j*j]=min(dp[i]+1)$$
具体实现时,我们是先求dp数组中前面的值dp[i],然后不断缩小并更新dp[i+j*j]的结果。代码如下:

class Solution {
public:
    int numSquares(int n)
    {
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 0; i <= n; ++i) {
            for (int j = 1; i + j * j <= n; ++j) {
                dp[i + j * j] = min(dp[i + j * j], dp[i] + 1);
            }
        }
        return dp[n];
    }
};

本代码提交AC,用时99MS。
这题还可以用纯数学的方法来解,涉及到四平方和定理,数学方法暂时就不研究了。

二刷,对于数i,其最大的平方数就是(sqrt(i))^2,所以从sqrt(i)到1都试一试,从哪个降下去的数目最少。对于第一个样例,sqrt(12)=3,所以依次尝试3,2,1,发现2降下去的数目最少,因为3降下去就是9+1+1+1,要4个数,比2降下去4+4+4多。

class Solution {
public:
	int numSquares(int n) {
		vector<int> dp(n + 1, n);
		dp[0] = 0;
		dp[1] = 1;
		for (int i = 2; i <= n; ++i) {
			int max_sqrt = sqrt(i);
			for (int j = max_sqrt; j >= 1; --j) {
				dp[i] = min(dp[i], dp[i - j * j] + 1);
			}
		}
		return dp[n];
	}
};

本代码提交AC,用时204MS。

三刷。转换为背包问题,先把所有可能的平方数求出来放到数组squares中,把每个平方数当做一件商品,限制背包容量为n,问最少拿多少件商品能填满背包。则对于每件商品,选择拿或者不拿。完整代码如下:

class Solution {
public:
    int numSquares(int n) {
        vector<int> squares = {0};
        for(int i = 1; i * i <= n; ++i) {
            squares.push_back(i * i);
        }
        int m = squares.size();
        vector<vector<int>> dp(m, vector<int>(n + 1, 0));
        for(int i = 1; i < m; ++i) {
            for(int j = 1; j <= n; ++j) {
                if(i == 1) dp[i][j] = j;
                else {
                    dp[i][j] = dp[i - 1][j];
                    if(j >= squares[i]) dp[i][j] = min(dp[i][j], dp[i][j - squares[i]] + 1);
                }
            }
        }
        return dp[m - 1][n];
    }
};

本代码提交AC,用时688MS。还可以进一步优化,dp数组可以变成一维的。

LeetCode Minimum Moves to Equal Array Elements II

LeetCode Minimum Moves to Equal Array Elements II 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]

LeetCode Minimum Moves to Equal Array Elements的改编题。这次每次只能改变一个数,让其增大1或者减小1,问最小需要多少次操作能使所有数字相等。 其实看样例就能猜到,最终统一的那个数是原数组中的中位数。这就好办了,对原数组排个序,然后累加所有元素和中位数的绝对值就可以了。 代码如下: [cpp] class Solution { public: int minMoves2(vector<int>& nums) { sort(nums.begin(), nums.end()); int ans = 0, mid = nums[nums.size() / 2]; for (const int& i : nums)ans += abs(i – mid); return ans; } }; [/cpp] 本代码提交AC,用时22MS。 排好序之后还有另一种方法求操作数,比如排好序是1,3,5,7,9,最终所有数都要变成5。之前的做法是所有数和5作差求绝对值加和,现在可以这样做,1到5需要(5-1)次操作,9变成5需要(9-5)次操作,累加就是(5-1)+(9-5)=(9-1),所以我们取排序之后的首位元素,互相作差即可。这就看起来和中位数没关系了。 代码如下: [cpp] class Solution { public: int minMoves2(vector<int>& nums) { sort(nums.begin(), nums.end()); int ans = 0, i = 0, j = nums.size() – 1; while (i < j) { ans += nums[j–] – nums[i++]; } return ans; } }; [/cpp] 本代码提交AC,用时19MS。 既然是要求中位数,其实不用对数组排序都可以做到,就是之前的求第k大数LeetCode Kth Largest Element in an Array,直接借用那个函数即可。STL也有类似的函数nth_element。 [cpp] class Solution { private: int helper(vector<int>& nums, int left, int right, int k) { if (left == right)return nums[left]; int pivot = nums[left]; int l = left, r = right; while (l < r) { while (l < r&&nums[r] <= pivot)–r; if (l >= r)break; nums[l] = nums[r]; while (l < r&&nums[l] >= pivot)++l; if (l >= r)break; nums[r] = nums[l]; } nums[l] = pivot; if (l + 1 == k)return pivot; if (k < l + 1)return helper(nums, left, l – 1, k); else return helper(nums, l + 1, right, k); } public: int minMoves2(vector<int>& nums) { //int ans = 0, mid = helper(nums, 0, nums.size() – 1, nums.size() / 2 + 1); nth_element(nums.begin(), nums.begin() + nums.size() / 2, nums.end()); int ans = 0, mid = nums[nums.size() / 2]; for (const int& i : nums)ans += abs(i – mid); return ans; } }; [/cpp] 本代码提交AC,用时13MS。]]>

LeetCode Minimum Moves to Equal Array Elements

LeetCode Minimum Moves to Equal Array Elements Given a non-empty integer array of size n, find the minimum number of moves required to make all array elements equal, where a move is incrementing n – 1 elements by 1. Example:

Input:
[1,2,3]
Output:
3
Explanation:
Only three moves are needed (remember each move increments two elements):
[1,2,3]  =>  [2,3,3]  =>  [3,4,3]  =>  [4,4,4]

给定一个长度为n数组,每次操作是把其中n-1个数加1,问需要多少次操作才能使数组中的所有元素都相等。 很有意思的数学题。常规思路是,每次找出数组中的最大数,然后对剩下的n-1个数加1,如此循环直到所有元素相等。但是这种解法每次操作都需要O(n)的复杂度,肯定会TLE。 另一个思路,对除最大数之外的所有数加1,相当于其他数不变,把最大数减1。所以可以先找到数组中的最小数,然后累加数组中各元素与最小值之差即可。 代码如下: [cpp] class Solution { public: int minMoves(vector<int>& nums) { int m = INT_MAX, ans = 0; for (const int& i : nums)m = min(m, i); for (const int& i : nums)ans += i – m; return ans; } }; [/cpp] 本代码提交AC,用时56MS。]]>

LeetCode Number of Boomerangs

LeetCode Number of Boomerangs Given n points in the plane that are all pairwise distinct, a “boomerang” is a tuple of points (i, j, k) such that the distance between iand j equals the distance between i and k (the order of the tuple matters). Find the number of boomerangs. You may assume that n will be at most 500 and coordinates of points are all in the range [-10000, 10000] (inclusive). Example:

Input:
[[0,0],[1,0],[2,0]]
Output:
2
Explanation:
The two boomerangs are [[1,0],[0,0],[2,0]] and [[1,0],[2,0],[0,0]]

给定一堆点集,问回飞镖的个数。一个回飞镖是一个三点集(i,j,k),且满足i到j和k的距离相等。 如果和i距离相等的点有n个,则这样的三点集有$$A_n^2=n(n-1)$$,也就是从n个点中拿两个点做排列。所以问题就转换为对每个点,都求其他所有点和该点的距离,求到距离相等的点的个数n,然后代入公式计算。 代码如下: [cpp] class Solution { public: int numberOfBoomerangs(vector<pair<int, int>>& points) { int ans = 0; for (int i = 0; i < points.size(); ++i) { unordered_map<int, int> dist_cnt; for (int j = 0; j < points.size(); ++j) { int xdiff = points[i].first – points[j].first; int ydiff = points[i].second – points[j].second; ++dist_cnt[xdiff*xdiff + ydiff*ydiff]; } for (auto it = dist_cnt.begin(); it != dist_cnt.end(); ++it)ans += it->second*(it->second – 1); } return ans; } }; [/cpp] 本代码提交AC,用时369MS。 因为题中说到所有点都是不相同的,所以第7行没必要限制j!=i,即使j==i,算出来的距离是0,dist_cnt[0]=1,也就是只有点x一个点和自己的距离是0。到第12行计算排列数时,n(n-1)=0,所以没关系。]]>

LeetCode Fraction to Recurring Decimal

166. Fraction to Recurring Decimal

Given two integers representing the numerator and denominator of a fraction, return the fraction in string format.

If the fractional part is repeating, enclose the repeating part in parentheses.

Example 1:

Input: numerator = 1, denominator = 2
Output: "0.5"

Example 2:

Input: numerator = 2, denominator = 1
Output: "2"

Example 3:

Input: numerator = 2, denominator = 3
Output: "0.(6)"

本题要把两数相除的结果转换为小数字符串,对于无限循环小数,把循环部分用括号括起来。 参考欣欣的做法。 首先判断一下符号位,如果异号则添加负号,然后把两数都转换为正数,注意因为int的负数个数比正数个数多一个-2147483648,abs(-2147483648)=-2147483648还是负数,因为int最大的正数是2147483647,导致转换为正数时溢出成-2147483648。所以需要先把分子分母转换为long long再取绝对值。

整数部分就是分子除以分母。如果没有余数,就整除了,直接返回结果;否则添加小数点,开始处理小数部分。小数部分判断是否有无限循环小数周期的方法是,用一个map保留每次除法的余数,以及对应的商在结果字符串中的位置,如果以后某次的余数在这个map中,就表明小数部分要开始循环了,通过map找到循环的起始位置,添加左括号,并在结果字符串末尾添加有括号就结束了。比如4/9,用长除法,第一次上0,添加小数点,余数为4。余数乘10再除以9,即40/9=4,余数还是4,因为之前有出现过4的余数,所以开始循环了。 有些除法能除尽,除尽的标志就是余数为0,所以也需要在循环的时候判断余数是否为0。 需要注意的一点是,不能对商建立hash表,比如某个小数是3.(5883),循环周期是5883,如果对商建立hash,则出现第二个8时,会误以为开始循环周期了,导致结果3.5(8),而正确的循环周期应该是5883。正确的做法是对余数建立hash表。 完整代码如下:

class Solution {
public:
    string fractionToDecimal(int numerator, int denominator)
    {
        if (numerator == 0)
            return "0";
        string ans = "";
        if ((numerator < 0) ^ (denominator < 0))
            ans = "-";
        long long num = llabs((long long)numerator), denom = llabs((long long)denominator);
        ans += to_string(num / denom);
        if (num % denom == 0)
            return ans;
        ans += ".";
        unordered_map<int, int> hash;
        long long reminder = num % denom;
        while (hash.find(reminder) == hash.end()) {
            hash[reminder] = ans.size();
            reminder *= 10;
            ans += to_string(reminder / denom);
            reminder %= denom;
            if (reminder == 0)
                return ans;
        }
        ans.insert(hash[reminder], "(");
        ans += ")";
        return ans;
    }
};

本代码提交AC,用时3MS。

二刷。相同思路:

class Solution {
public:
	string fractionToDecimal(int num, int denom) {

		long long numerator = num, denominator = denom;

		if (numerator == 0)return "0";
		if (denominator == 1)return to_string(numerator);
		if (denominator == -1)return to_string(-numerator);

		bool pos = true;
		if (numerator < 0) {
			numerator = -numerator;
			pos = !pos;
		}
		if (denominator < 0) {
			denominator = -denominator;
			pos = !pos;
		}

		unordered_map<int, int> hash;
		hash[numerator] = 0;
		vector<int> ans;
		
		int rep_start = -1;
		while (true) {
			int div = numerator / denominator;
			ans.push_back(div);
			numerator -= div * denominator;
			if (numerator == 0)break;
			numerator *= 10;
			if (hash.find(numerator) != hash.end()) {
				rep_start = hash[numerator];
				break;
			}
			else {
				hash[numerator] = ans.size();
			}
		}

		string frac = pos ? "" : "-";
		if (ans.size() == 1) {
			return frac + to_string(ans[0]);
		}
		frac += (to_string(ans[0]) + ".");
		for (int i = 1; i < ans.size(); ++i) {
			if (i == rep_start)frac += "(";
			frac += to_string(ans[i]);
		}
		if (rep_start >= 0)frac += ")";
		return frac;
	}
};

本代码提交AC,用时4MS。

LeetCode Count Primes

204. Count Primes

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.

本题要求从1~n共有多少个素数。Hint里一步步深入写得非常详细了,简要概括一下,有两种方法,一种是常规的从1~n一个个判断是否为非数,另一种是比较巧妙的Hash方法。 常规方法。首先看看判断一个数n是否为素数的方法,因为如果n为合数,则n可以分解为p×q,又n=p×q=(√n)×(√n),假设p是较小数的话,则p≤(√n)。所以我们只需要从2~(√n)判断能否被n整除,时间复杂度为O(n0.5)。从1~n都需要判断是否为素数,所以总的时间复杂度为O(n1.5)。 完整代码如下:

class Solution {
private:
    bool isPrime(int x)
    {
        if (x <= 1)
            return false;
        for (int i = 2; i * i <= x; ++i) {
            if (x % i == 0)
                return false;
        }
        return true;
    }
public:
    int countPrimes(int n)
    {
        int ans = 0;
        for (int i = 1; i < n; ++i) {
            if (isPrime(i))
                ++ans;
        }
        return ans;
    }
};

本代码提交TLE,在n很大的时候无法通过测试。

后来看了Hint,解法还是很巧妙的。如果一个数n是素数,则n的倍数肯定不是素数了,比如2是素数,则4=2*2、6=2*3、8=2*4…这些数肯定就不是素数了。所以我们可以建立一个1~n的Hash表,表示一个数是否为素数。初始的时候Hash[1~n]=true。然后从2开始,如果Hash[i]为true,说明i是素数,则2*i, 3*i,…都不是素数了,即Hash[2*i], Hash[3*i]..=false。如果Hash[i]为false,说明i不是素数,则i可以分解为i=p*q,使得p(或q)为素数,则之前测试p时,已经把p的所有倍数都置为false了,而i的倍数肯定也是p的倍数,所以不需要对i的倍数再置false了。

循环的终止条件是i>(√n),和第一种解法的分析一样,如果某个合数x大于(√n),则其肯定有一个素因子i是小于(√n)的,所以在测试i时,就已经把x置为false了。

另外对于素数i,我们之前分析的是要把所有2*i, 3*i…都置为false。其实这里也可以优化,我们可以从i*i开始置为false,而不需要每次都从2*i开始。比如i=5,常规是要把所有2*5, 3*5, 4*5, 5*5,…都置为false,但其实2*5, 3*5, 4*5都已经被之前的素数2或3置为false了。所以每次我们只需要从i*i开始,下标以i递增的置为false就好。(从i*i到i*i+(i-1)之间的合数被比i小的合数置为false了)总的来说,这一题加速的技巧很多,完整代码如下:

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

本代码提交AC,用时29MS。

LeetCode Factorial Trailing Zeroes

172. Factorial Trailing Zeroes

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.


本题要求n的阶乘结果中末尾有多少个数字0。暴力方法就是先把n!求出来,然后不断除10算末尾0的个数,但是暴力方法无法满足log(n)的时间复杂度。 参考网上的题解:http://www.geeksforgeeks.org/count-trailing-zeroes-factorial-number/,分析得还是很详细的。 要产生一个尾数0,必须是10=2*5,所以算n!中min(2的素因子,5的素因子),就有多少个0。简单考察一下5!= (2 * 2 * 2 * 3 * 5),11!= (2 8 * 34 * 52 * 7),即n!中2的素因子个数肯定要比5的素因子个数要多,这个也是可以证明的。比如从5k+1到5(k+1),只多了一个5的素因子, 但是[5k+1, 5k+2]至少多了一个2的素因子,从[5k+3, 5k+4]又至少多了一个2的素因子。所以2的素因子要多于5的素因子。
下面就把问题转换为求n!中5的素因子的个数。

举一个例子20!=1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19*20,能够分解出5的素因子的数只有5,10,15,20,一共4=floor(20/5)。所以20!=2432902008176640000有4个尾数0。所以n!中5的素因子的个数是floor(n/5)?

且慢,如果n=25,floor(n/5)=5,但是25=5*5能分解出两个5的素因子,所以25!中应该有六个5的素因子。所以每增加一个25的倍数的数,5的素因子的个数加1;同理每增加一个125的倍数的数,5的素因子要加2,但因为125的倍数的数肯定是25的倍数的数,所以我们在求25的倍数的数的时候已经求过一次125倍数的数的个数了,结果就是5的个数=floor(n/5)+floor(n/25)+floor(n/125)+…
完整代码如下,注意i要是long long类型的,否则可能溢出。

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

本代码提交AC,用时3MS。
还有一种解法,思路是一样的:

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

第一种解法是固定分子不变,第二种解法是固定分母不变,结果是一样的。

LeetCode Arranging Coins

LeetCode Arranging Coins You have a total of n coins that you want to form in a staircase shape, where every k-th row must have exactly k coins. Given n, find the total number of full staircase rows that can be formed. n is a non-negative integer and fits within the range of a 32-bit signed integer. Example 1:

n = 5
The coins can form the following rows:
¤
¤ ¤
¤ ¤
Because the 3rd row is incomplete, we return 2.
Example 2:
n = 8
The coins can form the following rows:
¤
¤ ¤
¤ ¤ ¤
¤ ¤
Because the 4th row is incomplete, we return 3.

问n个硬币最多能摆成多少级台阶,每级台阶的硬币数是以1为步长递增的。其实就是求1+2+…+k<=n的最大的k。当然最简单的方法是暴力枚举[1,n]之间的k。 O(lgn)的方法是二分搜索满足上述不等式的最大的k。代码如下: [cpp] class Solution { public: int arrangeCoins(int n) { long long l = 0, r = n; while (l <= r) { long long m = (l + r) / 2; long long sum = (1 + m)*m / 2; if (n < sum)r = m – 1; else l = m + 1; } return r; } }; [/cpp] 本代码提交AC,用时35MS。 参考:http://bookshadow.com/weblog/2016/10/30/leetcode-arranging-coins/ P.S.感觉二分搜索的代码边界条件很麻烦。。。]]>