题目链接及描述
题目分析
最长递增子序列作为一道经典的动态规划题目,定义dp[i] 表示下标 i 时数组中存在的最长递增子序列,则可以确定递推公式:
if(nums[i] < nums[i]){
dp[i] = Math.max(dp[i], dp[j] + 1);
}
此题之前自己写过很多遍,对于这个思想比较熟悉,就不再赘述了。写这道题目的目的,是和334题的题目进行对比。 此题参考如下:
class Solution {
public int lengthOfLIS(int[] nums) {
int ans = Integer.MIN_VALUE;
int len = nums.length;
int[] dp = new int[len];
for(int i = 0; i < len; i++){
for(int j = 0; j < i; j++){
if(nums[j] < nums[i]){
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
ans = Math.max(ans, dp[i]);
}
return ans + 1;
}
}
对于334题,今天这是第一次写,首先想的一种做法是,采用回溯的思想,遍历构造所有长度对的3的数组,并且在构造的过程中验证是否满足nums[i] < nums[j] < nums[k] 如果不满足直接返回false,如果满足并且得到长度为3时终止循环,并且返回ture。
感觉使用回溯的做法有些许复杂,随后下班回到出租屋后又打开电脑,联想到【最长递增子序列】上面的那道题。本次无非就是寻找长度为3的最长递增子序列。于是乎使用上面的思路编写代码如下:
class Solution {
public boolean increasingTriplet(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
Arrays.fill(dp, 1);
for(int i = 0; i < n; i++){
for(int j = 0; j < i; j++){
if(nums[j] < nums[i]){
dp[i] = Math.max(dp[i], dp[j] + 1);
if(dp[i] == 3){
return true;
}
}
}
}
return false;
}
}
不幸的是,使用这种解法超时了,无法通过所有测试用测,将这个方法写出来就是为了扩展做题思路。
随后参考答案的写法看到一种贪心的做法,非常巧妙,由于题目是寻找到长度为3的递增数组,所有设置两个阈值first、second。参考图示如下:
遍历数组nums中的每一个数,如果num在(-oo,first] 之间,说明遇到比当前得到的最小的数更小的数,此时将num 赋值给first,如果num在(first,second] 之间,说明遇到了比当前第二小更小的数,此时将num 赋值给second。如果num 在(second,+oo)之间,说明遇到了第三大的数,此时返回true。终止循环。
需要将 first 和 second 初始化为Integer.MAX_VALUE。
代码编写
class Solution {
public boolean increasingTriplet(int[] nums) {
int first = Integer.MAX_VALUE, second = Integer.MAX_VALUE;
if(nums.length < 3){
return false;
}
for(int num : nums){
if(num <= first){
first = num;
}else if(num <= second){
second = num;
}else{
return true;
}
}
return false;
}
}