- 86. 分隔链表
- 138. 复制带随机指针的链表
- 622. 设计循环队列
- 641. 设计循环双端队列
- 1670. 设计前中后队列
- 933. 最近的请求次数
- ### 面试题 17.09. 第 k 个数
- 859. 亲密字符串
- 860. 柠檬水找零
- 969. 煎饼排序
- 621. 任务调度器
86. 分隔链表
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。
提示: 链表中节点的数目在范围 [0, 200] 内 -100 <= Node.val <= 100 -200 <= x <= 200
题意理解: 给定一个数x,将列表按需排列,前面都是小于节点,后半截都是大于等于x的节点
- 创建两个链表big,small并初始化节点,用来才分链表,一个存小于x的节点,一个存大于等于x的节点
- currentBig=big,currentSmall=small,以后操作currentBig,currentSmall,因为js 中链表存的是索引,所以需要一个中转来进行操作
- 遍历链表head,将小于x的值存入currentSmall中,其他存入currentBig
- 遍历完成后切断currentBig.nuxt,将currentSmall.next = big.next;
- 返回small.next
var partition = function (head, x) {
const big = new ListNode(-1), small = new ListNode(-1);
let currentBig = big, currentSmall = small;
while (head) {
if (head.val < x) {
currentSmall.next = head;
currentSmall=currentSmall.next;
} else {
currentBig.next = head;
currentBig=currentBig.next;
}
head = head.next
}
currentBig.next = null;
currentSmall.next = big.next;
return small.next
};
138. 复制带随机指针的链表
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。 例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。 返回复制链表的头节点。 用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示: val:一个表示 Node.val 的整数。 random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。 你的代码 只 接受原链表的头节点 head 作为传入参数。
提示: 0 <= n <= 1000 -104 <= Node.val <= 104 Node.random 为 null 或指向链表中的节点。
提议理解: 深拷贝双向链表(做题时最好画图操作)
- 声明变量newHead指向head,currentNode = newHead,以后操作currentNode
- 先将列表中的next拷贝出一份
- 然后赋值currentNode=newHead,再将random正确连接到新拷贝的节点上
- 将拷贝的节点与旧节点拆开,才散时需要拷贝resHead=newHead.next,currentNode=newHead
- 返回resHead
var copyRandomList = function (head) {
if(!head) return null;
const newHead = head;
let currentNode = newHead;
while (currentNode) {
currentNode.next=new Node(currentNode.val,currentNode.next,null);
currentNode=currentNode.next.next;
}
currentNode=newHead;
while(currentNode){
currentNode.next.random = currentNode.random?.next || null;
currentNode=currentNode.next.next;
}
let resHead=newHead.next;
currentNode=newHead;
while(currentNode){
const cNode = currentNode.next;
currentNode.next=currentNode.next.next;
cNode.next = cNode.next?.next || null;
currentNode=currentNode.next
}
return resHead;
};
622. 设计循环队列
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。 循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。 你的实现应该支持如下操作: MyCircularQueue(k): 构造器,设置队列长度为 k 。 Front: 从队首获取元素。如果队列为空,返回 -1 。 Rear: 获取队尾元素。如果队列为空,返回 -1 。 enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。 deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。 isEmpty(): 检查循环队列是否为空。 isFull(): 检查循环队列是否已满。
提示: 所有的值都在 0 至 1000 的范围内; 操作数将在 1 至 1000 的范围内; 请不要使用内置的队列库。
题意理解: 设计一个循环队列,包含以上方法
- 使用链表实现
- 初始化,头结点head,rear,列表大小length,当前列表中数据个数count
function Node(value) {
return {
val: value,
next: null
}
}
/**
* @param {number} k
*/
var MyCircularQueue = function (k) {
this.head = null;
this.rear = null;
this.length = k;
this.count = 0;
};
/**
* @param {number} value
* @return {boolean}
*/
MyCircularQueue.prototype.enQueue = function (value) {
if (this.isFull()) return false;
this.count += 1;
if (this.count === 1) {
this.head = new Node(value);
this.rear = this.head;
} else {
this.rear.next = new Node(value);
this.rear = this.rear.next;
}
return true;
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.deQueue = function () {
if (this.isEmpty()) {
return false;
}
this.count -= 1;
if (this.count === 0) {
this.rear = this.head = null;
} else {
this.head = this.head?.next || null;;
}
return true;
};
/**
* @return {number}
*/
MyCircularQueue.prototype.Front = function () {
if (this.count === 0) {
return -1;
}
return this.head.val;
};
/**
* @return {number}
*/
MyCircularQueue.prototype.Rear = function () {
if (this.count === 0) {
return -1;
}
return this.rear.val;
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.isEmpty = function () {
return this.count === 0
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.isFull = function () {
return this.count === this.length
};
/**
* Your MyCircularQueue object will be instantiated and called as such:
* var obj = new MyCircularQueue(k)
* var param_1 = obj.enQueue(value)
* var param_2 = obj.deQueue()
* var param_3 = obj.Front()
* var param_4 = obj.Rear()
* var param_5 = obj.isEmpty()
* var param_6 = obj.isFull()
*/
使用数组实现
- 初始化队列queue=[],frontInde队头索引frontIndex,队尾索引rearIndex,列表大小length,当前列表中数据个数count
/**
* @param {number} k
*/
var MyCircularQueue = function (k) {
this.queue = [];
this.frontIndex = 0;
this.count = 0;
this.rearIndex = -1; // 我先计算的长度,也可以为0,将计算放到后面
this.length = k;
};
/**
* @param {number} value
* @return {boolean}
*/
MyCircularQueue.prototype.enQueue = function (value) {
if (this.count === this.length) {
return false;
}
this.count += 1;
this.rearIndex += 1;
if (this.rearIndex === this.length) {
this.rearIndex = 0;
}
this.queue[this.rearIndex] = value;
return true;
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.deQueue = function () {
if (this.count === 0) { return false };
this.queue[this.frontIndex] = undefined;
this.count -= 1;
this.frontIndex += 1;
if (this.frontIndex === this.length) {
this.frontIndex = 0;
}
return true;
};
/**
* @return {number}
*/
MyCircularQueue.prototype.Front = function () {
if (this.count === 0) {
return -1;
}
return this.queue[this.frontIndex];
};
/**
* @return {number}
*/
MyCircularQueue.prototype.Rear = function () {
if (this.count === 0) {
return -1;
}
return this.queue[this.rearIndex];
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.isEmpty = function () {
return this.count === 0;
};
/**
* @return {boolean}
*/
MyCircularQueue.prototype.isFull = function () {
return this.count === this.length;
};
/**
* Your MyCircularQueue object will be instantiated and called as such:
* var obj = new MyCircularQueue(k)
* var param_1 = obj.enQueue(value)
* var param_2 = obj.deQueue()
* var param_3 = obj.Front()
* var param_4 = obj.Rear()
* var param_5 = obj.isEmpty()
* var param_6 = obj.isFull()
*/
641. 设计循环双端队列
设计实现双端队列。 实现 MyCircularDeque 类: MyCircularDeque(int k) :构造函数,双端队列最大为 k 。 boolean insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true ,否则返回 false 。 boolean insertLast() :将一个元素添加到双端队列尾部。如果操作成功返回 true ,否则返回 false 。 boolean deleteFront() :从双端队列头部删除一个元素。 如果操作成功返回 true ,否则返回 false 。 boolean deleteLast() :从双端队列尾部删除一个元素。如果操作成功返回 true ,否则返回 false 。 int getFront() ):从双端队列头部获得一个元素。如果双端队列为空,返回 -1 。 int getRear() :获得双端队列的最后一个元素。 如果双端队列为空,返回 -1 。 boolean isEmpty() :若双端队列为空,则返回 true ,否则返回 false 。 boolean isFull() :若双端队列满了,则返回 true ,否则返回 false 。
提示: 1 <= k <= 1000 0 <= value <= 1000 insertFront, insertLast, deleteFront, deleteLast, getFront, getRear, isEmpty, isFull 调用次数不大于 2000 次
题意理解: 实现双端队列
- 使用数组实现
- 初始化队列arr,队列长度length,当前队列中元素个数count,队首索引frontIndex,队尾索引lastIndex
/**
* @param {number} k
*/
var MyCircularDeque = function (k) {
this.arr = new Array(k);
this.count = 0;
this.length = k;
this.frontIndex = 0;
this.lastIndex = -1;
};
/**
* @param {number} value
* @return {boolean}
*/
MyCircularDeque.prototype.insertFront = function (value) {
if (this.isFull()) {
return false;
}
this.count+=1;
this.frontIndex -= 1;
if (this.frontIndex < 0) {
this.frontIndex = this.length - 1;
}
this.arr[this.frontIndex] = value;
if(this.count===1){
this.lastIndex=this.frontIndex;
}
return true;
};
/**
* @param {number} value
* @return {boolean}
*/
MyCircularDeque.prototype.insertLast = function (value) {
if (this.isFull()) {
return false;
}
this.count+=1;
this.lastIndex+=1;
if(this.lastIndex===this.length){
this.lastIndex=0;
}
this.arr[this.lastIndex]=value;
if(this.count===1){
this.frontIndex=this.lastIndex;
}
return true;
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.deleteFront = function () {
if (this.isEmpty()) {
return false;
}
this.arr[this.frontIndex]=undefined;
this.count-=1;
this.frontIndex+=1;
if (this.frontIndex === this.length) {
this.frontIndex = 0;
}
if(this.count===1){
this.lastIndex=this.frontIndex;
}
return true;
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.deleteLast = function () {
if (this.isEmpty()) {
return false;
}
this.arr[this.lastIndex]=undefined;
this.count-=1;
this.lastIndex-=1;
if (this.lastIndex < 0) {
this.lastIndex = this.length - 1;
}
if(this.count===1){
this.frontIndex=this.lastIndex;
}
return true;
};
/**
* @return {number}
*/
MyCircularDeque.prototype.getFront = function () {
if (this.isEmpty()) {
return -1
}
return this.arr[this.frontIndex];
};
/**
* @return {number}
*/
MyCircularDeque.prototype.getRear = function () {
if (this.isEmpty()) {
return -1
}
return this.arr[this.lastIndex];
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.isEmpty = function () {
return this.count === 0;
};
/**
* @return {boolean}
*/
MyCircularDeque.prototype.isFull = function () {
return this.count === this.length;
};
/**
* 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()
*/
1670. 设计前中后队列
请你设计一个队列,支持在前,中,后三个位置的 push 和 pop 操作。 请你完成 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 <= val <= 109 最多调用 1000 次 pushFront, pushMiddle, pushBack, popFront, popMiddle 和 popBack 。
题意理解: 设计一个队列,支持前中后进行元素的添加删除
- 使用双向链表实现
- 写一个辅助函数findMiddle,用来偶去要删除的节点和在中接插入节点的前一个位置。
- Node用来创建节点,初始化head,tail用来指向头尾节点。
function Node(val, next = null, pre = null) {
return {
val,
next,
pre
}
}
var FrontMiddleBackQueue = function () {
this.head = null;
this.count = 0;
this.tail = null;
};
FrontMiddleBackQueue.prototype.findMiddle = function (isAdd = true) {
let mid = this.count >> 1;
// 删除返回的节点,添加在返回的节点后添加
mid += isAdd ? -1 : this.count % 2 == 0 ? -1 : 0;
let currentHead = this.head;
while (currentHead && mid > 0) {
currentHead = currentHead.next;
mid--;
}
return currentHead;
}
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushFront = function (val) {
const newNode = new Node(val, null, null)
if (this.count === 0) {
this.tail = this.head = newNode;
} else {
this.head.pre = newNode;
newNode.next = this.head;
this.head = newNode;
}
this.count++;
// console.log("pushFront",this.head)
return this.head;
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushMiddle = function (val) {
if (this.count <= 1) {
this.pushFront(val);
} else {
const middle = this.findMiddle(true);
const newNode = new Node(val, null, null);
middle.next.pre = newNode;
newNode.next = middle.next;
middle.next = newNode;
newNode.pre = middle;
this.count++;
}
// console.log("pushMiddle",this.head)
return this.head;
};
/**
* @param {number} val
* @return {void}
*/
FrontMiddleBackQueue.prototype.pushBack = function (val) {
const newNode = new Node(val, null, null);
if (this.count === 0) {
this.head = this.tail = newNode;
} else {
this.tail.next = newNode;
newNode.pre = this.tail;
this.tail = this.tail.next;
}
this.count++;
// console.log("pushBack",this.head)
return this.head;
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popFront = function () {
if (this.count === 0) return -1;
const val = this.head.val;
if (this.count === 1) {
this.tail = this.head == null;
} else {
this.head.next.pre = null;
this.head = this.head.next;
}
this.count--;
return val;
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popMiddle = function () {
if (this.count === 0) return -1;
let currentNode = this.findMiddle(false);
if (this.count <= 2) {
this.popFront();
} else {
const pre = currentNode.pre;
pre.next = currentNode.next || null;
currentNode.next.pre = pre;
this.count--;
}
return currentNode.val;
};
/**
* @return {number}
*/
FrontMiddleBackQueue.prototype.popBack = function () {
if (this.count === 0) return -1;
const val = this.tail.val;
if (this.count === 1) {
this.tail = this.head == null;
} else {
const pre = this.tail.pre;
pre.next = null;
this.tail = pre;
}
this.count--;
return val;
};
/**
* Your FrontMiddleBackQueue object will be instantiated and called as such:
* var obj = new FrontMiddleBackQueue()
* obj.pushFront(val)
* obj.pushMiddle(val)
* obj.pushBack(val)
* var param_4 = obj.popFront()
* var param_5 = obj.popMiddle()
* var param_6 = obj.popBack()
*/
933. 最近的请求次数
写一个 RecentCounter 类来计算特定时间范围内最近的请求。 请你实现 RecentCounter 类: RecentCounter() 初始化计数器,请求数为 0 。 int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。 保证 每次对 ping 的调用都使用比之前更大的 t 值。
提示: 1 <= t <= 109 保证每次对 ping 调用所使用的 t 值都 严格递增 至多调用 ping 方法 104 次
题意理解: 返回t-3000, t内请求的次数
- 使用队列特性解决
- 初始化队列arr=[]
- 每次进入队尾添加t,遍历this.arr[0],如果this.arr[0]<(t-3000)则执行出队操作
- 返回arr.length
var RecentCounter = function() {
this.arr=[];
};
/**
* @param {number} t
* @return {number}
*/
RecentCounter.prototype.ping = function(t) {
this.arr.push(t)
while(this.arr[0] && this.arr[0]<(t-3000)){
this.arr.shift();
}
return this.arr.length
};
/**
* Your RecentCounter object will be instantiated and called as such:
* var obj = new RecentCounter()
* var param_1 = obj.ping(t)
*/
面试题 17.09. 第 k 个数
有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数。注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。
提议理解: 这个数组由,3,5,7的倍数组成,并且从小到大排列
- 初始化数组arr=[1]保存这些数;表示已在arr中出现3的倍数的索引arr3Index = 0, arr5Index = 0, arr7Index = 0
- 循环计算出第k个数,计算当前数currentMin用来存储还没出现在arr中的最小数
- 如果currentMin和arr3Index、arr5Index、arr7Index有相同的则自加1
- 返回arr[k - 1]
var getKthMagicNumber = function (k) {
const arr = [1];
let arr3Index = 0, arr5Index = 0, arr7Index = 0;
while (arr.length < k) {
let currentMin = arr[arr3Index]*3;
if (currentMin > arr[arr5Index]*5) {
currentMin = arr[arr5Index]*5;
}
if (currentMin > arr[arr7Index]*7) {
currentMin = arr[arr7Index]*7;
}
if (currentMin === arr[arr3Index]*3) {
arr3Index++;
}
if (currentMin === arr[arr5Index]*5) {
arr5Index++;
}
if (currentMin === arr[arr7Index]*7) {
arr7Index++;
}
arr.push(currentMin)
}
return arr[k - 1]
};
859. 亲密字符串
给你两个字符串 s 和 goal ,只要我们可以通过交换 s 中的两个字母得到与 goal 相等的结果,就返回 true ;否则返回 false 。 交换字母的定义是:取两个下标 i 和 j (下标从 0 开始)且满足 i != j ,接着交换 s[i] 和 s[j] 处的字符。 例如,在 "abcd" 中交换下标 0 和下标 2 的元素可以生成 "cbad" 。
提示: 1 <= s.length, goal.length <= 2 * 104 s 和 goal 由小写英文字母组成
题意理解:
- diffS用来存储s和goal不同的s中的字符,diffGoal用来存储s和goal不同的goal中的字符
- 遍历字符计算不同的字符数diff,如果大于2则返回false
- 如果diff等于0,且s中有相同的字符返回true
- diff等于2且diffGoal,diffS中的数据刚好相反则返回true
- 否则返回false
var buddyStrings = function (s, goal) {
if (s.length !== goal.length || s.length < 2) return false;
let diff = 0;
let diffS = [];
let diffGoal = [];
let isSameStr = false;
for (let i=0; i < s.length; i++) {
if (s[i] !== goal[i]) {
diff++;
diffS.push(s[i])
diffGoal.push(goal[i])
}
if(diff>2){
return false
}
if (i !== s.lastIndexOf(s[i])) {
isSameStr = true
}
}
if (diff === 2) {
return diffS[0] === diffGoal[1] && diffS[1] === diffGoal[0]
}
if (diff === 0 && isSameStr) {
return true
}
return false;
};
860. 柠檬水找零
在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。 每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。 注意,一开始你手头没有任何零钱。 给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。
提示: 1 <= bills.length <= 105 bills[i] 不是 5 就是 10 或是 20
题意理解: 找钱问题,最大限度的给多个顾客找零,如果为20找钱时优先找给(10,5)没有则找(5,5,5)
- moneyCount5统计还有5元的个数,moneyCount10 统计还有10元的个数
var lemonadeChange = function (bills) {
if (bills[0] > 5) return false;
let moneyCount5 = 0;
let moneyCount10 = 0;
for (let val of bills) {
if (val === 5) {
moneyCount5++;
continue
}
if (val === 10) {
if (moneyCount5 === 0) {
return false
}
moneyCount10++;
moneyCount5--;
continue
}
if (val === 20) {
if (moneyCount5 === 0) {
return false
}
if (moneyCount10 > 0) {
moneyCount10--;
moneyCount5--;
continue
}
if (moneyCount5 < 3) {
return false;
}
moneyCount5 -= 3;
}
}
return true;
};
969. 煎饼排序
给你一个整数数组 arr ,请使用 煎饼翻转 完成对数组的排序。 一次煎饼翻转的执行过程如下: 选择一个整数 k ,1 <= k <= arr.length 反转子数组 arr[0...k-1](下标从 0 开始) 例如,arr = [3,2,1,4] ,选择 k = 3 进行一次煎饼翻转,反转子数组 [3,2,1] ,得到 arr = [1,2,3,4] 。
以数组形式返回能使 arr 有序的煎饼翻转操作所对应的 k 值序列。任何将数组排序且翻转次数在 10 * arr.length 范围内的有效答案都将被判断为正确。 提示:
1 <= arr.length <= 100 1 <= arr[i] <= arr.length arr 中的所有整数互不相同(即,arr 是从 1 到 arr.length 整数的一个排列)
题意理解:
- 使用翻转解决
- k伪随机取的数,你可以按照自己的想法去取,本代码k采用每次取未排序最大数
调试时可能和运行结果不同,这是方法不一样,会存在多种结果
var pancakeSort = function(arr) {
function reverse(i){
for(let j=0;j<i;j++,i--){
[arr[j],arr[i]]=[arr[i],arr[j]]
}
}
const output=[];
for(let i=arr.length;i>1;i--){
if(arr[i-1]===i){
continue;
}
if(arr[i-1]!==i && arr[0]!==i){
const k=arr.indexOf(i)
output.push(k+1)
reverse(k)
}
if(arr[0]===i){
output.push(i)
reverse(i-1)
}
}
return output;
};
621. 任务调度器
给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。 然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。 你需要计算完成所有任务所需要的 最短时间 。
提示: 1 <= task.length <= 104 tasks[i] 是大写英文字母 n 的取值范围为 [0, 100]
提议理解: 在n内不能执行相同的进程,可以等待计算tasks所使用的的最短时间 (n + 1) * (arrCount[0] - 1) + maxCount 推理计算 n+1内不能出现重复的进程,arrCount[0]最大进程数,相同的最大进程数的个数maxCount
- 统计每种进程出现的次数,并找出最大进程arrCount[0],和最大进程相同个数的进程数arrCount
- 返回Math.max((n + 1) * (arrCount[0] - 1) + maxCount, tasks.length)
var leastInterval = function (tasks, n) {
if (n === 0) return tasks.length;
const map = new Map();
let count = 0;
for (let val of tasks) {
if (map.has(val)) {
map.set(val, map.get(val) + 1)
} else {
map.set(val, 1)
}
}
const arrCount = [...map.values()].sort((x, y) => y - x)
let maxCount = 0;
for (let val of arrCount) {
if (val === arrCount[0]) {
maxCount++;
} else {
break;
}
}
return Math.max((n + 1) * (arrCount[0] - 1) + maxCount, tasks.length);
};