每日一題,雙指針的進階版
nums
1 <= nums.length <= 1000
0 <= nums[i] <= 1000
Input: nums = [2,2,3,4]
Output: 3
Explanation: Valid combinations are:
2,3,4 (using the first 2) 不同的2視為不同組合
2,3,4 (using the second 2)
2,2,3
nums[k]
,用雙指針 i
, j
在剩餘元素中尋找滿足條件的組合i
, j
nums[i] + nums[j] > nums[k]
時,說明從 i
到 j-1
的所有元素都能與 nums[j]
, nums[k]
組成三角形class Solution {
public:
int triangleNumber(vector<int>& nums) {
sort(nums.begin(), nums.end());
int result = 0;
int n = nums.size();
if(n < 3) return 0;
for(int i = 0; i < n - 2; i++){
for(int j = i+1; j < n - 1; j++){
for(int k = j+1; k < n; k++){
if(nums[i] + nums[j] > nums[k]) result += 1;
}
}
}
return result;
}
};
class Solution {
public:
int triangleNumber(vector<int>& nums) {
sort(nums.begin(), nums.end());
int result = 0;
int n = nums.size();
if(n < 3) return 0;
for(int k = n-1; k>=2; k--){
int i = 0, j = k-1; //從 k 比小一位的地方開始檢查
while(j > i){
if(nums[i] + nums[j] > nums[k]){
result += j-i; //因為最小的i都有三角形了,中間的i+1, i+2...必可以建構出三角形
j--;
}
else{
i++;
}
}
}
return result;
}
};
void test() {
Solution sol;
// Test Case 1
vector<int> nums1 = {2,2,3,4};
assert(sol.triangleNumber(nums1) == 3);
// Test Case 2
vector<int> nums2 = {4,2,3,4};
assert(sol.triangleNumber(nums2) == 4);
// Edge Cases
vector<int> nums3 = {1}; // 長度 < 3
assert(sol.triangleNumber(nums3) == 0);
vector<int> nums4 = {1,2}; // 長度 < 3
assert(sol.triangleNumber(nums4) == 0);
vector<int> nums5 = {1,1,3}; // 1+1 < 3,無法組成三角形
assert(sol.triangleNumber(nums5) == 0);
vector<int> nums6 = {3,4,5}; // 一個有效三角形
assert(sol.triangleNumber(nums6) == 1);
}
j
如果從 1 開始而不是從 i+1
開始,會造成重複計算。正確做法是確保 i < j < k
。a ≤ b ≤ c
,只需檢查 a + b > c
map<tuple<int,int,int>, int>
來存三個變數,但在這個問題中不是最佳方案,因為會增加時間和空間複雜度。ps. 部分內容經 AI 協助整理