>> 分隔链表
问题描述: 给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
你应当 保留 两个分区中每个节点的初始相对位置。(by leetcode 86)
示例 1:
输入:head = [1,4,3,2,5,2], x = 3
输出:[1,2,2,4,3,5]
思路:
/**
* 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} x
* @return {ListNode}
*/
var partition = function(head, x) {
let lsn=new ListNode(),ls=lsn,lbn=new ListNode(),lb=lbn,p=head,q;
while(p){
q=p.next;
p.next=null;
if(p.val<x){
ls.next=p;
ls=p
}
else{
lb.next=p;
lb=p;
}
p=q;
}
ls.next=lbn.next;
return lsn.next;
};
>> 设计循环队列
**问题描述:**设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。(by leetcode 622)
你的实现应该支持如下操作:
-
MyCircularQueue(k): 构造器,设置队列长度为 k 。 -
Front: 从队首获取元素。如果队列为空,返回 -1 。 -
Rear: 获取队尾元素。如果队列为空,返回 -1 。 -
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。 -
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。 -
isEmpty(): 检查循环队列是否为空。 -
isFull(): 检查循环队列是否已满。
示例:
MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1); // 返回 true
circularQueue.enQueue(2); // 返回 true
circularQueue.enQueue(3); // 返回 true
circularQueue.enQueue(4); // 返回 false,队列已满
circularQueue.Rear(); // 返回 3
circularQueue.isFull(); // 返回 true
circularQueue.deQueue(); // 返回 true
circularQueue.enQueue(4); // 返回 true
circularQueue.Rear(); // 返回 4
思路: 封装的思想
/**
* @param {number} k
*/
var MyCircularQueue = function(k) {
this.count=0;
this.size=k;
this.head=0;
this.tail=0;
this.data=[]
};
/**
* @param {number} value
* @return {boolean}
*/
MyCircularQueue.prototype.enQueue = function(value) {
if(this.isFull()){
return false
}
this.data[this.tail]=value;
this.tail++;
this.count++;
if(this.tail==this.size)this.tail=0;
return true;
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.deQueue = function() {
if(this.isEmpty()){
return false;
}
// this.data[this.head]=null;
this.head++;
this.count--;
if(this.head==this.size)this.head=0;
return true;
};
/**
* @return {number}
*/
MyCircularQueue.prototype.Front = function() {
if(this.isEmpty()){
return -1
}
return this.data[this.head]
};
/**
* @return {number}
*/
MyCircularQueue.prototype.Rear = function() {
if(this.isEmpty()){
return -1
}
return this.data[this.tail-1<0?this.size-1:this.tail-1]
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.isEmpty = function() {
return this.count==0
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.isFull = function() {
return this.count==this.size
// if(this.count==this.size)return true
};
设计循环双端队列
问题描述: 设计实现双端队列。 你的实现需要支持以下操作:
- MyCircularDeque(k):构造函数,双端队列的大小为k。
- insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true。
- insertLast():将一个元素添加到双端队列尾部。如果操作成功返回 true。
- deleteFront():从双端队列头部删除一个元素。 如果操作成功返回 true。
- deleteLast():从双端队列尾部删除一个元素。如果操作成功返回 true。
- getFront():从双端队列头部获得一个元素。如果双端队列为空,返回 -1。
- getRear():获得双端队列的最后一个元素。 如果双端队列为空,返回 -1。
- isEmpty():检查双端队列是否为空。
- isFull():检查双端队列是否满了。(by leetcode 641)
示例:
MyCircularDeque circularDeque = new MycircularDeque(3); // 设置容量大小为3
circularDeque.insertLast(1); // 返回 true
circularDeque.insertLast(2); // 返回 true
circularDeque.insertFront(3); // 返回 true
circularDeque.insertFront(4); // 已经满了,返回 false
circularDeque.getRear(); // 返回 2
circularDeque.isFull(); // 返回 true
circularDeque.deleteLast(); // 返回 true
circularDeque.insertFront(4); // 返回 true
circularDeque.getFront(); // 返回 4
思路: 这里需要注意的两点:1.一个是尾指针指向的是最后一个节点的下一个位置,因此在尾部插入节点的时候,应该先放值,再移动指针。2.指针移动的时候要主要-1跟this.size的值的处理。
/**
* @param {number} k
*/
var MyCircularDeque = function(k) {
this.tail=0;//尾部指针指向最后一个节点的后一个位置
this.head=0;
this.count=0;
this.data=[];
this.size=k;
};
/**
* @param {number} value
* @return {boolean}
*/
MyCircularDeque.prototype.insertFront = function(value) {
if(this.isFull()) return false;
this.head=(this.head-1+this.size)%this.size;
this.data[this.head]=value;
this.count++;
return true
};
/**
* @param {number} value
* @return {boolean}
*/
MyCircularDeque.prototype.insertLast = function(value) {
if(this.isFull())return false;
this.data[this.tail]=value;//先赋值 再移动指针
this.tail=(this.tail+1)%this.size;
this.count++;
return true;
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.deleteFront = function() {
if(this.isEmpty())return false;
this.head=(this.head+1)%this.size;
this.count--;
return true;
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.deleteLast = function() {
if(this.isEmpty())return false;
this.tail=(this.tail-1+this.size)%this.size;
this.count--;
return true
};
/**
* @return {number}
*/
MyCircularDeque.prototype.getFront = function() {
if(this.isEmpty())return -1;
return this.data[this.head]
};
/**
* @return {number}
*/
MyCircularDeque.prototype.getRear = function() {
if(this.isEmpty())return -1;
return this.data[(this.tail-1+this.size)%this.size]
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.isEmpty = function() {
return this.count==0
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.isFull = function() {
return this.count==this.size
};
/**
* Your MyCircularDeque object will be instantiated and called as such:
* var obj = new MyCircularDeque(k)
* var param_1 = obj.insertFront(value)
* var param_2 = obj.insertLast(value)
* var param_3 = obj.deleteFront()
* var param_4 = obj.deleteLast()
* var param_5 = obj.getFront()
* var param_6 = obj.getRear()
* var param_7 = obj.isEmpty()
* var param_8 = obj.isFull()
*/
最近的请求次数
问题描述: 写一个 RecentCounter 类来计算特定时间范围内最近的请求。(by leeetcode 933)
请你实现 RecentCounter 类:
RecentCounter()初始化计数器,请求数为 0 。int ping(int t)在时间t添加一个新请求,其中t表示以毫秒为单位的某个时间,并返回过去3000毫秒内发生的所有请求数(包括新请求)。确切地说,返回在[t-3000, t]内发生的请求数。
保证 每次对 ping 的调用都使用比之前更大的 t 值。
示例:
输入:
["RecentCounter", "ping", "ping", "ping", "ping"]
[[], [1], [100], [3001], [3002]]
输出:
[null, 1, 2, 3, 3]
解释:
RecentCounter recentCounter = new RecentCounter();
recentCounter.ping(1); // requests = [1],范围是 [-2999,1],返回 1
recentCounter.ping(100); // requests = [1, 100],范围是 [-2900,100],返回 2
recentCounter.ping(3001); // requests = [1, 100, 3001],范围是 [1,3001],返回 3
recentCounter.ping(3002); // requests = [1, 100, 3001, 3002],范围是 [2,3002],返回 3
思路: 通过队列的思想,当ping一个时间节点的时候,将队列中大于t-3000的节点去出队,最后队列长度就是要求的值。
var RecentCounter = function() {
this.count=[]
};
/**
\* @param {number} t
\* @return {number}
*/
RecentCounter.prototype.ping = function(t) {
this.count.push(t);
while(t-this.count[0]>3000){
this.count.shift();
}
return this.count.length;
};
/**
\* Your RecentCounter object will be instantiated and called as such:
\* var obj = new RecentCounter()
\* var param_1 = obj.ping(t)
*/
设计前中后队列
问题描述: 请你设计一个队列,支持在前,中,后三个位置的 push 和 pop 操作。(by leetcode 1670)
请你完成 FrontMiddleBack 类:
FrontMiddleBack()初始化队列。void pushFront(int val)将val添加到队列的 最前面 。void pushMiddle(int val)将val添加到队列的 正中间 。void pushBack(int val)将val添加到队里的 最后面 。int popFront()将 最前面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回-1。int popMiddle()将 正中间 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回-1。int popBack()将 最后面 的元素从队列中删除并返回值,如果删除之前队列为空,那么返回-1。
请注意当有 两个 中间位置的时候,选择靠前面的位置进行操作。比方说:
-
将
6添加到[1, 2, 3, 4, 5]的中间位置,结果数组为[1, 2, **6**, 3, 4, 5]。 -
从
[1, 2, **3**, 4, 5, 6]的中间位置弹出元素,返回3,数组变为[1, 2, 4, 5, 6]。
示例 1:
输入:
["FrontMiddleBackQueue", "pushFront", "pushBack", "pushMiddle", "pushMiddle", "popFront", "popMiddle", "popMiddle", "popBack", "popFront"]
[[], [1], [2], [3], [4], [], [], [], [], []]
输出:
[null, null, null, null, null, 1, 3, 4, 2, -1]
解释:
FrontMiddleBackQueue q = new FrontMiddleBackQueue();
q.pushFront(1); // [1]
q.pushBack(2); // [1, 2]
q.pushMiddle(3); // [1, 3, 2]
q.pushMiddle(4); // [1, 4, 3, 2]
q.popFront(); // 返回 1 -> [4, 3, 2]
q.popMiddle(); // 返回 3 -> [4, 2]
q.popMiddle(); // 返回 4 -> [2]
q.popBack(); // 返回 2 -> []
q.popFront(); // 返回 -1 -> [] (队列为空)
思路: 用双向链表来实现,注重封装思想
// 实现链表节点
class NodeList{
constructor(val,next,pre){
this.val=(val===undefined ? 0 : val)
this.next=(next===undefined ? null : next)
this.pre=(pre===undefined ? null : pre)
}
// 节点之后插入
insert_back(p){
p.pre=this;
p.next=this.next;
if(this.next)this.next.pre=p;
this.next=p;
return true;
}
// 节点之前插入
insert_front(p){
p.pre=this.pre;
p.next=this;
if(this.pre)this.pre.next=p;
this.pre=p;
return true;
}
// 删除之前节点
delete_front(){
if(this.pre){
let p=this.pre;
p.pre.next=this;
this.pre=p.pre;
}
return true;
}
// 删除之后节点
delete_back(){
if(this.next){
let p=this.next;
this.next=p.next;
if(p.next)p.next.pre=this
}
return true;
}
}
// 实现双向链表
class dbQueue{
constructor(){
this.tail=new NodeList();
this.head=new NodeList();
this.head.next=this.tail;
this.head.pre=null;
this.tail.next=null;
this.tail.pre=this.head;
this.count=0;
}
isEmpty(){
return this.head.next==this.tail;
}
insert_front(val){
// 在头节点后面插入值
this.head.insert_back(new NodeList(val));
this.count++;
return true;
}
insert_back(val){
// 在尾节点之前插入节点
this.tail.insert_front(new NodeList(val))
this.count++;
return true;
}
delete_back(){
//尾节点之前删除-尾部出队
if(this.isEmpty())return -1;
this.count--;
let val=this.tail.pre.val;
this.tail.delete_front();
return val
}
delete_front(){
// 头节点之后删除-头部出队
if(this.isEmpty())return -1;
this.count--;
let val=this.head.next.val;
this.head.delete_back();
return val
}
front(){
return this.head.next.val;
}
rear(){
return this.tail.pre.val;
}
size(){
return this.count;
}
}
// 双向链表实现
var FrontMiddleBackQueue = function() {
this.l1=new dbQueue();
this.l2=new dbQueue();
};
FrontMiddleBackQueue.prototype.isEmpty = function(val) {
return this.l1.size()==0
};
FrontMiddleBackQueue.prototype.update = function(val) {
if(this.l1.size()<this.l2.size()){
this.l1.insert_back(this.l2.front())
this.l2.delete_front()
}
else if(this.l1.size()>=this.l2.size()+2){
this.l2.insert_front(this.l1.rear())
this.l1.delete_back()
}
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushFront = function(val) {
this.l1.insert_front(val)
this.update();
// console.log(this.l1)
return true;
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushMiddle = function(val) {
if(this.l1.size()>this.l2.size()){
this.l2.insert_front(this.l1.rear());
this.l1.delete_back();
}
this.l1.insert_back(val);
return true;
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushBack = function(val) {
this.l2.insert_back(val)
this.update();
return true;
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popFront = function() {
if(this.isEmpty()) return -1
let val=this.l1.delete_front();
this.update();
return val;
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popMiddle = function() {
if(this.isEmpty()) return -1;
var val=this.l1.delete_back();
this.update();
return val;
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popBack = function() {
if(this.isEmpty()) return -1;
let val=0;
if(this.l2.size()){val=this.l2.delete_back();}
else{
val=this.l1.delete_back();
}
this.update();
return val;
};