83. 删除排序链表中的重复元素
解题思路
- 定义pre和cur两个相邻的指针
- 每个指针向后移动一位,判断两个节点的值
- 如果不相等,同时向后移动一位
- 如果相等,cur指针向后移动一位,pre节点next指向新的cur节点
/**
* 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 deleteDuplicates = function(head) {
if(!head || !head.next) {
return head;
}
let pre = head;
let cur = head.next;
while(cur) {
if(cur.val === pre.val) {
cur = cur.next;
pre.next = cur;
} else {
cur = cur.next;
pre = pre.next;
}
}
return head;
};
61. 旋转链表
解题思路
- 将链表尾节点连接到头节点,组成一个环
- 找到旋转后的链表头节点的前一个节点
- 拆环,返回新的头节点
/**
* 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} k
* @return {ListNode}
*/
var rotateRight = function(head, k) {
if (!head || !head.next) {
return head;
}
let tail = head;
let len = 1;
// 查找链表的最后一个节点,将tail 的next 指向head
while (tail.next) {
tail = tail.next;
len++;
}
// 此时tail 指向最后一个节点,将tail的next属性指向head
tail.next = head;
// 将向右旋转变为向左旋转
let n = len - (k % len);
let pre = head;
let ret = head;
// 用户--那目的少旋转一个,便于操作
while (--n) {
pre = pre.next;
}
// ret 指向新的头节点
ret = pre.next;
// 将环拆开
pre.next = null;
return ret;
};
92. 反转链表 II
解题思路
- 找到需要翻转的头节点的前一个节点
- reverve函数: 翻转以头节点开始的k个节点 返回包含后面未翻转部分的新链表
- 链接前半部分和部分新的链表
/**
* 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} left
* @param {number} right
* @return {ListNode}
*/
var reverseBetween = function(head, left, right) {
if(!head || !head.next) {
return head;
}
if(right -left ===0) {
return head;
}
// 虚拟头节点
const ret = new ListNode(null,head);
// 查找left 的前一个节点
let l = left;
let pre = ret;
while(--l) {
pre = pre.next;
}
const reserve = (head,n) => {
if(!head) {
return null;
}
let pre = null;
let cur = head;
// 翻转前k个节点
while(cur && n-- > 0) {
const next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
// head: 翻转部分的尾部节点,pre: 翻转部分的头节点
// cur: 剩余部分的头节点
head.next = cur;
return pre;
}
// 此时pre为需要翻转节点的前一个节点
// reserve 返回之后部分的链表,且left 到 right 部分已经被翻转
pre.next = reserve(pre.next,right - left + 1);
return ret.next;
};
19. 删除链表的倒数第 N 个结点
解题思路
如何找到倒数第n个节点
- 定义第一个指针 front,先向后走n步,
- 定义第二个指针 after, front 和 after 一同向后走
- 当 front走到链表尾部节点时,after 指向的就是倒数第n个节点 技巧: 当节点有很大概率会改变时,需要用到虚拟头节点的技巧, 就是在头部定义一个虚拟的链表节点,next指针指向head
/**
* 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) {
if (!head) {
return null;
}
// 定义虚拟头节点
let ret = new ListNode(null, head);
let front = ret;
while (n--) {
front = front.next;
}
// 定义after指针,然后两个指针一起向后走
let after = ret;
while (front.next) {
after = after.next;
front = front.next;
}
// 此时after,指向倒数第n个节点的前一个节点
after.next = after.next.next;
return ret.next;
};