双指针,大体可以分为三种指针:
1、普通双指针:同向双指针(其实也就是双层for循环
2、对撞双指针:反方向双指针
3、快慢双指针:步调不一致的指针
27.移除元素
思路:首先数组的内存空间地址是连续的,不能单独删除某个元素,只能覆盖
题目要求只返回删了几个元素
采用快慢双指针法, 慢指针负责遍历原数组所有元素,快指针负责记录删除后的新数组
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function(nums, val) {
let k = 0;
for(let i = 0;i < nums.length;i++){
if(nums[i] != val){
nums[k] = nums[i];
k++;
}
}
return k
}; //时间复杂度O(n),空间复杂度O(1)
344.反转字符串
思路:对撞双指针,交换值即可
let j = s.length - 1;
let left = 0, right = 0;
for (i = 0; i < j; i++) {
left = s[i];
right = s[j];
s[i] = right;
s[j] = left;
j--;
}
return s
151.反转字符串中的单词
思路:直接利用js的内置API,暴力解决
- .split(/\s+/) 意味着【 包括制表符,换行符,回车符,垂直制表符,换页符在内的一个至无穷个类空格字符】隔开。
/**
* @param {string} s
* @return {string}
*/
var reverseWords = function (s) {
s = s.split(/\s+/).reverse().join(" ").trim()
return s
};
206.反转链表
思路:依次改变node的指向即可。
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function (head) {
let pre = null, tmp = null, cur = head;
if (!head || !head.next) return head;
while (cur) {
tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre
};
19.删除链表的倒数第N个节点
思路:快慢指针,以快指针的指向为null时结束循环。快指针应比慢指针快走n+1步,以便删除节点。
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} n
* @return {ListNode}
*/
var removeNthFromEnd = function(head, n) {
const ret = new ListNode(0,head);
let fast = ret, slow = ret;
while(n--) {
fast = fast.next;
}
while(fast.next != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return ret.next;
};
02.07. 链表相交
思路:注意,找链表相交值是找引用的相交值。
取两条链表的长度差,对齐末尾,查找是否有相等的值。
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getListLen = function(head) {
let len = 0, cur = head;
while(cur) {
len++;
cur = cur.next;
}
return len;
}
var getIntersectionNode = function(headA, headB) {
let curA = headA,curB = headB,
lenA = getListLen(headA), // 求链表A的长度
lenB = getListLen(headB);
if(lenA < lenB) { // 让curA为最长链表的头,lenA为其长度
// 交换变量注意加 “分号” ,两个数组交换变量在同一个作用域下时
// 如果不加分号,下面两条代码等同于一条代码: [curA, curB] = [lenB, lenA]
[curA, curB] = [curB, curA];
[lenA, lenB] = [lenB, lenA];
}
let i = lenA - lenB; // 求长度差
while(i-- > 0) { // 让curA和curB在同一起点上(末尾位置对齐)
curA = curA.next;
}
while(curA && curA !== curB) { // 遍历curA 和 curB,遇到相同则直接返回
curA = curA.next;
curB = curB.next;
}
return curA;
};
142.环形链表II
思路:快慢指针,如果有环必相遇
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} head
* @return {ListNode}
*/
var detectCycle = function (head) {
if (!head || !head.next) return null;
let slow = head.next, fast = head.next.next;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (fast === slow) {
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
};
15.三数之和
思路:重点在于去重,先给原数组排序,如果排到某一组数的第一个元素大于0,则可以直接退出循环,减少内存。锁定一个数后,另外两个用对撞双指针即可。
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
nums = nums.sort((a, b) => a - b);
let newArr = [];
for (i = 0; i < nums.length; i++) {
if (nums[i] > 0) {
break;
}
if (i > 0 && nums[i] === nums[i - 1]) continue; //去重
let L = i + 1,
R = nums.length - 1;
while (L < R) {
let sum = nums[i] + nums[L] + nums[R];
if (sum === 0) {
newArr.push([nums[i], nums[L], nums[R]]);
while (nums[L] === nums[L + 1]) { L++; } //去重
while (nums[R] === nums[R - 1]) { R--; } //去重
L++;
R--;
}
else if (sum > 0) { R-- }
else if (sum < 0) { L++ }
}
}
return newArr
};
18.四数之和
思路:其实和三数之和一样,其实N数之和都一样,都能用双指针法把原来的O(n^n)降复杂度为O(n^n-1)。
/**
* @param {number[]} nums
* @param {number} target
* @return {number[][]}
*/
var fourSum = function(nums, target) {
nums = nums.sort((a, b) => a - b);
const len = nums.length;
let newArr = [];
for (i = 0; i < len; i++) {
if (i > 0 && nums[i] === nums[i - 1]) continue;
for (j = i + 1; j < len; j++) {
if (j >i + 1 && nums[j] === nums[j - 1]) continue;
let L = j + 1,
R = len - 1;
while (L < R) {
const sum = nums[i] + nums[j] + nums[L] + nums[R];
if (sum === target) {
newArr.push([nums[i], nums[j], nums[L], nums[R]]);
while (nums[L] === nums[L + 1]) L++;
while (nums[R] === nums[R - 1]) R--;
L++;
R--;
}
if (sum > target) R--;
if (sum < target) L++;
}
}
}
return newArr;
};