子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

128. 最长连续序列

[100,4,200,1,3,2] => [1, 2, 3, 4]
我自己没做出来,看下官方解:
官方解,确实好一点,尤其是使用了 set 的数据结构,让取值变得简单多了。还有就是其遍历的手段挺有意思的:利用set结构找连续值:找数集中是否有连续的数,直接通过set查找即可。

  1. var longestConsecutive = function(nums) {
  2. if (nums.length <= 1) {
  3. return nums.length;
  4. }
  5. let max = 0;
  6. let nums_set = new Set(nums); // 利用set结构找连续值
  7. for (let num of nums_set) {
  8. let cur = num;
  9. // 这一点特别鸡贼,避免了重复运算:只从起始点运算 -- 这也是记忆化搜索的替代方案。
  10. if (nums_set.has(cur - 1)) { // 不是局部最大的就跳过,如 [300, 5, 4, 3, 10],其中 4,3, 300, 10 就不满足条件,而 5 满足
  11. continue;
  12. }
  13. let size = 1;
  14. while (nums_set.has(cur + 1)) {
  15. cur++;
  16. size++;
  17. }
  18. if (max < size) {
  19. max = size;
  20. }
  21. }
  22. return max;
  23. };
  24. longestConsecutive([100,4,200,1,3,2]);

674. 最长连续递增序列

[1,3,5,4,7] => [1,3,5]
思路:一个一个遍历元素,记录当前元素为cur,然后判断其后面相邻元素 post,是否比它大:
1)如果大,则增加记录值,然后移动指针
2)如果不大于,则重置状态,去探查下一个序列
一次遍历,双 while 循环:

  1. var findLengthOfLCIS = function(nums) {
  2. let n = nums.length;
  3. if (n <= 1) {
  4. return n;
  5. }
  6. let max = 0;
  7. let i = 0;
  8. while (i < n) { // 因为 i 指针,不一定按照顺序:进入下一轮 while 循环,i 指针可能隔好几个数
  9. let size = 1
  10. let cur = nums[i];
  11. let post = nums[i + 1];
  12. while (cur < post) {
  13. i++;
  14. size++
  15. cur = nums[i];
  16. post = nums[i + 1];
  17. }
  18. i++; // 容易丢:i++ 是循环向下走的关键,必须保证 while 循环能有路
  19. if (max < size) {
  20. max = size;
  21. }
  22. }
  23. return max;
  24. };

结果:(也还可以吧)
image.png

既然,面试不仅靠算法,还要考 coding 能力,那我这道题不换思路,换 for 循环去做:

  1. var findLengthOfLCIS = function(nums) {
  2. let n = nums.length;
  3. if (n <= 1) {
  4. return n;
  5. }
  6. let max = 0;
  7. let size = 1;
  8. for (let i = 0; i < n - 1; i++) {
  9. let cur = nums[i];
  10. let post = nums[i + 1];
  11. if (cur < post) {
  12. size++;
  13. } else { // 上一轮已经记过了
  14. size = 1; // 直接清除就好了
  15. }
  16. if (max < size) { // 每轮都去记录
  17. max = size;
  18. }
  19. }
  20. return max;
  21. };

300. 最长递增子序列

[10,9,2,5,3,7,101,18] => [2,3,7,101]
这个题目和前面最大的不同就是:不再连续!
不能使用 在《最长连续序列里》 的 set 数据结构,也不能使用 while 循环或for循环。
这段说的非常有理:
image.png
逻辑很土,但是有效:

  1. var lengthOfLIS = function(nums) {
  2. let n = nums.length;
  3. if (n <= 1) {
  4. return n;
  5. }
  6. let dp = (new Array(n)).fill(1); // 单个数自己成递增数列
  7. for (let i = 1; i < n; i++) {
  8. for (let j = 0; j < i; j++) {
  9. if (nums[j] < nums[i]) {
  10. dp[i] = Math.max(dp[i], dp[j] + 1); // 去掉max,dp[i]默认是1,所以不断与1比,不需要额外的max来记录最大值了
  11. }
  12. }
  13. }
  14. return Math.max(...dp);
  15. };