[LeetCode] Valid Triangle Number 合法的三角形個數
Given an array consists of non-negative integers, your task is to count the number of triplets chosen from the array that can make triangles if we take them as side lengths of a triangle.
Example 1:
Input: [2,2,3,4] Output: 3 Explanation: Valid combinations are: 2,3,4 (using the first 2) 2,3,4 (using the second 2) 2,2,3
Note:
- The length of the given array won't exceed 1000.
- The integers in the given array are in the range of [0, 1000].
這道題給了我們一堆數字,問我們能組成多少個正確的三角形,我們初中就知道三角形的性質,任意兩條邊之和要大於第三邊。那麼問題其實就變成了找出所有這樣的三個數字,使得任意兩個數字之和都大於第三個數字。那麼可以轉變一下,三個數字中如果較小的兩個數字之和大於第三個數字,那麼任意兩個數字之和都大於第三個數字,這很好證明,因為第三個數字是最大的,所以它加上任意一個數肯定大於另一個數。這樣,我們就先要給陣列排序,博主最先嚐試了暴力破解法,結果TLE了(不要吐槽博主哈,博主就是喜歡霸王硬上弓~),後來優化的方法是先確定前兩個數,將這兩個數之和sum作為目標值,然後用二分查詢法來快速確定第一個小於目標值的數,這種情況屬於博主之前的部落格
解法一:
class Solution { public: int triangleNumber(vector<int>& nums) { int res = 0, n = nums.size(); sort(nums.begin(), nums.end()); for (int i = 0; i < n; ++i) {for (int j = i + 1; j < n; ++j) { int sum = nums[i] + nums[j], left = j + 1, right = n; while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] < sum) left = mid + 1; else right = mid; } res += right - 1 - j; } } return res; } };
其實還有更進一步優化的方法,用的是博主之前那篇3Sum Smaller裡面的解法二,明明博主以前都總結過,換個題目情景就又沒想到,看來博主的舉一反三能力還是有所欠缺啊。沒辦法,只能繼續刻意練習了。這種方法能將時間複雜度優化到O(n2), 感覺很叼了。思路是排序之後,從數字末尾開始往前遍歷,將left指向首數字,將right之前遍歷到的數字的前面一個數字,然後如果left小於right就進行迴圈,迴圈裡面判斷如果left指向的數加上right指向的數大於當前的數字的話,那麼right到left之間的數字都可以組成三角形,這是為啥呢,相當於此時確定了i和right的位置,可以將left向右移到right的位置,中間經過的數都大於left指向的數,所以都能組成三角形,就說這思路叼不叼!加完之後,right自減一,即向左移動一位。如果left和right指向的數字之和不大於nums[i],那麼left自增1,即向右移動一位,參見程式碼如下:
解法二:
class Solution { public: int triangleNumber(vector<int>& nums) { int res = 0, n = nums.size(); sort(nums.begin(), nums.end()); for (int i = n - 1; i >= 2; --i) { int left = 0, right = i - 1; while (left < right) { if (nums[left] + nums[right] > nums[i]) { res += right - left; --right; } else { ++left; } } } return res; } };
類似題目:
參考資料: