双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。
1. 两数之和 II - 输入有序数组
题目
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
var twoSum = function(numbers, target) {
let left = 0, right = numbers.length - 1;
let result = [];
while(right > left) {
let sum = numbers[left] + numbers[right];
if (sum === target) {
result.push(left + 1, right + 1);
return result;
} else if (sum > target) {
right--;
} else {
left++;
}
}
return result;
};
2. 平方数之和
题目
给定一个非负整数 c
,你要判断是否存在两个整数 a
和 b
,使得 a2 + b2 = c
。
/**
* @param {number} c
* @return {boolean}
*/
var judgeSquareSum = function(c) {
let left = 0, right = Math.ceil(Math.sqrt(c));
while(right >= left) {
let value = left * left + right * right;
if (value === c) {
return true;
} else if (value > c) {
right--;
} else {
left++;
}
}
return false;
};
3. 反转字符串中的元音字母
题目
编写一个函数,以字符串作为输入,反转该字符串中的元音字母。
/**
* @param {string} s
* @return {string}
*/
var reverseVowels = function(s) {
const sets = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']);
let resArr = s.split('');
let left = 0, right = resArr.length - 1;
while(right > left) {
const leftFlag = sets.has(resArr[left]);
const rightFlag = sets.has(resArr[right]);
if (leftFlag && rightFlag) {
swap(resArr, left, right);
left++;
right--;
} else if (leftFlag) {
right--;
} else {
left++;
}
}
return resArr.join('');
};
function swap(arr, i, j) {
const temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
4. 验证回文字符串 Ⅱ
题目
给定一个非空字符串 s
,最多删除一个字符。判断是否能成为回文字符串。
/**
* @param {string} s
* @return {boolean}
*/
var validPalindrome = function(s) {
let left = 0, right = s.length - 1;
while(right > left) {
if (s.charAt(left) !== s.charAt(right)) {
return isPalindrome(s, left + 1, right) || isPalindrome(s, left, right - 1);
}
right--;
left++;
}
return true;
};
function isPalindrome(str, left, right) {
while(right > left) {
if (str.charAt(left) !== str.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}
5. 合并两个有序数组
题目
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。
// 注意要从数组后面往前遍历
var merge = function(nums1, m, nums2, n) {
let index1 = m - 1, index2 = n - 1, index = m + n - 1;
while(index1 !== -1 || index2 !== -1) {
if (index1 === -1) {
nums1[index--] = nums2[index2--];
} else if (index2 === -1) {
nums1[index--] = nums1[index1--];
} else if (nums2[index2] > nums1[index1]) {
nums1[index--] = nums2[index2--];
} else {
nums1[index--] = nums1[index1--];
}
}
};
6. 环形链表
题目
给定一个链表,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
// 快慢指针
var hasCycle = function(head) {
if (!head) return false;
let slow = head, fast = head;
while(slow && fast) {
slow = slow.next;
if (!fast.next) {
return false;
}
fast = fast.next.next;
if (slow === fast) {
return true;
}
}
return false;
};
7. 通过删除字母匹配到字典里最长单词
题目
给你一个字符串 s 和一个字符串数组 dictionary 作为字典,找出并返回字典中最长的字符串,该字符串可以通过删除 s 中的某些字符得到。
如果答案不止一个,返回长度最长且字典序最小的字符串。如果答案不存在,则返回空字符串。
var findLongestWord = function(s, dictionary) {
let maxLength = 0, res = '';
dictionary.forEach(item => {
if (isSubString(s, item)) {
if (item.length > maxLength) {
maxLength = item.length;
res = item;
} else if (item.length === maxLength) {
res = item > res ? res : item;
}
}
})
return res;
};
function isSubString(str, subStr) {
let index = 0, subIndex = 0;
let strLength = str.length, subLength = subStr.length;
while(index < strLength) {
if (subIndex === subLength) {
return true;
}
if (str[index] === subStr[subIndex]) {
subIndex++;
}
index++;
}
return subIndex === subLength;
}