最先想到的思路,就是用一个 Map<Integer, List<Integer>>
,其中 key 对应下标 index
,value 为当 index_x > index
时,如果 nums[index_x] > nums[index]
,则将该 index_x
添加到 index
对应到链表中,该链表的作用就是收集在 index
右边的比 nums[index]
大的元素的标。
收集完成后,再一个一个的遍历收集的 list 中的元素 index_
,如果 index_
在 map 中存在,就表示 nums 中还有比 nums[index_]
大的数且该数的下标在 index_
的右边(即比 index_
大)。
因此就有 index < index_x < index_y
且 nums[index] < nums[index_x] < nums[index_y]
。
public boolean increasingTriplet(int[] nums) {
Map<Integer, List<Integer>> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
for (int j = i+1; j < nums.length; j++) {
if (nums[j] > nums[i]) {
if (map.containsKey(i)) {
map.get(i).add(j);
} else {
List<Integer> list = new ArrayList<>();
list.add(j);
map.put(i, list);
}
}
}
}
// 存在 index,就表示有 index2 > index && nums[index2] > nums[index]
for (List<Integer> list : map.values()) {
for (Integer index : list) {
if (map.containsKey(index)) return true;
}
}
return false;
}
上述实现在性能上还是存在不足,后来有看到 LeetCode 上的 3ms 范例:
(同样也可以参考 https://blog.csdn.net/liangzhaoyang1/article/details/50973304)
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(first>num){
first = num;
}else if(first<num && second>num){
second = num;
}else if(num>second){
return true;
}
}
return false;
这样的实现可以说是很好的了,因为传入的是 nums
数组,所以数组中的最大值最大也就为 Integer.MAX_VALUE
,这是需要注意的一个前提。
上面的算法,思想也很简单,就是利用了题目中说的规律,然后利用两个指针辅助。
假设 nums
数组中至少有一个符合题意的子序列 first、second、third
:
x1 x2 ... first ... xi ... second ... xj ... third ... xk
那么,first
肯定是 first
到 second
中最小的,否则,就会把 first
更新,以保证到 second
之间是最小的。
if(first>num) first = num;
而 if(first<num && second>num) second = num;
是为了保持 second
在大于 first
的基础上取 second
与 third
之间的最小值。
之后如果找到了比 second
还大的数就符合条件返回 true
了。