// 定义单链表的节点.
function ListNode(val, next) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}
反转链表
问题: 给定单链表的头节点 head
,请反转链表,并返回反转后的链表的头节点。(leetcode 024)
思路: 定义三个指针,分别指向前一个结点,待反转头节点,待反转头节点原下一个节点
解法一:
var reverseList = function(head) {
if(head==null||head.next==null) return head;
let pre=null;
let cur=head;
let next=head.next;
while(cur){
cur.next=pre;
pre=cur;
(cur=next)&&(next=next.next)
}
return pre;
};
解法二:递归
var reverseList=function(head){
if(head==null||head.next==null) return head;
let tail=head.next;
let p=reverseList(head.next);
head.next=tail.next;
tail.next=head;
return p
}
旋转链表
问题: 给你一个链表的头节点 head
,旋转链表,将链表每个节点向右移动 k
个位置。(leetcode 61)
解法一:找到尾节点,连到首节点,并记录链表长度n。从头节点开始,找到n-n%k位置,断开向后的指向。
var rotateRight = function(head, k) {
if(head==null||head.next==null)return head;
let p=head;
let n=1;
while(p.next){
p=p.next;
n++;
}
p.next=head;
k%=n;
k=n-k;
while(k){
p=p.next;
k--
}
head=p.next;
p.next=null;
return head
};
链表相交
问题: 给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表没有交点,返回 null
。(leetcode 02.07)
思路: 分别循环两个链表并比较,若其中一个链表的下一个节点为空,说明该链表短,则将临时指针指向长链表的头节点。如果有交点,那么在互相切换指针以后,就会在交点集合;否则都会指向对方的尾节点的下一个节点null.(就是想办法让他们走一样长度就可以了)
var getIntersectionNode = function(headA, headB) {
let pA=headA;
let pB=headB;
while(pA!==pB){
pA=pA===null?headB:pA.next;
pB=pB===null?headA:pB.next;
}
return pA;
};
数据流中的第 K 大元素
问题: 设计一个找到数据流中第 k
大元素的类(class)。注意是排序后的第 k
大元素,不是第 k
个不同的元素。(leetcode 703)
请实现 KthLargest
类:
KthLargest(int k, int[] nums)
使用整数k
和整数流nums
初始化对象。int add(int val)
将val
插入数据流nums
后,返回当前数据流中第k
大的元素。
思路: 用优先队列 建立一个大小为 k 的优先队列来存储前 k 大的元素,优先队列已排好序。
在单次插入的操作中,我们首先将元素 val 加入到优先队列中。如果此时优先队列的大小大于 k,我们需要将优先队列的队头元素弹出,以保证优先队列的大小为 k。
class KthLargest{
constructor(k,nums){
this.k = k;
this.heap = new MinHeap();
for (const x of nums) {
this.add(x);
}
}
add(){
this.heap.offer(val);
if (this.heap.size() > this.k) {
this.heap.poll();
}
return this.heap.peek();
}
}
class MinHeap {
constructor(data = []) {
this.data = data;
this.comparator = (a, b) => a - b;
this.heapify();
}
heapify() {
if (this.size() < 2) return;
for (let i = 1; i < this.size(); i++) {
this.bubbleUp(i);
}
}
peek() {
if (this.size() === 0) return null;
return this.data[0];
}
offer(value) {
this.data.push(value);
this.bubbleUp(this.size() - 1);
}
poll() {
if (this.size() === 0) {
return null;
}
const result = this.data[0];
const last = this.data.pop();
if (this.size() !== 0) {
this.data[0] = last;
this.bubbleDown(0);
}
return result;
}
bubbleUp(index) {
while (index > 0) {
const parentIndex = (index - 1) >> 1;
if (this.comparator(this.data[index], this.data[parentIndex]) < 0) {
this.swap(index, parentIndex);
index = parentIndex;
} else {
break;
}
}
}
bubbleDown(index) {
const lastIndex = this.size() - 1;
while (true) {
const leftIndex = index * 2 + 1;
const rightIndex = index * 2 + 2;
let findIndex = index;
if (
leftIndex <= lastIndex &&
this.comparator(this.data[leftIndex], this.data[findIndex]) < 0
) {
findIndex = leftIndex;
}
if (
rightIndex <= lastIndex &&
this.comparator(this.data[rightIndex], this.data[findIndex]) < 0
) {
findIndex = rightIndex;
}
if (index !== findIndex) {
this.swap(index, findIndex);
index = findIndex;
} else {
break;
}
}
}
size() {
return this.data.length;
}
swap(index1, index2) {
[this.data[index1], this.data[index2]] = [this.data[index2], this.data[index1]];
}
}
翻转二叉树
翻转一棵二叉树。(leetcode 226)
思路: 递归 先翻转叶子节点 然后翻转向上的叶子节点树。
var invertTree = function(root) {
if (root === null) {
return null;
}
const left = invertTree(root.left);
const right = invertTree(root.right);
root.left = right;
root.right = left;
return root;
};