# 双指针技巧秒杀七道数组题目

  • 快慢双指针
  • 左右双指针
  • 扩散双指针

# 167. 两数之和 II - 输入有序数组 (opens new window)

// 左右指针
var twoSum = function (numbers, target) {
  // 方式1 暴力 时间 O(n2) 空间O(1)
  // for (let i = 0; i < numbers.length; i++) {
  //     for (let j = i+1; j < numbers.length;j++ ) {
  //         if(numbers[i]+numbers[j] === target) {
  //             return [i+1, j+1]
  //         }
  //     }
  // }
  // 方式二 首位双指针 时间 O(n) 空间O(1)
  let start = 0
  let end = numbers.length - 1

  while (start < end) {
    if (numbers[start] + numbers[end] > target) {
      end--
    } else if (numbers[start] + numbers[end] < target) {
      start++
    } else {
      return [start + 1, end + 1]
    }
  }
}

# 26. 删除有序数组中的重复项 (opens new window)

/**
 * @param {number[]} nums
 * @return {number}
 */
var removeDuplicates = function (nums) {
  // 升序 原地删除 快慢指针 遇到与slow不一样的元素的时候 fast移动 slow移动 修改slow的值
  let slow = 0
  let fast = 0
  while (fast < nums.length) {
    if (nums[slow] === nums[fast]) {
      fast++
    } else {
      let diff = nums[fast]
      slow++
      nums[slow] = diff
      fast++
    }
  }
  return slow + 1
}

::: Tip 数组的原地删除可以通过调换位置实现 :::

# 27. 移除元素 (opens new window)

/**
 * @param {number[]} nums
 * @param {number} val
 * @return {number}
 */
var removeElement = function(nums, val) {
    // 数组的原地操作 快指针的目的:找到目标元素 慢指针:找到填入的位置
    let slow = 0
    let fast = 0
    while (fast < nums.length) {
        if (nums[fast] === val) {
            fast++
        } else {
            nums[slow] = nums[fast]
            slow++
            fast++
        }
    }
    return slow

# 283. 移动零 (opens new window)

var moveZeroes = function (nums) {
  const n = nums.length
  let left = 0
  for (let right = 0; right < n; right++) {
    if (nums[right] !== 0) {
      ;[nums[left], nums[right]] = [nums[right], nums[left]]
      left++
    }
  }
  return left
}

/**
 * @param {number[]} nums
 * @return {void} Do not return anything, modify nums in-place instead.
 */
var moveZeroes = function (nums) {
  let slow = 0
  let fast = 0
  while (fast < nums.length) {
    if (nums[fast] === 0) {
      fast++
    } else {
      // 这里做一个调换 而不是直接赋值
      const tmp = nums[slow]
      nums[slow] = nums[fast]
      nums[fast] = tmp
      slow++
      fast++
    }
  }
  return nums
}

# 344. 反转字符串 (opens new window)

var reverseString = function (s) {
  let left = 0
  let right = s.length - 1

  while (left < right) {
    ;[s[left], s[right]] = [s[right], s[left]]
    left++
    right--
  }
  return s
}

# 5. 最长回文子串 (opens new window)

/**
 * @param {string} s
 * @return {string}
 */
var longestPalindrome = function (s) {
  // let max = 0
  // let res = ''
  // // 最长 回文 暴力解法
  // for (let i = 0; i < s.length; i++) {
  //     for (let j = i ;j<s.length;j++){
  //         if (isPalindrome(s,i,j)){
  //            if (j-i>=max){
  //                max = j-i
  //                res = s.substring(i,j+1)
  //            }
  //         }
  //     }
  // }
  // return res
  // 双指针中心扩散
  let res = ''
  for (let i = 0; i < s.length; i++) {
    const s1 = palindRome(s, i, i)
    const s2 = palindRome(s, i, i + 1)
    res = s1.length > res.length ? s1 : res
    res = s2.length > res.length ? s2 : res
  }
  return res
}

const palindRome = (s, left, right) => {
  while (left >= 0 && right < s.length && s[left] === s[right]) {
    left--
    right++
  }
  // left 和 right 多加了一次1
  return s.substring(left + 1, right)
}
const isPalindrome = (s, left, right) => {
  while (left < right) {
    if (s[left] === s[right]) {
      left++
      right--
    } else {
      return false
    }
  }
  return true
}