跳到主要内容

7 篇博文 含有标签「有序集合」

查看所有标签

· 阅读需 6 分钟

1、题干

给你两个二维整数数组 items1 和 items2 ,表示两个物品集合。每个数组 items 有以下特质:

  • items[i] = [valuei, weighti] 其中 valuei 表示第 i 件物品的 价值 ,weighti 表示第 i 件物品的 重量 。
  • items 中每件物品的价值都是 唯一的 。

请你返回一个二维数组 ret,其中 ret[i] = [valuei, weighti], weighti 是所有价值为 valuei 物品的 重量之和 。

注意:ret 应该按价值 升序 排序后返回。

 

示例 1:

输入:items1 = [[1,1],[4,5],[3,8]], items2 = [[3,1],[1,5]]
输出:[[1,6],[3,9],[4,5]]
解释:
value = 1 的物品在 items1 中 weight = 1 ,在 items2 中 weight = 5 ,总重量为 1 + 5 = 6 。
value = 3 的物品再 items1 中 weight = 8 ,在 items2 中 weight = 1 ,总重量为 8 + 1 = 9 。
value = 4 的物品在 items1 中 weight = 5 ,总重量为 5 。
所以,我们返回 [[1,6],[3,9],[4,5]] 。

示例 2:

输入:items1 = [[1,1],[3,2],[2,3]], items2 = [[2,1],[3,2],[1,3]]
输出:[[1,4],[2,4],[3,4]]
解释:
value = 1 的物品在 items1 中 weight = 1 ,在 items2 中 weight = 3 ,总重量为 1 + 3 = 4 。
value = 2 的物品在 items1 中 weight = 3 ,在 items2 中 weight = 1 ,总重量为 3 + 1 = 4 。
value = 3 的物品在 items1 中 weight = 2 ,在 items2 中 weight = 2 ,总重量为 2 + 2 = 4 。
所以,我们返回 [[1,4],[2,4],[3,4]] 。

示例 3:

输入:items1 = [[1,3],[2,2]], items2 = [[7,1],[2,2],[1,4]]
输出:[[1,7],[2,4],[7,1]]
解释:
value = 1 的物品在 items1 中 weight = 3 ,在 items2 中 weight = 4 ,总重量为 3 + 4 = 7 。
value = 2 的物品在 items1 中 weight = 2 ,在 items2 中 weight = 2 ,总重量为 2 + 2 = 4 。
value = 7 的物品在 items2 中 weight = 1 ,总重量为 1 。
所以,我们返回 [[1,7],[2,4],[7,1]] 。

 

提示:

  • 1 <= items1.length, items2.length <= 1000
  • items1[i].length == items2[i].length == 2
  • 1 <= valuei, weighti <= 1000
  • items1 中每个 valuei 都是 唯一的 。
  • items2 中每个 valuei 都是 唯一的 。

2、思路1-整合+排序

整合两个数组再统一升序排序,接着遍历所有物品得到结果

3、代码

function mergeSimilarItems(items1: number[][], items2: number[][]): number[][] {
items1.push(...items2);
items1.sort((a, b) => a[0] - b[0]);

const ans = [];
for (let i = 0; i < items1.length; i++) {
if (items1[i][0] === items1[i + 1]?.at(0)) items1[i + 1][1] += items1[i][1];
else ans.push(items1[i]);
}

return ans;
};

4、复杂度

  • 时间复杂度:O(nlogn)O(n \log n)
  • 空间复杂度:O(n)O(n)

5、执行结果

image.png


6、思路2-桶排序

以价值作为桶序号,累加物品重量,最后返回重量大于0的桶序号及其重量

桶内不需要再排序,而是累加数值,跟常见的桶排序有点不同

7、代码

function mergeSimilarItems(items1: number[][], items2: number[][]): number[][] {
const bucket = new Array(1001).fill(0);
for (let i = 0; i < items1.length || i < items2.length; i++) {
if (items1[i]) bucket[items1[i][0]] += items1[i][1];
if (items2[i]) bucket[items2[i][0]] += items2[i][1];
}

return bucket.map((w, i) => [i, w]).filter(b => b[1]);
};

8、复杂度

  • 时间复杂度:O(max(C,n))O(max(C,n))
  • 空间复杂度:O(C)O(C)

9、执行结果

image.png


10、思路3-哈希+排序

以价值作为哈希表的键,累加物品重量,最后返回按键升序排序的键值对

