双指针
【283】移动零
| Category | Difficulty | Likes | Dislikes |
|---|---|---|---|
| algorithms | Easy (63.86%) | 1142 | - |
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
个人解法
var moveZeroes = function (nums) {
/* let [left, right] = [0, nums.length - 1];
while (left <= right) {
if (nums[left] === 0) {
nums.push(...nums.splice(left, 1));
left++;
}
if (nums[right] !== 0) {
nums.push(...nums.splice(right, 1));
right--;
}
}
return nums; 错误*/
let j = 0;
let [left, right] = [0, nums.length - 1];
while (left <= right) {
if (nums[left] === 0) {
nums.splice(left, 1);
j++;
} else {
left++;
}
}
while (j > 0) {
nums.push(0);
j--;
}
return nums;
};
| 通过 | 96 ms | 39.3 MB | JavaScript |
|---|
分析
一开始的思路出错,是因为nums元素被删后,循环时仍沿用原数组的下标,无法遍历原数组中所有的0。使用双指针法,下标随数组长度改变而改变,可以解决这个问题。
优化
var moveZeroes = function (nums) {
let [left, right] = [0, 0];
while (right < nums.length) {
if (nums[right]) {
/* let temp = nums[left];
nums[left] = nums[right];
nums[right] = temp; */
[nums[left], nums[right]] = [nums[right], nums[left]];
left++;
}
right++;
}
return nums;
};
| 通过 | 72 ms | 39.9 MB | JavaScript |
|---|
分析
一开始虽然也想过定义left、right指针,交换右侧非零数至左侧,但只想到定义left、right为头尾端点下标,头尾交换,此时数组非零元素顺序被反转;未曾想到将left、right同指向数组开头,也就是逐位左右交换,这样可保证非零元素顺序不变。
right指针每次都向右移动一位,而left只在right指向非零数、二者交换值后右移。
tips:
使用解构赋值,比定义中间值temp以交换nums[left],nums[left]快。
【167】两数之和 II - 输入有序数组
| Category | Difficulty | Likes | Dislikes |
|---|---|---|---|
| algorithms | Easy (58.19%) | 548 | - |
给定一个已按照升序排列的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值 。 numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
个人解法
var twoSum = function (numbers, target) {
/* let [left, right] = [0, nums.length];
while (left < right) {
let mid = parseInt((left + right) / 2);
if (mid <= target) {
left++;
}
if () 错误 */
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];
}
}
}
};
| 通过 | 264 ms | 38.4 MB | JavaScript |
|---|
分析
定义i、j两次遍历数组,不如固定第一个数,用二分查找法找第二个数。
优化(二分查找)
var twoSum = function (numbers, target) {
for (let i = 0; i < numbers.length; i++) {
let [left, right] = [i + 1, numbers.length - 1];
while (left <= right) {
let mid = parseInt((left + right) / 2);
if (numbers[i] + numbers[mid] === target) {
return [i + 1, mid + 1];
} else if (numbers[i] + numbers[mid] > target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
}
| 通过 | 84 ms | 39.9 MB | JavaScript |
|---|
第二种解法(双指针)
var twoSum = function (numbers, target) {
let [left, right] = [0, numbers.length - 1];
while (left < right) {
if (numbers[left] + numbers[right] === target) {
return [left + 1, right + 1];
} else if (numbers[left] + numbers[right] < target) {
left++;
} else {
right--;
}
}
return [left + 1, right + 1];
};
| 通过 | 72 ms | 38.2 MB | JavaScript |
|---|
分析
此题使用双指针法的关键点在于:将左右指针初始化为0, numbers.length - 1 。假设numbers[i]+numbers[j]=target就是唯一解,0 ≤ i < j ≤ numbers.length−1。由于题目确保有唯一的答案,左指针不可能移到 i 的右侧,右指针不可能移到 j 的左侧,也不会遗漏解。