单链表问题
class Node {
public ele: any;
public next: null;
constructor(ele) {
this.ele = ele;
this.next = null;
}
}Last updated
class Node {
public ele: any;
public next: null;
constructor(ele) {
this.ele = ele;
this.next = null;
}
}Last updated
class LinkedList {
private head: any;
private length: number;
constructor() {
this.head = null;
this.length = 0;
}
/**
* 查询指定位置节点
* @param pos 待搜索节点位置
* @returns {Node} 找到返回节点,否则返回-1
*/
get(pos) {
if (pos < 0 || pos > this.length) {
console.warn("索引位置非法!");
return -1;
}
let tmp = this.head,
index = 0;
while (index++ < pos) {
tmp = tmp.next;
}
return tmp;
}
/**
* 追加节点
* @param {Node} ele 待插入节点
* @returns {Boolean} 插入成功返回true,否则false
*/
append(ele) {
let newNode = new Node(ele);
if (!this.head) {
this.head = newNode;
} else {
let tmp = this.head;
while (tmp.next) {
tmp = tmp.next;
}
tmp.next = newNode;
}
this.length++;
return true;
}
/**
* 指定位置插入节点
* @param {Node} ele 待插入节点
* @param {Number} pos 待插入位置 默认为length
* @returns {Boolean} 插入成功返回true,否则false
*/
insert(ele, pos?) {
let validPos = pos ?? this.length; // pos为null/undefined是取右边的值
if (validPos < 0 || validPos > this.length) {
console.warn("插入位置非法!");
return false;
}
let newNode = new Node(ele),
tmp = this.head,
index = 0,
prev;
if (validPos == 0) {
newNode.next = tmp;
// 更新头节点
this.head = newNode;
} else {
while (index++ < validPos) {
prev = tmp;
tmp = tmp.next;
}
// console.log('test', prev, tmp);
// newNode要插在prev和tmp之间
// newNode下一个指向tmp
// prev下一个指向newNode
// 从而把链条拼接上
newNode.next = tmp;
prev.next = newNode;
}
this.length++;
return true;
}
/**
* 指定位置删除节点
* @param {Number} pos 待删除位置
* @returns {Boolean} 删除成功返回true,否则false
*/
remove(pos) {
if (pos < 0 || pos > this.length) {
console.warn("删除位置非法!");
return false;
}
// 找到要删除节点以及其之前的节点
let tmp = this.head,
index = 0,
prev;
if (pos === 0) {
this.head = this.head.next;
} else {
while (index++ < pos) {
prev = tmp;
tmp = tmp.next;
}
// console.log('test', prev, tmp);
// 直接跳过tmp,和tmp的下一个节点拼接
prev.next = tmp.next;
}
this.length--;
return true;
}
/**
* 链表是否为空
* @returns {Boolean} 链表为空返回true,否则false
*/
isEmpty() {
return this.length === 0;
}
/**
* 获取头节点
* @returns {Node} 返回头节点
*/
getHead() {
return this.head;
}
/**
* 获取链表长度
* @returns {Number} 返回链表长度
*/
getSize() {
return this.length;
}
/**
* 获取链表元素数组
* @returns {Array} 返回链表元素数组
*
* TODO 需要考虑环状链表
*/
getList() {
const ret = [];
let cur = this.head;
while (cur.next) {
ret.push(cur.ele);
cur = cur.next;
}
ret.push(cur.ele);
return ret;
}
}const mergeTwoList = (r1, r2) => {
if (r1 === null) return r2;
if (r2 === null) return r1;
if (r1.ele <= r2.ele) {
// 指针后移
r1.next = mergeTwoList(r1.next, r2)
return r1
} else {
r2.next = mergeTwoList(r2.next, r1)
return r2
}
}const hasCycle = (r) => {
while (r) {
if (r.visited) return true
r.visited = true
r = r.next;
}
return false
}const hasCycle = (r) => {
try {
JSON.stringify(r);
return false
} catch (e) {
return true
}
}const hasCycle = (r) => {
if (!r || !r.next) return false
let fast = r.next.next, slow = r.next;
while (fast !== slow) {
if (!fast || !fast.next) return false
fast = fast.next.next
slow = slow.next
}
// 如需找到环入口只需新建一个指针tmp和slow指针同时向前遍历,当两者相等时,入口就是tmp
return true
}const getMiddle = (r) => {
if (!r || !r.next) return r;
let fast = r, slow = r;
while (fast && fast.next) {
fast = fast.next.next;
slow = slow.next
}
return slow
}const reverse = (r) => {
if (!r || !r.next) return r;
let prev = null, cur = r;
while (cur) {
// 用于临时存储 cur 后继节点
// 否则下一步就会抹掉原来的cur.next
let next = cur.next; // 4
// 反转 cur 的后继指针
cur.next = prev; // 首个节点的next就变为了null
// 变更prev、cur
prev = cur; // prev前移
cur = next // cur前移
}
r = prev;
return r;
}const reverse = (r) => {
const _reverse = function (prev, cur) {
if (!cur) return prev // 前移的时候cur为null就结束了
// 临时存储
let next = cur.next;
// 核心反转
cur.next = prev;
return _reverse(cur, next) // prev,cur => cur, next
}
if (!r || !r.next) return r;
r = _reverse(null, r);
return r;
}const addTwoNumbers = (l1, l2) => {
let carry = 0;
let head = null, tail = null; // 当carry>0时,tail用于表示进位
while (l1 || l2) {
let n1 = l1 ? l1.ele : 0;
let n2 = l2 ? l2.ele : 0;
let sum = n1 + n2 + carry;
if (!head) {
head = tail = new Node(sum % 10);
} else {
tail.next = new Node(sum % 10);
tail = tail.next
}
carry = (sum / 10) >> 0
// console.log('ele', sum, l1.ele, l2.ele)
if (l1) {
l1 = l1.next;
}
if (l2) {
l2 = l2.next;
}
}
// 如果有进位,附加一个新节点,其值为carry
if (carry) {
tail.next = new Node(carry)
}
return head
}var isPalindrome = function (head) {
const arr = [];
while (head) {
arr.push(head.val);
head = head.next;
}
let i = 0,
len = arr.length,
j = len - 1;
for (i, j; i < j; i++, j--) {
if (arr[i] !== arr[j]) {
return false;
}
}
return true;
};var isPalindrome = function (head) {
let slow = head,
fast = head;
let prev = null,
next = null;
while (fast !== null && fast.next !== null) {
fast = fast.next.next;
next = slow.next;
// slow 边走边逆序
slow.next = prev;
prev = slow;
slow = next;
}
if (fast !== null) {
// 链表长度为奇数
slow = slow.next;
}
while (prev !== null && slow !== null) {
if (prev.val !== slow.val) {
return false;
}
prev = prev.next;
slow = slow.next;
}
return true;
};var sortList = function (head) {
// 自顶向下归并排序
// 1. 找到链表的中点,以中点为分界,将链表拆分成两个子链表。
// 寻找链表的中点可以使用快慢指针的做法,快指针每次移动 22 步,慢指针每次移动 11 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点
// 2. 对两个子链表分别排序。
// 3. 将两个排序后的子链表合并,得到完整的排序后的链表
return toSortList(head, null);
};
var toSortList = function (head, tail) {
if (!head || !head.next) {
return head;
}
if (head.next === tail) {
head.next = null;
return head;
}
// let slow = head.next;
// let fast = head.next.next;
// while (fast && fast.next && fast !== tail) {
// slow = slow.next;
// fast = fast.next.next;
// }
let slow = head,
fast = head;
while (fast !== tail) {
slow = slow.next;
fast = fast.next;
if (fast !== tail) {
fast = fast.next;
}
}
const mid = slow;
return mergeTwoList(toSortList(head, mid), toSortList(mid, tail));
};