11、代码

function mergeSimilarItems(items1: number[][], items2: number[][]): number[][] {
const map = new Map();
for (let i = 0; i < items1.length || i < items2.length; i++) {
if (items1[i]) map.set(items1[i][0], (map.get(items1[i][0]) || 0) + items1[i][1]);
if (items2[i]) map.set(items2[i][0], (map.get(items2[i][0]) || 0) + items2[i][1]);
}

return [...map].sort((a, b) => a[0] - b[0]);
};

12、复杂度

  • 时间复杂度:O(nlogn)O(n \log n)
  • 空间复杂度:O(n)O(n)

13、执行结果

image.png


14、思路4-双指针+排序

先对两个数组分别排序,再使用双指针按价值从小到大遍历所有物品

15、代码

function mergeSimilarItems(items1: number[][], items2: number[][]): number[][] {
items1.sort((a, b) => a[0] - b[0]);
items2.sort((a, b) => a[0] - b[0]);

const ans = [];
for (let i = 0, j = 0; i < items1.length || j < items2.length;) {
while (i < items1.length && (!items2[j] || items1[i][0] < items2[j][0])) {
ans.push(items1[i]);
i++;
}

while (j < items2.length && (!items1[i] || items1[i][0] > items2[j][0])) {
ans.push(items2[j]);
j++;
}

if (i < items1.length && j < items2.length && items1[i][0] === items2[j][0]) {
items1[i][1] += items2[j][1];
ans.push(items1[i]);
i++, j++;
}
}

return ans;
};

16、复杂度

  • 时间复杂度:O(nlogn)O(n \log n)
  • 空间复杂度:O(logn)O(\log n)

17、执行结果

image.png

· 阅读需 6 分钟

1、题干

给你两个整数 m 和 k ,以及数据流形式的若干整数。你需要实现一个数据结构,计算这个数据流的 MK 平均值 。

MK 平均值 按照如下步骤计算:

  1. 如果数据流中的整数少于 m 个,MK 平均值 为 -1 ,否则将数据流中最后 m 个元素拷贝到一个独立的容器中。
  2. 从这个容器中删除最小的 k 个数和最大的 k 个数。
  3. 计算剩余元素的平均值,并 向下取整到最近的整数 。

请你实现 MKAverage 类:

  • MKAverage(int m, int k) 用一个空的数据流和两个整数 m 和 k 初始化 MKAverage 对象。
  • void addElement(int num) 往数据流中插入一个新的元素 num 。
  • int calculateMKAverage() 对当前的数据流计算并返回 MK 平均数 ,结果需 向下取整到最近的整数

 

示例 1:

输入:
["MKAverage", "addElement", "addElement", "calculateMKAverage", "addElement", "calculateMKAverage", "addElement", "addElement", "addElement", "calculateMKAverage"]
[[3, 1], [3], [1], [], [10], [], [5], [5], [5], []]
输出:
[null, null, null, -1, null, 3, null, null, null, 5]

解释:
MKAverage obj = new MKAverage(3, 1);
obj.addElement(3); // 当前元素为 [3]
obj.addElement(1); // 当前元素为 [3,1]
obj.calculateMKAverage(); // 返回 -1 ,因为 m = 3 ,但数据流中只有 2 个元素
obj.addElement(10); // 当前元素为 [3,1,10]
obj.calculateMKAverage(); // 最后 3 个元素为 [3,1,10]
// 删除最小以及最大的 1 个元素后,容器为 [3]
// [3] 的平均值等于 3/1 = 3 ,故返回 3
obj.addElement(5); // 当前元素为 [3,1,10,5]
obj.addElement(5); // 当前元素为 [3,1,10,5,5]
obj.addElement(5); // 当前元素为 [3,1,10,5,5,5]
obj.calculateMKAverage(); // 最后 3 个元素为 [5,5,5]
// 删除最小以及最大的 1 个元素后,容器为 [5]
// [5] 的平均值等于 5/1 = 5 ,故返回 5

 

提示:

  • 3 <= m <= 105
  • 1 <= k*2 < m
  • 1 <= num <= 105
  • addElement 与 calculateMKAverage 总操作次数不超过 105 次。

这10分真的十分难拿,临场肯定写不出来,没有第三方库肯定也写不出来

2、思路

