1.有序矩阵中第K小的元素
题目:给定一个 n x n
矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k
小的元素。
请注意,它是排序后的第 k
小元素,而不是第 k
个不同的元素。
思路:先来个最简单的,展开成一维数组,然后sort排序
时间复杂度O(n2logn2),空间复杂度O(n2)
/**
* @param {number[][]} matrix
* @param {number} k
* @return {number}
*/
var kthSmallest = function(matrix, k) {
const n = matrix.length;
const list = new Array(n * n);
let v = 0;
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
list[v++] = matrix[i][j];
}
}
list.sort((a, b) => a - b);
return list[k - 1];
};
注意到,矩阵的每一行是有序数组,我们可以记录从0开始每一行对应的下标,先比较出当前最小的那一行,该行对应的下标+1,直到第K个。这个和之前前K对最小数是一样的
时间复杂度O(kn),空间复杂度O(n)
/**
* @param {number[][]} matrix
* @param {number} k
* @return {number}
*/
var kthSmallest = function(matrix, k) {
const n = matrix.length;
let c = 1;
const list = new Array(n).fill(0);
let res = matrix[0][0];
list[0] = 1;
while (c < k) {
let cur = matrix[0][list[0]] ?? Infinity;
let index = 0;
for (let i = 1; i < n; i++) {
if ((matrix[i][list[i]] ?? Infinity) < cur) {
cur = matrix[i][list[i]];
index = i;
}
}
res = cur;
list[index]++;
c++
}
return res;
};
2.常数时间插入、删除和随机获取元素
题目:
设计一个支持在平均 时间复杂度 O(1) 下,执行以下操作的数据结构。
insert(val):当元素 val 不存在时,向集合中插入该项。
remove(val):元素 val 存在时,从集合中移除该项。
getRandom:随机返回现有集合中的一项。每个元素应该有相同的概率被返回
思路:用数组或者set记录数据,随机获取下标即可
每次操作时间复杂度:O(n),空间复杂度O(n)
/**
* Initialize your data structure here.
*/
var RandomizedSet = function () {
this.data = [];
};
/**
* Inserts a value to the set. Returns true if the set did not already contain the specified element.
* @param {number} val
* @return {boolean}
*/
RandomizedSet.prototype.insert = function (val) {
if (this.data.includes(val)) return false;
this.data.push(val);
return true;
};
/**
* Removes a value from the set. Returns true if the set contained the specified element.
* @param {number} val
* @return {boolean}
*/
RandomizedSet.prototype.remove = function (val) {
if (!this.data.includes(val)) return false;
const index=this.data.findIndex(i=>i==val)
this.data.splice(index,1);
return true;
};
/**
* Get a random element from the set.
* @return {number}
*/
RandomizedSet.prototype.getRandom = function () {
const index = ~~(Math.random() * this.data.length);
return this.data[index];
};
3.链表随机节点
题目:
给定一个单链表,随机选择链表的一个节点,并返回相应的节点值。保证每个节点被选的概率一样。
进阶:
如果链表十分大且长度未知,如何解决这个问题?你能否使用常数级空间复杂度实现?
思路:先获取链表长度,然后随机获取下标,然后从头部开始得到模板节点
每次操作时间复杂度:o(n),空间复杂度O(1)
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param head The linked list's head.
Note that the head is guaranteed to be not null, so it contains at least one node.
* @param {ListNode} head
*/
var Solution = function (head) {
this.head = head;
let l = 0;
while (head) {
head = head.next;
l++;
}
this.length = l;
};
/**
* Returns a random node's value.
* @return {number}
*/
Solution.prototype.getRandom = function () {
if (!this.length) return null;
let node = this.head;
let index = ~~(Math.random() * this.length) + 1;
while (--index) {
node=node.next;
}
return node.val;
};
也可以单次遍历链表。对于第i个节点,有1/i的概率将该节点值作为结果。
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param head The linked list's head.
Note that the head is guaranteed to be not null, so it contains at least one node.
* @param {ListNode} head
*/
var Solution = function (head) {
this.head = head;
};
/**
* Returns a random node's value.
* @return {number}
*/
Solution.prototype.getRandom = function () {
if (!this.head) return null;
let v = this.head.val;
let index = 1;
let node = this.head.next;
while (node) {
index++;
if (!~~(Math.random() * index)) {
v = node.val;
}
node = node.next;
}
return v;
};
/**
* Your Solution object will be instantiated and called as such:
* var obj = new Solution(head)
* var param_1 = obj.getRandom()
*/
4.打乱数组
题目:
给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。
实现 Solution
class:
Solution(int[] nums)
使用整数数组nums
初始化对象int[] reset()
重设数组到它的初始状态并返回int[] shuffle()
返回数组随机打乱后的结果
思路:每次根据当前数组长度随机获取一个元素,然后删除当前元素进入下一轮获取
,每次时间复杂度O(n2),空间复杂度O(n)
/**
* @param {number[]} nums
*/
var Solution = function (nums) {
this.data = nums;
};
/**
* Resets the array to its original configuration and return it.
* @return {number[]}
*/
Solution.prototype.reset = function () {
return this.data;
};
/**
* Returns a random shuffling of the array.
* @return {number[]}
*/
Solution.prototype.shuffle = function () {
const l = this.data.length;
const res = new Array(l);
const list = new Array(l).fill('').map((item, i) => i);
for (let i = 0; i < l; i++) {
const index = list.splice(~~(Math.random() * (l - i)), 1)[0];
res[index] = this.data[i];
}
return res;
};
/**
* Your Solution object will be instantiated and called as such:
* var obj = new Solution(nums)
* var param_1 = obj.reset()
* var param_2 = obj.shuffle()
*/
5.字典序排序
题目:
给定一个整数 n, 返回从 1 到 n 的字典顺序。
例如,
给定 n =1 3,返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。
请尽可能的优化算法的时间复杂度和空间复杂度。 输入的数据 n 小于等于 5,000,000。
思路:先说简单的。用数组的sort排序。因为字符串比较时就是字典序比较
时间复杂度O(nlogn),空间复杂度O(n)
/**
* @param {number} n
* @return {number[]}
*/
var lexicalOrder = function(n) {
const res = new Array(n);
for (let i = 1; i <= n; i++) {
res[i - 1] = `${i}`;
}
res.sort();
return res;
};
也可以自定义顺序推入数组。
我们将数字放入一个数组里,每次从头部取出一个数,如果这个数满足条件(小于等于n),那么推入结果。同时将这个数字后面连接0-9的数字形成10个新的数字,推入数组的头部
时间复杂度O(n),空间复杂度O(n)
/**
* @param {number} n
* @return {number[]}
*/
var lexicalOrder = function(n) {
const res = new Array(n);
const stack = ["1", "2", "3", "4", "5", "6", "7", "8", "9"];
let c = 0;
while (c < n) {
const item = stack.shift();
if (+item > n) continue;
res[c++] = item;
const list = new Array(10);
for (let i = 0; i < 10; i++) {
list[i] = `${item}${i}`;
}
stack.unshift(...list);
}
return res;
};