1. 有序数组的 Two Sum
LeetCode 167
Input: numbers 有序数组,target 需要求和的值 Output: index1,index2 两个值的下标,注意从1开始
题目描述:在有序数组中寻找两个数,使之和为 target
使用双指针,一个指针指向较小的元素,一个指针指向较大的元素。小指针从头开始往后遍历,大指针从尾开始往前遍历。
- 如果两个指针指向的元素和为 target 则得到了要求的结果
- 如果 sum > target 说明结果大了,大指针需要前移
- 如果 sum < target 说明结果小了,小指针需要后移
/**
* @param {number[]} numbers
* @param {number} target
* @return {number[]}
*/
var twoSum = function (numbers, target) {
let p1 = 0, p2 = numbers.length - 1
while (p1 < p2) {
if (numbers[p1] + numbers[p2] === target) return [p1 + 1, p2 + 1]
else if (numbers[p1] + numbers[p2] < target) p1++
else p2--
}
};
2. 两数平方和
LeetCode 633
Input: 5 Output: True
题目描述:判断一个数是否是两个数的平方和
var judgeSquareSum = function (c) {
let p1 = 0, p2 = parseInt(Math.sqrt(c))
while (p1 <= p2) {
if (p1 * p1 + p2 * p2 === c) return true
else if (p1 * p1 + p2 * p2 > c) p2--
else p1++
}
return false
};
3. 反转字符串中的元音字母
LeetCode 345
Input: "LeetCode" Output: "LeoCede"
解题思路:使用双指针指向待反转的两个元音字母,一个指针从头遍历,一个指针从尾遍历。
var reverseVowels = function (s) {
const VOWELS = { 'a': 1, 'e': 1, 'i': 1, 'o': 1, 'u': 1, 'A': 1, 'E': 1, 'I': 1, 'O': 1, 'U': 1 }
const arr = s.split('')
let i = 0, j = arr.length - 1
while (i < j) {
if (VOWELS[arr[i]] && VOWELS[arr[j]]) {
[arr[i], arr[j]] = [arr[j], arr[i]]
i++
j--
} else if (VOWELS[arr[i]]) j--
else i++
}
return arr.join('')
};
4. 回文字符串
LeetCode 680
Input: "abca" Output: true
题目描述:可以删除一个字符,判断是否可以构成回文串
var validPalindrome = function (s) {
let i = 0, j = s.length-1
while (i < j) {
if (s[i] !== s[j]) {
return judge(s, i + 1, j) || judge(s, i, j - 1)
} else {
i++
j--
}
}
return true
};
const judge = (s, i, j) => {
while (i < j) {
if (s[i] !== s[j]) {
return false
}
i++
j--
}
return true
}
5. 归并两个有序数组
LeetCode 88
Input: nums1 = [1,2,3,0,0,0], m = 3 nums2 = [4,5,6], n = 3
Output: [1,2,3,4,5,6]
题目描述:把结果归并在第一个数组上
需要从尾部开始遍历,不然结果会覆盖未进行归并的值。
var merge = function (nums1, m, nums2, n) {
let p1 = m - 1, p2 = n - 1, mergeIndex = m + n - 1
while (p1 >= 0 || p2 >= 0) {
if (p1 < 0) {
nums1[mergeIndex--] = nums2[p2--]
} else if (p2 < 0) {
nums1[mergeIndex--] = nums1[p1--]
} else if (nums2[p2] >= nums1[p1]) {
nums1[mergeIndex--] = nums2[p2--]
} else {
nums1[mergeIndex--] = nums1[p1--]
}
}
};
6. 判断链表是否存在环
LeetCode 141
使用双指针,一个指针一次移动一个节点,一个一次移动两个节点,如果存在环,则两个指针一定会相遇。 PS: 起始时不能使两个指针指向同一个节点,一前一后不会出问题。
var hasCycle = function (head) {
if (head === null) return false
let p1 = head, p2 = head.next
while (p1 !== null && p2 !== null && p2.next !== null) {
if (p1 === p2) return true
p1 = p1.next
p2 = p2.next.next
}
return false
};
7. 最长子序列
LeetCode 524
Input: s = "abpcplea", d = ["ale","apple","monkey","plea"]
Output: "apple"
题目描述:删除 s 中的一些字符,使之能构成 d 列表中的一个字符串,找出能构成的最长字符串,如果字符串长度相同,则取字典序最小的。
通过删除 s 中的一些字符获得字符串 t,可以认为 t 是 s 的子串序列,我们可以用双指针判断一个字符串是否是另一个字符串的子序列
var findLongestWord = function (s, d) {
let longestCode = ''
for (let cur of d) {
const l1 = longestCode.length, l2 = cur.length
if (l1 > l2 || (l1 === l2 && cur > longestCode))
continue
if (isSubStr(s, cur)) {
longestCode = cur
}
}
return longestCode
};
const isSubStr = (s, target) => {
let i = 0, j = 0
while (i < s.length && j < target.length) {
if (s[i] === target[j]) {
j++
}
i++
}
return j === target.length
}