3棵二叉搜索树保存最近 m 个数字,其中 trees[0] 保存最小的 k 个数、trees[1] 保存中间的 m - 2*k 个数、trees[2] 保存最大的 k 个数。保存中间数字之和 sum,并在添加元素时更新,以便快速计算平均值。

addElement 时先进行移除操作,再进行插入操作:

  • 若当前已超过 m 个数,则从树中移除倒数第 m+1 个数,然后将处于后方树中最小的数字往前方的树填充
  • 将当前数字插入第一棵树,然后将前方树中多余的最大数字往后方的树填充

calculateMKAverage 直接使用中间数字之和 sum 求平均

3、代码

var MKAverage = function (m, k) {
this.m = m;
this.k = k;

this.nums = [];
this.trees = [new AVLTree(), new AVLTree(), new AVLTree()];
this.sum = 0;
};

MKAverage.prototype.addElement = function (num) {
this.nums.push(num);
const trees = this.trees;

// remove
if (this.nums.length > this.m) {
const n = this.nums[this.nums.length - this.m - 1];
let i = trees.findIndex(t => t.contains(n));

if (i === 1) this.sum -= n;
trees[i].remove(n);

for (; i < trees.length - 1 && trees[i + 1].size > 0; i++) {
const tmin = trees[i + 1].min();
trees[i + 1].remove(tmin);
trees[i].insert(tmin);
if (i === 0) this.sum -= tmin;
else if (i === 1) this.sum += tmin;
}
}

// insert
for (let i = 0; i < trees.length; i++) {
const c = i !== 1 ? this.k : this.m - 2 * this.k;
trees[i].insert(num);
if (i === 1) this.sum += num;

if (trees[i].size <= c) break;

num = trees[i].max();
trees[i].remove(num);
if (i === 1) this.sum -= num;
}
};

MKAverage.prototype.calculateMKAverage = function () {
return this.nums.length < this.m ? -1 : (this.sum / (this.m - 2 * this.k)) >> 0;
};

