[LeetCode] Increasing Triplet Subsequence 遞增的三元子序列
Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array.
Formally the function should:
Return true if there exists i, j, k
such that arr[i] < arr[j] < arr[k] given 0 ≤ i < j < k ≤ n-1 else return false.
Your algorithm should run in O(n) time complexity and O(1
Examples:
Given [1, 2, 3, 4, 5]
,
return true
.
Given [5, 4, 3, 2, 1]
,
return false
.
Credits:
Special thanks to @DjangoUnchained for adding this problem and creating all test cases.
這道題讓我們求一個無序陣列中是否有任意三個數字是遞增關係的,我最先相處的方法是用一個dp陣列,dp[i]表示在i位置之前小於等於nums[i]的數字的個數(包括其本身),我們初始化dp陣列都為1,然後我們開始遍歷原陣列,對當前數字nums[i],我們遍歷其之前的所有數字,如果之前某個數字nums[j]小於nums[i],那麼我們更新dp[i] = max(dp[i], dp[j] + 1),如果此時dp[i]到3了,則返回true,若遍歷完成,則返回false,參見程式碼如下:
解法一:
// Dumped, brute force class Solution { public: bool increasingTriplet(vector<int>& nums) { vector<int> dp(nums.size(), 1); for (int i = 0; i < nums.size(); ++i) { for (int j = 0; j < i; ++j) { if (nums[j] < nums[i]) { dp[i]= max(dp[i], dp[j] + 1); if (dp[i] >= 3) return true; } } } return false; } };
但是題目中要求我們O(n)的時間複雜度和O(1)的空間複雜度,上面的那種方法一條都沒滿足,所以白寫了。我們下面來看滿足題意的方法,這個思路是使用兩個指標m1和m2,初始化為整型最大值,我們遍歷陣列,如果m1大於等於當前數字,則將當前數字賦給m1;如果m1小於當前數字且m2大於等於當前數字,那麼將當前數字賦給m2,一旦m2被更新了,說明一定會有一個數小於m2,那麼我們就成功的組成了一個長度為2的遞增子序列,所以我們一旦遍歷到比m2還大的數,我們直接返回ture。如果我們遇到比m1小的數,還是要更新m1,有可能的話也要更新m2為更小的值,畢竟m2的值越小,能組成長度為3的遞增序列的可能性越大,參見程式碼如下:
解法二:
class Solution { public: bool increasingTriplet(vector<int>& nums) { int m1 = INT_MAX, m2 = INT_MAX; for (auto a : nums) { if (m1 >= a) m1 = a; else if (m2 >= a) m2 = a; else return true; } return false; } };
如果覺得上面的解法不容易想出來,那麼如果能想出下面這種解法,估計面試官也會為你點贊。這種方法的雖然不滿足常數空間的要求,但是作為對暴力搜尋的優化,也是一種非常好的解題思路。這個解法的思路是建立兩個陣列,forward陣列和backward陣列,其中forward[i]表示[0, i]之間最小的數,backward[i]表示[i, n-1]之間最大的數,那麼對於任意一個位置i,如果滿足 forward[i] < nums[i] < backward[i],則表示這個遞增三元子序列存在,舉個例子來看吧,比如:
nums: 8 3 5 1 6
foward: 8 3 3 1 1
backward: 8 6 6 6 6
我們發現數字5滿足forward[i] < nums[i] < backward[i],所以三元子序列存在。
解法三:
class Solution { public: bool increasingTriplet(vector<int>& nums) { if (nums.size() < 3) return false; int n = nums.size(); vector<int> f(n, nums[0]), b(n, nums.back()); for (int i = 1; i < n; ++i) { f[i] = min(f[i - 1], nums[i]); } for (int i = n - 2; i >= 0; --i) { b[i] = max(b[i + 1], nums[i]); } for (int i = 0; i < n; ++i) { if (nums[i] > f[i] && nums[i] < b[i]) return true; } return false; } };
參考資料: