算法题:递增的三元子序列
今天我看到一道挺有意思的算法题:递增的三元子序列。
首先,大家先别被题目中的“递增”和“三元子序列”这些词吓到,其实这类题目一旦理解了本质,往往不那么复杂,反倒很有挑战性。
题目的大意是这样的:给定一个整数数组,判断这个数组中是否存在一个递增的三元子序列,具体来说,就是是否可以从数组中挑选出三个数,满足这三个数的顺序是递增的。比如数组 [1, 2, 3] 就有递增的三元子序列 [1, 2, 3],但数组 [3, 1, 4, 2] 就没有。
那么,问题来了,我们该怎么高效地解决这个问题呢?下面我就用我对Java的理解,带大家走一遍解题过程。
首先,这个问题的核心是“找出三元子序列”。如果我们尝试使用暴力法,直接遍历每一组三个数,时间复杂度是O(n³)的,这显然不符合大多数情况下的要求,尤其是当数组长度很大的时候,性能就成了问题。
所以,我们要用更聪明的方法来做。具体来说,我们可以借助两个数组(或者变量)来优化问题的求解过程。我们可以将问题转换成:如何找出数组中某个位置的元素,可以比该位置前面的元素大,同时又能比该位置后面的元素小。
两个变量的策略
我想到了使用两个变量来表示当前元素前面的最小值和当前元素后面的最大值。
min:表示数组当前元素左边的最小值。 max:表示数组当前元素右边的最大值。
那么,如何高效地找出这样的三元子序列呢?
我们可以用一个循环遍历整个数组,对于每个元素,检查其是否能形成递增的三元子序列。如何做呢?你可以用贪心算法的思路来解决。
代码实现
public class Solution {
public boolean increasingTriplet(int[] nums) {
if (nums == null || nums.length < 3) {
return false;
}
int first = Integer.MAX_VALUE; // 最小的数
int second = Integer.MAX_VALUE; // 第二小的数
for (int num : nums) {
if (num <= first) {
// 更新最小的数
first = num;
} else if (num <= second) {
// 更新第二小的数
second = num;
} else {
// 如果当前数大于 first 和 second,那么就能构成递增的三元子序列
return true;
}
}
return false;
}
}
解释一下这段代码
首先,我们定义了两个变量
first
和second
。它们分别代表递增子序列中的第一个和第二个元素。初始化时,我们把它们都设置为Integer.MAX_VALUE
,这样它们可以任意接受数组中的值。然后,我们遍历数组,对于每个数字,我们有三种情况:
如果当前数字比 first
小,我们就更新first
。这说明我们找到了一个新的最小值。如果当前数字比 first
大,但是比second
小,我们更新second
。这意味着我们找到了一个比first
大但是比second
小的数字。如果当前数字比 second
还要大,那就说明我们找到了一个递增的三元子序列(first
<second
< 当前数字)。这时我们直接返回true
。
如果循环结束后我们还没有找到这样的三元子序列,说明数组中没有递增的三元子序列,返回 false
。
时间复杂度分析
时间复杂度:O(n),因为我们只遍历了一次数组,进行了常数时间的操作。 空间复杂度:O(1),只用了常数个变量来存储状态。
小结
通过这种方式,我们巧妙地避免了暴力法的O(n³)复杂度,使得算法的效率大大提高。而且,虽然题目看起来有点复杂,但通过贪心算法和巧妙的状态管理,我们就能轻松搞定它,真是既高效又简洁。
-END-
以上,就是今天的分享了,看完文章记得右下角给何老师点赞,也欢迎在评论区写下你的留言。