// https://github.com/w8r/avl/
function print(root,printNode){if(printNode===void 0)printNode=function(n){return n.key};var out=[];row(root,'',true,function(v){return out.push(v)},printNode);return out.join('')}function row(root,prefix,isTail,out,printNode){if(root){out((""+prefix+(isTail?'└── ':'├── ')+(printNode(root))+"\n"));var indent=prefix+(isTail?' ':'│ ');if(root.left){row(root.left,indent,false,out,printNode)}if(root.right){row(root.right,indent,true,out,printNode)}}}function isBalanced(root){if(root===null){return true}var lh=height(root.left);var rh=height(root.right);if(Math.abs(lh-rh)<=1&&isBalanced(root.left)&&isBalanced(root.right)){return true}return false}function height(node){return node?(1+Math.max(height(node.left),height(node.right))):0}function loadRecursive(parent,keys,values,start,end){var size=end-start;if(size>0){var middle=start+Math.floor(size/2);var key=keys[middle];var data=values[middle];var node={key:key,data:data,parent:parent};node.left=loadRecursive(node,keys,values,start,middle);node.right=loadRecursive(node,keys,values,middle+1,end);return node}return null}function markBalance(node){if(node===null){return 0}var lh=markBalance(node.left);var rh=markBalance(node.right);node.balanceFactor=lh-rh;return Math.max(lh,rh)+1}function sort(keys,values,left,right,compare){if(left>=right){return}var pivot=keys[(left+right)>>1];var i=left-1;var j=right+1;while(true){do{i++}while(compare(keys[i],pivot)<0);do{j--}while(compare(keys[j],pivot)>0);if(i>=j){break}var tmp=keys[i];keys[i]=keys[j];keys[j]=tmp;tmp=values[i];values[i]=values[j];values[j]=tmp}sort(keys,values,left,j,compare);sort(keys,values,j+1,right,compare)}function DEFAULT_COMPARE(a,b){return a>b?1:a<b?-1:0}function rotateLeft(node){var rightNode=node.right;node.right=rightNode.left;if(rightNode.left){rightNode.left.parent=node}rightNode.parent=node.parent;if(rightNode.parent){if(rightNode.parent.left===node){rightNode.parent.left=rightNode}else{rightNode.parent.right=rightNode}}node.parent=rightNode;rightNode.left=node;node.balanceFactor+=1;if(rightNode.balanceFactor<0){node.balanceFactor-=rightNode.balanceFactor}rightNode.balanceFactor+=1;if(node.balanceFactor>0){rightNode.balanceFactor+=node.balanceFactor}return rightNode}function rotateRight(node){var leftNode=node.left;node.left=leftNode.right;if(node.left){node.left.parent=node}leftNode.parent=node.parent;if(leftNode.parent){if(leftNode.parent.left===node){leftNode.parent.left=leftNode}else{leftNode.parent.right=leftNode}}node.parent=leftNode;leftNode.right=node;node.balanceFactor-=1;if(leftNode.balanceFactor>0){node.balanceFactor-=leftNode.balanceFactor}leftNode.balanceFactor-=1;if(node.balanceFactor<0){leftNode.balanceFactor+=node.balanceFactor}return leftNode}var AVLTree=function AVLTree(comparator,noDuplicates){if(noDuplicates===void 0)noDuplicates=false;this._comparator=comparator||DEFAULT_COMPARE;this._root=null;this._size=0;this._noDuplicates=!!noDuplicates};var prototypeAccessors={size:{configurable:true}};AVLTree.prototype.destroy=function destroy(){return this.clear()};AVLTree.prototype.clear=function clear(){this._root=null;this._size=0;return this};prototypeAccessors.size.get=function(){return this._size};AVLTree.prototype.contains=function contains(key){if(this._root){var node=this._root;var comparator=this._comparator;while(node){var cmp=comparator(key,node.key);if(cmp===0){return true}else if(cmp<0){node=node.left}else{node=node.right}}}return false};AVLTree.prototype.next=function next(node){var successor=node;if(successor){if(successor.right){successor=successor.right;while(successor.left){successor=successor.left}}else{successor=node.parent;while(successor&&successor.right===node){node=successor;successor=successor.parent}}}return successor};AVLTree.prototype.prev=function prev(node){var predecessor=node;if(predecessor){if(predecessor.left){predecessor=predecessor.left;while(predecessor.right){predecessor=predecessor.right}}else{predecessor=node.parent;while(predecessor&&predecessor.left===node){node=predecessor;predecessor=predecessor.parent}}}return predecessor};AVLTree.prototype.forEach=function forEach(callback){var current=this._root;var s=[],done=false,i=0;while(!done){if(current){s.push(current);current=current.left}else{if(s.length>0){current=s.pop();callback(current,i++);current=current.right}else{done=true}}}return this};AVLTree.prototype.range=function range(low,high,fn,ctx){var Q=[];var compare=this._comparator;var node=this._root,cmp;while(Q.length!==0||node){if(node){Q.push(node);node=node.left}else{node=Q.pop();cmp=compare(node.key,high);if(cmp>0){break}else if(compare(node.key,low)>=0){if(fn.call(ctx,node)){return this}}node=node.right}}return this};AVLTree.prototype.keys=function keys(){var current=this._root;var s=[],r=[],done=false;while(!done){if(current){s.push(current);current=current.left}else{if(s.length>0){current=s.pop();r.push(current.key);current=current.right}else{done=true}}}return r};AVLTree.prototype.values=function values(){var current=this._root;var s=[],r=[],done=false;while(!done){if(current){s.push(current);current=current.left}else{if(s.length>0){current=s.pop();r.push(current.data);current=current.right}else{done=true}}}return r};AVLTree.prototype.at=function at(index){var current=this._root;var s=[],done=false,i=0;while(!done){if(current){s.push(current);current=current.left}else{if(s.length>0){current=s.pop();if(i===index){return current}i++;current=current.right}else{done=true}}}return null};AVLTree.prototype.minNode=function minNode(){var node=this._root;if(!node){return null}while(node.left){node=node.left}return node};AVLTree.prototype.maxNode=function maxNode(){var node=this._root;if(!node){return null}while(node.right){node=node.right}return node};AVLTree.prototype.min=function min(){var node=this._root;if(!node){return null}while(node.left){node=node.left}return node.key};AVLTree.prototype.max=function max(){var node=this._root;if(!node){return null}while(node.right){node=node.right}return node.key};AVLTree.prototype.isEmpty=function isEmpty(){return!this._root};AVLTree.prototype.pop=function pop(){var node=this._root,returnValue=null;if(node){while(node.left){node=node.left}returnValue={key:node.key,data:node.data};this.remove(node.key)}return returnValue};AVLTree.prototype.popMax=function popMax(){var node=this._root,returnValue=null;if(node){while(node.right){node=node.right}returnValue={key:node.key,data:node.data};this.remove(node.key)}return returnValue};AVLTree.prototype.find=function find(key){var root=this._root;var subtree=root,cmp;var compare=this._comparator;while(subtree){cmp=compare(key,subtree.key);if(cmp===0){return subtree}else if(cmp<0){subtree=subtree.left}else{subtree=subtree.right}}return null};AVLTree.prototype.insert=function insert(key,data){if(!this._root){this._root={parent:null,left:null,right:null,balanceFactor:0,key:key,data:data};this._size++;return this._root}var compare=this._comparator;var node=this._root;var parent=null;var cmp=0;if(this._noDuplicates){while(node){cmp=compare(key,node.key);parent=node;if(cmp===0){return null}else if(cmp<0){node=node.left}else{node=node.right}}}else{while(node){cmp=compare(key,node.key);parent=node;if(cmp<=0){node=node.left}else{node=node.right}}}var newNode={left:null,right:null,balanceFactor:0,parent:parent,key:key,data:data};var newRoot;if(cmp<=0){parent.left=newNode}else{parent.right=newNode}while(parent){cmp=compare(parent.key,key);if(cmp<0){parent.balanceFactor-=1}else{parent.balanceFactor+=1}if(parent.balanceFactor===0){break}else if(parent.balanceFactor<-1){if(parent.right.balanceFactor===1){rotateRight(parent.right)}newRoot=rotateLeft(parent);if(parent===this._root){this._root=newRoot}break}else if(parent.balanceFactor>1){if(parent.left.balanceFactor===-1){rotateLeft(parent.left)}newRoot=rotateRight(parent);if(parent===this._root){this._root=newRoot}break}parent=parent.parent}this._size++;return newNode};AVLTree.prototype.remove=function remove(key){if(!this._root){return null}var node=this._root;var compare=this._comparator;var cmp=0;while(node){cmp=compare(key,node.key);if(cmp===0){break}else if(cmp<0){node=node.left}else{node=node.right}}if(!node){return null}var returnValue=node.key;var max,min;if(node.left){max=node.left;while(max.left||max.right){while(max.right){max=max.right}node.key=max.key;node.data=max.data;if(max.left){node=max;max=max.left}}node.key=max.key;node.data=max.data;node=max}if(node.right){min=node.right;while(min.left||min.right){while(min.left){min=min.left}node.key=min.key;node.data=min.data;if(min.right){node=min;min=min.right}}node.key=min.key;node.data=min.data;node=min}var parent=node.parent;var pp=node;var newRoot;while(parent){if(parent.left===pp){parent.balanceFactor-=1}else{parent.balanceFactor+=1}if(parent.balanceFactor<-1){if(parent.right.balanceFactor===1){rotateRight(parent.right)}newRoot=rotateLeft(parent);if(parent===this._root){this._root=newRoot}parent=newRoot}else if(parent.balanceFactor>1){if(parent.left.balanceFactor===-1){rotateLeft(parent.left)}newRoot=rotateRight(parent);if(parent===this._root){this._root=newRoot}parent=newRoot}if(parent.balanceFactor===-1||parent.balanceFactor===1){break}pp=parent;parent=parent.parent}if(node.parent){if(node.parent.left===node){node.parent.left=null}else{node.parent.right=null}}if(node===this._root){this._root=null}this._size--;return returnValue};AVLTree.prototype.load=function load(keys,values,presort){if(keys===void 0)keys=[];if(values===void 0)values=[];if(this._size!==0){throw new Error('bulk-load: tree is not empty');}var size=keys.length;if(presort){sort(keys,values,0,size-1,this._comparator)}this._root=loadRecursive(null,keys,values,0,size);markBalance(this._root);this._size=size;return this};AVLTree.prototype.isBalanced=function isBalanced$1(){return isBalanced(this._root)};AVLTree.prototype.toString=function toString(printNode){return print(this._root,printNode)};Object.defineProperties(AVLTree.prototype,prototypeAccessors);

