# [LeetCode 611. Valid Triangle Number](https://leetcode.com/explore/challenge/card/july-leetcoding-challenge-2021/610/week-3-july-15th-july-21st/3815/)
### Daily challenge Jul 15, 2021 (MEDIAN)
>Given an integer array nums, return the number of triplets chosen from the array that can make triangles if we take them as side lengths of a triangle.
:::info
**Example 1:**
**Input:** nums = [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
:::
:::info
**Example 2:**
**Input:** nums = [4,2,3,4]
**Output:** 4
:::
:::warning
**Constraints:**
* 1 <= nums.length <= 1000
* 0 <= nums[i] <= 1000
:::
---
### Approach 1 : Brute Force :bulb:
**`TLE`** **`O(n^3)`**
將 **`nums`** 排序, 使用三層 for loop 遍歷所有可能。
若 **`nums[j] + nums[k] = nums[i]`**,則找到一個答案。
```cpp=1
class Solution {
public:
int triangleNumber(vector<int>& nums) {
// brute force --> TLE //
sort(nums.begin(), nums.end());
int count = 0;
for(int i=nums.size()-1; i>=2; i--){
for(int j=i-1; j>=1; j--){
for(int k=j-1; k>=0; k--){
if(nums[j] + nums[k] > nums[i]) count++;
}
}
}
return count;
}
};
```
### Approach 2 : Optimize Brute Force :bulb:
**`116 ms`** **`O(n^2)`**
既然已經將 **`nums`** `由小到大`排序過,我們就不需要檢查所有可能。
我們需要做的是先固定 *`(i, j)`*,找到 *`k`* 符合 **`num[i] + num[j] > num[k]`** 的`右極限`,此時 **`count += k - j - 1`** ( -1 因為 k^th^ 不符 )。
下一步,我們移動 *`j + 1`*,但是我們不須將 *`k`* 重製到 *`j + 1`*,因為 *`(j+1, k-1)`* 之間的可能都是符合的 (當 *`i`*、*`k`* 固定,且 *`nums[j] <= nums[j+1]`*,所有符合 *`nums[j]`* 的答案一定也符合 *`nums[j+1]`*),這樣可以剩下大量的多餘計算。
:::spoiler SEE MORE
>Initial state --->
>* i = 0
>* j = i + 1
>* k = i + 2
>
| 2 | 5 | 6 | 6 | 6 | 8 | 9 |NULL |
| -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
| i | j | k
>When *nums[k] = 8* ---> invalid
>
| 2 | 5 | 6 | 6 | 6 | 8 | 9 |NULL|
| -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
| i | j | | | | k | |
>Next state ---> **we don't need to reset k to j+1**
>
| 2 | 5 | 6 | 6 | 6 | 8 | 9 |NULL|
| -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
| i | | j | | | k |
:::
---
```cpp=1
class Solution {
public:
int triangleNumber(vector<int>& nums) {
// optimize
int size = nums.size();
int count = 0;
sort(nums.begin(), nums.end());
for(int i=0; i<size-2; i++){
if(nums[i] == 0) continue;
int k = i + 2;
for(int j=i+1; j<size-1; j++){
while(k < size && nums[i] + nums[j] > nums[k]) k++;
count += k - j - 1; // -1 becauce nums[k] is not the answer
}
}
return count;
}
};
```
### Approach 3 : MUCH FASTER (Use two pointer) :book:
**`84 ms`** **`O(n^2)`**
與 Approach 2 想法相同,但只使用一層迴圈以及兩個指標 ( left & right )。
>* If **`num[left] + num[right] > num[i]`** ---> **`count = right - left`**, and we can check other *smaller sum* ---> **`right - 1`**.
>* Otherwise, we have to a find *bigger sum* ---> **`left + 1`**.
```cpp=1
class Solution {
public:
int triangleNumber(vector<int>& nums) {
// much faster
int count = 0;
sort(nums.begin(), nums.end());
for(int i = nums.size()-1; i>=2; i--){
int left = 0, right = i-1;
while(left < right){
if(nums[left] + nums[right] > nums[i]){
count += right - left;
right--;
}
else left++;
}
}
return count;
}
};
```