给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。
如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false 。
解题思路:回溯、动态规划、贪心
方法一:回溯(超时)
这个题类似于之前做过的求数组的递增子序列(长度大于3)的情况,并且只需要返回true和false。
代码和提交结果如下:
class Solution {
public boolean increasingTriplet(int[] nums) {
List<Integer> paths = new ArrayList();
return backTracking(paths,nums,0);
}
private boolean backTracking(List<Integer> paths , int[] nums , int startIndex){
if(paths.size() >= 3){
return true;
}
for(int i = startIndex ; i < nums.length ; i++){
HashSet<Integer> set = new HashSet();
if(!set.add(nums[i])||(!paths.isEmpty() && nums[i] <= paths.get(paths.size()-1))){
continue;
}
paths.add(nums[i]);
if(backTracking(paths,nums,i+1)){
return true;
}
paths.remove(paths.size()-1);
}
return false;
}
}
总结:数组的长度太长了,1000000,所以回溯超时很正常,刚开始没有看数据量直接写的代码。
方法二:动态规划
① 创建一个leftMin[nums.length]数组,用来存储数组每个位置的数左边的所有数以及包括自己本身在内的最小值。
② 创建一个rightMax[nums.length]数组,用来存储数组每个位置的数右边的所有数以及包括自己本身在内的最大值。
③ 遍历数组,如果nums[i] > leftMin[i-1] && nums[i] < rightMax[i+1],返回true,遍历完没有发现,返回false。
代码和提交结果如下:
class Solution {
public boolean increasingTriplet(int[] nums) {
int n = nums.length;
if (n < 3) {
return false;
}
int[] leftMin = new int[n];
leftMin[0] = nums[0];
for (int i = 1; i < n; i++) {
leftMin[i] = Math.min(leftMin[i - 1], nums[i]);
}
int[] rightMax = new int[n];
rightMax[n - 1] = nums[n - 1];
for (int i = n - 2; i >= 0; i--) {
rightMax[i] = Math.max(rightMax[i + 1], nums[i]);
}
for (int i = 1; i < n - 1; i++) {
if (nums[i] > leftMin[i - 1] && nums[i] < rightMax[i+1]) {
return true;
}
}
return false;
}
}
方法三:贪心 ,O(n)时间复杂度,也不需要单独开数组
定义两个变量 int one = nums[0];int two = Integer.MAX_VALUE,然后从 i = 1 开始遍历数组,如果nums[i] > two,返回 true ,如果 two > nums[i] > first , two = nums[i] , 如果 nums[i] < first,first = nums[i] ,遍历结束之后如果没能返回 true,则意味着没找到,就返回false。
代码和提交结果如下图所示:
class Solution {
public boolean increasingTriplet(int[] nums) {
//贪心
int first = nums[0];
int second = Integer.MAX_VALUE;
for(int i = 1 ; i < nums.length ;i++){
if(nums[i] > second){
return true;
}else if(nums[i] > first){
second = nums[i];
}else{
first = nums[i];
}
}
return false;
}
}
总结:回溯在使用的时候一定要注意数据量。