4、复杂度

  • 时间复杂度:addElementO(logn)O(logn)calculateMKAverageO(1)O(1)
  • 空间复杂度:O(n)O(n)

5、执行结果

image.png

· 阅读需 4 分钟

1、题干

在考场里,一排有 N 个座位,分别编号为 0, 1, 2, ..., N-1 。

当学生进入考场后,他必须坐在能够使他与离他最近的人之间的距离达到最大化的座位上。如果有多个这样的座位,他会坐在编号最小的座位上。(另外,如果考场里没有人,那么学生就坐在 0 号座位上。)

返回 ExamRoom(int N) 类,它有两个公开的函数:其中,函数 ExamRoom.seat() 会返回一个 int (整型数据),代表学生坐的位置;函数 ExamRoom.leave(int p) 代表坐在座位 p 上的学生现在离开了考场。每次调用 ExamRoom.leave(p) 时都保证有学生坐在座位 p 上。

 

示例:

输入:["ExamRoom","seat","seat","seat","seat","leave","seat"], [[10],[],[],[],[],[4],[]]
输出:[null,0,9,4,2,null,5]
解释:
ExamRoom(10) -> null
seat() -> 0,没有人在考场里,那么学生坐在 0 号座位上。
seat() -> 9,学生最后坐在 9 号座位上。
seat() -> 4,学生最后坐在 4 号座位上。
seat() -> 2,学生最后坐在 2 号座位上。
leave(4) -> null
seat() -> 5,学生最后坐在 5 号座位上。

 

