leetcode-- 双指针专题

145 阅读1分钟

结合最近刷的一些题目,会陆续总结出相类似的题目和大家一起解体,持续更新中.

下面我们先来几道开胃菜:

26. 删除有序数组中的重复项

image.png

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function(nums) {
    let fast = 0, slow = 0;
    while(fast < nums.length) {
        if (nums[slow] === nums[fast]) {
            fast++;
        } else if (nums[slow] !== nums[fast]) {
            slow++;
            // 维护 nums[0..slow] 无重复
            nums[slow] = nums[fast];
        }
    }
    // 长度等于 数组长度 + 1;
    return slow + 1;
};

83. 删除排序链表中的重复的元素

image.png

这道题和上题不同地方在于,我们需要用链表的思路去逐个遍历, 将重复的元素删除 删除的思路就是 当 slow.next = fast更新 slow = slow.next.这里在处理的时候,会需要在最后while 结束之后,注意断开slow与后面连接slow.next = null

var deleteDuplicates = function(head) {
   if (head === null) return null;
   let slow = head, fast = head;
   while(fast) {
       if (fast.val !== slow.val) {
           // 删除元素
           slow.next = fast;
           slow = slow.next;
       }
       // 继续更新 fast
       fast = fast.next;
   }
   slow.next = null;
   return head;
}

27. 移除元素

image.png

image.png

从题目中可以看出, 其实已经给出了重复的值是谁,那么我们需要做的事情,就变成了根据val 的值去找到对应的元素,进行对应的删除操作.

var removeElement = function(nums, val) {
   let slow = 0, fast = 0, n = nums.length;
   while(right < n) {
       // nums[fast] === val 需要做什么?
       if (nums[fast] !== val) {
           nums[slow] = nums[fast];
           slow++;
       }
       fast++;
   }
   return slow;
}

283. 移动零

image.png

其实这道题目,如果你对上面的几道题细细评味的话,你就会觉得这道题其实确实很简单.

简单在哪里呢? 首先是我们看题意把所有0移动到数组的末尾,我们可以转换为另一种思维是不是要我去把 0 当作重复的元素的从原数组中拿出来,将剩下的元素按照之前的顺序存储,那么我们结合 上题的返回值和 原数组的长度将 数组重新拼接起来.

那我就说到这里了,你是不是已经摩拳擦掌了,迫切的想去试试了呢?

var moveZeroes = function(nums) {
   let n = nums.length;
   
   let p = removeZero(nums, 0);
   // 组合新的数组
   for (; p < n; p++) {
      nums[p] = 0;
   }
   return nums;
}

function removeZero(nums, val) {
    let fast = 0, slow = 0;
    while(fast < nums.length) {
        if (nums[fast] !== val) {
           nums[slow] = nums[fast]
           slow++;
        }
        fast++;
    }
    return slow;
}

下面我们要开始上难度了

42. 接雨水

image.png

对于接雨水系列我会出一个比较详细的教程,去慢慢解读它的思路,# 雨水☔️ 该怎么样才好接呢?;现在呢,我先放出最终的解法

在写之前,我们可以简单的梳理一下, 我们需要关注的点是 每次i能装多少水 然后计算每次能装最多的水,但是 每次能装的水其实会和两个变量有关系, 我们暂时定为 l_max[i], r_max[i]; 仔细慢慢想想 他们之间是不是有什么关系呢?

water[i] = Math.min(l_max, r_max) - height[i]

l_max = Math.max(l_max, height[left])

r_max = Math.max(r_max, height[right])

到这里大家是不是开始有点感觉了呢?让我们一起试试吧。

// 双指针
// 用双指针 边走边算  节省出那部分空间来
var trap = function(height) {
   let left = 0, right = height.length-1;
   
   let l_max = [], r_max = [], res = 0;
   while (left < right) {
       // 是不是很熟悉的操作
       l_max = Math.max(l_max, height[left]);
       r_max = Math.max(r_max, height[right]);
       
       // 这里是决定谁去更新
       if (l_max < r_max) {
          res += l_max - height[left];
          // 更新
          left++;
       } else {
          res += r_max - height[right];
          right++:
       }
   }
   return res;
}

到这里, 你是不是和我一样收获满满呢, 希望我们都可以坚持下去✊。

题目链接🔗:

26. 删除有序数组中的重复项

83. 删除排序链表中的重复的元素

27. 移除元素

283. 移动零

42.接雨水