提示:

  1. 1 <= N <= 10^9
  2. 在所有的测试样例中 ExamRoom.seat() 和 ExamRoom.leave() 最多被调用 10^4 次。
  3. 保证在调用 ExamRoom.leave(p) 时有学生正坐在座位 p 上。

2、代码

class ExamRoom {
n = -1;
min = Infinity;
max = -Infinity;
set = new Set<number>();
pq = new PriorityQueue({
compare: (a: [number, number], b: [number, number]): number => {
const da = (a[1] - a[0]) / 2 >> 0, db = (b[1] - b[0]) / 2 >> 0;
return da !== db ? db - da : a[0] - b[0];
}
});

constructor(n: number) {
this.n = n;
}

seat(): number {
let i = 0;
if (this.set.size) {
let found = false;
while (!found && this.pq.size()) {
const [n1, n2] = this.pq.dequeue();
if (n2 - n1 < 1 || !this.set.has(n1) || !this.set.has(n2)) continue;

const [m1, m2] = this.pq.front() || [];
if (n1 === m1 && n2 === m2) continue;

i = (n1 + n2) / 2 >> 0;
if (this.set.has(i) && this.set.has(i + 1)) continue;

if ((n2 - n1) / 2 >> 0 <= this.min || (n2 - n1) / 2 >> 0 < this.n - 1 - this.max) {
this.pq.enqueue([n1, n2]);
break;
}

found = true;
if (this.set.has(i)) i = i + 1;

this.pq.enqueue([n1, i]);
this.pq.enqueue([i, n2]);
}

if (!found) {
if (this.n - 1 - this.max > this.min) {
i = this.n - 1;
this.pq.enqueue([this.max, i]);
} else {
i = 0;
this.pq.enqueue([i, this.min]);
}
}
}

this.set.add(i);
if (i < this.min) this.min = i;
if (i > this.max) this.max = i;
return i;
}

leave(p: number): void {
this.set.delete(p);
const nums = [...this.set].sort((a, b) => a - b);

this.min = !nums.length ? Infinity : nums[0];
this.max = !nums.length ? -Infinity : nums[nums.length - 1];

const i = nums.findIndex(n => n > p);
if (i > 0) this.pq.enqueue([nums[i - 1], nums[i]]);
}
}

3、执行结果

image.png

· 阅读需 3 分钟

1、题干

给你一个整数数组 nums 和两个整数 kt 。请你判断是否存在 两个不同下标 ij,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k

如果存在则返回 true,不存在返回 false

 

示例 1:

输入:nums = [1,2,3,1], k = 3, t = 0
输出:true

示例 2:

输入:nums = [1,0,1,1], k = 1, t = 2
输出:true

示例 3:

输入:nums = [1,5,9,1,5,9], k = 2, t = 3
输出:false

 

提示:

  • 0 <= nums.length <= 2 * 104
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 104
  • 0 <= t <= 231 - 1

 

注意:本题与主站 220 题相同: https://leetcode-cn.com/problems/contains-duplicate-iii/

2、解法1-暴力解法

双层遍历,外层从头到尾遍历,内层遍历外层元素之后的 k 个元素,如果找到两个元素差值的绝对值小于等于 t 则结果为 true

注意:内层只需要遍历后 k 个元素,因为前 k 个元素在外层遍历时已经判断过

3、复杂度

  • 时间复杂度:O(nk)O(nk)
  • 空间复杂度:O(1)O(1)

4、代码

var containsNearbyAlmostDuplicate = function (nums, k, t) {
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j <= i + k && j < nums.length; j++) {
if (Math.abs(nums[j] - nums[i]) <= t) return true;
}
}
return false;
};

5、执行结果

执行用时: 500 ms 内存消耗: 39.1 MB

6、解法2-桶排序

遍历过程中使用桶排序维护 k 个元素的有序集合,桶的大小设置为 t + 1 以保证同一个桶内出现两个元素 n1n2 时,必定有 abs(n1 - n2) <= t 即结果为true,另外如果相邻的桶内有数字且满足与当前数字的差值的绝对值小于等于 t 则结果为 true

7、复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(k)O(k)

8、代码

var containsNearbyAlmostDuplicate = function (nums, k, t) {
const buckets = new Map();
const genIdx = (n) => ((n + 2147483648) / (t + 1)) >> 0;

for (let i = 0; i < nums.length; i++) {
if (i > k) buckets.delete(genIdx(nums[i - k - 1]));
const idx = genIdx(nums[i]);
if (buckets.has(idx)) return true;
if (buckets.has(idx - 1) && nums[i] - buckets.get(idx - 1) <= t) return true;
if (buckets.has(idx + 1) && buckets.get(idx + 1) - nums[i] <= t) return true;
buckets.set(idx, nums[i]);
}

return false;
};

9、执行结果

image.png

· 阅读需 3 分钟

1、题干

请实现一个 MyCalendar 类来存放你的日程安排。如果要添加的时间内没有其他安排,则可以存储这个新的日程安排。

MyCalendar 有一个 book(int start, int end)方法。它意味着在 start 到 end 时间内增加一个日程安排,注意,这里的时间是半开区间,即 [start, end), 实数 x 的范围为,  start <= x < end

当两个日程安排有一些时间上的交叉时(例如两个日程安排都在同一时间内),就会产生重复预订。

每次调用 MyCalendar.book方法时,如果可以将日程安排成功添加到日历中而不会导致重复预订,返回 true。否则,返回 false 并且不要将该日程安排添加到日历中。

请按照以下步骤调用 MyCalendar 类: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)

 

示例:

输入:
["MyCalendar","book","book","book"]
[[],[10,20],[15,25],[20,30]]
输出: [null,true,false,true]
解释:
MyCalendar myCalendar = new MyCalendar();
MyCalendar.book(10, 20); // returns true
MyCalendar.book(15, 25); // returns false ,第二个日程安排不能添加到日历中,因为时间 15 已经被第一个日程安排预定了
MyCalendar.book(20, 30); // returns true ,第三个日程安排可以添加到日历中,因为第一个日程安排并不包含时间 20

 

 

提示:

  • 每个测试用例,调用 MyCalendar.book 函数最多不超过 1000次。
  • 0 <= start < end <= 109

 

注意:本题与主站 729 题相同: https://leetcode-cn.com/problems/my-calendar-i/

2、解题思路

理想解法是使用平衡二叉搜索树,因为其查找和写入的时间复杂度都是 O(logn)O(logn),但是 JS 没有自带这样的数据结构,手写难度较大,因此采用暴力解法实现。

3、复杂度

  • 时间复杂度:O(n2)O(n^2)
  • 空间复杂度:O(n)O(n)

4、代码

var MyCalendar = function () {
this.matrix = [];
};

MyCalendar.prototype.book = function (start, end) {
for (let [s, e] of this.matrix) {
if (!(start > e || end - 1 < s)) return false;
}
return this.matrix.push([start, end - 1]), true;
};

5、执行结果

执行用时: 212 ms 内存消耗: 47.3 MB

· 阅读需 3 分钟

1、题干

给你一个整数数组 nums 和两个整数 kt 。请你判断是否存在 两个不同下标 ij,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k

如果存在则返回 true,不存在返回 false

 

示例 1:

输入:nums = [1,2,3,1], k = 3, t = 0
输出:true

示例 2:

输入:nums = [1,0,1,1], k = 1, t = 2
输出:true

示例 3:

输入:nums = [1,5,9,1,5,9], k = 2, t = 3
输出:false

 

提示:

  • 0 <= nums.length <= 2 * 104
  • -231 <= nums[i] <= 231 - 1
  • 0 <= k <= 104
  • 0 <= t <= 231 - 1

 

注意:本题与主站 220 题相同: https://leetcode-cn.com/problems/contains-duplicate-iii/

2、解法1-暴力解法

双层遍历,外层从头到尾遍历,内层遍历外层元素之后的 k 个元素,如果找到两个元素差值的绝对值小于等于 t 则结果为 true

注意:内层只需要遍历后 k 个元素,因为前 k 个元素在外层遍历时已经判断过

3、复杂度

  • 时间复杂度:O(nk)O(nk)
  • 空间复杂度:O(1)O(1)

4、代码

var containsNearbyAlmostDuplicate = function (nums, k, t) {
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j <= i + k && j < nums.length; j++) {
if (Math.abs(nums[j] - nums[i]) <= t) return true;
}
}
return false;
};

5、执行结果

执行用时: 500 ms 内存消耗: 39.1 MB

6、解法2-桶排序

遍历过程中使用桶排序维护 k 个元素的有序集合,桶的大小设置为 t + 1 以保证同一个桶内出现两个元素 n1n2 时,必定有 abs(n1 - n2) <= t 即结果为true,另外如果相邻的桶内有数字且满足与当前数字的差值的绝对值小于等于 t 则结果为 true

7、复杂度

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(k)O(k)

8、代码

var containsNearbyAlmostDuplicate = function (nums, k, t) {
const buckets = new Map();
const genIdx = (n) => ((n + 2147483648) / (t + 1)) >> 0;

for (let i = 0; i < nums.length; i++) {
if (i > k) buckets.delete(genIdx(nums[i - k - 1]));
const idx = genIdx(nums[i]);
if (buckets.has(idx)) return true;
if (buckets.has(idx - 1) && nums[i] - buckets.get(idx - 1) <= t) return true;
if (buckets.has(idx + 1) && buckets.get(idx + 1) - nums[i] <= t) return true;
buckets.set(idx, nums[i]);
}

return false;
};

9、执行结果

image.png

· 阅读需 3 分钟

1、题干

请实现一个 MyCalendar 类来存放你的日程安排。如果要添加的时间内没有其他安排,则可以存储这个新的日程安排。

MyCalendar 有一个 book(int start, int end)方法。它意味着在 start 到 end 时间内增加一个日程安排,注意,这里的时间是半开区间,即 [start, end), 实数 x 的范围为,  start <= x < end

当两个日程安排有一些时间上的交叉时(例如两个日程安排都在同一时间内),就会产生重复预订。

每次调用 MyCalendar.book方法时,如果可以将日程安排成功添加到日历中而不会导致重复预订,返回 true。否则,返回 false 并且不要将该日程安排添加到日历中。

请按照以下步骤调用 MyCalendar 类: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)

 

示例:

输入:
["MyCalendar","book","book","book"]
[[],[10,20],[15,25],[20,30]]
输出: [null,true,false,true]
解释:
MyCalendar myCalendar = new MyCalendar();
MyCalendar.book(10, 20); // returns true
MyCalendar.book(15, 25); // returns false ,第二个日程安排不能添加到日历中,因为时间 15 已经被第一个日程安排预定了
MyCalendar.book(20, 30); // returns true ,第三个日程安排可以添加到日历中,因为第一个日程安排并不包含时间 20

 

 

提示:

  • 每个测试用例,调用 MyCalendar.book 函数最多不超过 1000次。
  • 0 <= start < end <= 109

 

注意:本题与主站 729 题相同: https://leetcode-cn.com/problems/my-calendar-i/

2、解题思路

理想解法是使用平衡二叉搜索树,因为其查找和写入的时间复杂度都是 O(logn)O(logn),但是 JS 没有自带这样的数据结构,手写难度较大,因此采用暴力解法实现。

3、复杂度

  • 时间复杂度:O(n2)O(n^2)
  • 空间复杂度:O(n)O(n)

4、代码

var MyCalendar = function () {
this.matrix = [];
};

MyCalendar.prototype.book = function (start, end) {
for (let [s, e] of this.matrix) {
if (!(start > e || end - 1 < s)) return false;
}
return this.matrix.push([start, end - 1]), true;
};

5、执行结果

执行用时: 212 ms 内存消耗: 47.3 MB