每日一题 -- 树
恢复二叉搜索树
O(n) 空间复杂度的解法
- 题目首先已经说了,如果用空间复杂度为 O(n) 的解法很简单,那么明显提示可以先中序遍历保存数组,根据数组来解决的方式更简单
- 中序遍历一课 BST, 得到的应该是一个单增的数组,既然题目已知只改动了两个节点,那就是改成如果在数组中移动两个值,使得数组单增
- 我是直接排序出另外一个单增数组,然后直接两个数组作比较得到两个改变值;既然暴力了,就暴力到底
- 然后就是再次中序遍历树,这次只有找到改变值,然后将另外的值赋值过去即可。
- 至于其他更高效的办法,等我级别更高再说吧,毕竟我现在是举三反一,先多做,后面再来一题多解,加油
var recoverTree = function(root) {
const res = []
const dfs = root => {
if(!root) return
dfs(root.left)
res.push(root.val)
dfs(root.right)
}
dfs(root)
const sorted = [...res].sort((a,b) => a-b)
const changedArr=[]
for(let i =0;i<res.length;i++){
if(res[i]!==sorted[i]){
changedArr.push(res[i])
}
}
const [a,b] = changedArr
const dfsToChange = root => {
if(!root) return
dfsToChange(root.left)
if(root.val === a){
root.val = b
}else if(root.val === b){
root.val = a
}
dfsToChange(root.right)
}
dfsToChange(root)
return root
};
91 算法 -- 滑动窗口
定长子串中元音的最大数目
复杂度分析
时间复杂度
- 遍历 s 了, O(n)
- 判断是否为元音字母,用的是对象查找 O(1)
- 所以是 O(N),n 为 s 的长度
空间复杂度
var maxVowels = function (s, k) {
if (s.length < k) return 0
let max = 0
let temp = 0
for (let i = 0; i < s.length; i++) {
if(i>=k){
if(isVowels(s[i-k])) temp--
}
if(isVowels(s[i])) temp++
max = max > temp ? max : temp
}
return max
};
const isVowels = (word) => {
const map = {
'a': 1,
'e': 1,
'i': 1,
'o': 1,
'u': 1
}
if (map[word]) return true
return false
}
LC 的每日一题
547. 省份数量
分析
构建简单的并查集类
- 先构建一个简化版的的并查集类,在这里只需要能够实现合并集合就可以了, rank什么都不要
- 合并的时候也不用考虑是 a 指向 b 还是 b 指向 a,只要能减少size 就好
执行
- 直接两个循环查看二维数组中的值
- 这个数组肯定是长宽一致,且对角线对称的二维数组,不然连线就混乱了,所以只需要判断一半的值即可
- 每当 M[i][j] === 1 ,则这两个城市是一个省份,所以就把这两个集合并成一个
- 初始化是将每个城市都是一个集合,当遍历结束了,那么同一个省的城市已经合并成了一个集合,最后剩下来的集合就是省份隔离,就是省份的数量了。
// https://leetcode-cn.com/problems/number-of-provinces/
class UnionFind {
constructor(size) {
this.parents = Array(size).fill(0).map((_, i) => i) // [1,2,3]
this.numberOfSets = size // set 的个数
}
// 求还有多少个集合
size() {
return this.numberOfSets
}
findSet(x) {
// 如果传入的值和在 this.parents[x] 不一样,代表已经指向另外的集合了,所以需要递归的去查找
if (x !== this.parents[x]) {
this.parents[x] = this.findSet(this.parents[x])
}
// 在没有合并过的集合中,x === this.parents[x]
return this.parents[x]
}
unionSet(x, y) {
const px = this.findSet(x)
const py = this.findSet(y)
if (px === py) return // 在同一个集合中
// 如果不是,则其中一个集合的值指向另外一个集合
this.parents[py] = px
this.numberOfSets--
}
}
const findCircleNum = function(M){
// 有 len 个城市,也是最大的省数
const len = M.length
// 创建一个长度为 len 的并查集
const uf = new UnionFind(len)
for(let i=0;i<len;i++){
for(let j = i+1;j<len;j++){
// 当值为 1 时,证明这两个城市是连接的,所以需要合并这两个集合
M[i][j] === 1 && uf.unionSet(i,j)
}
}
// 最后只需要看看还剩多少个集合,即有多少个城市
return uf.size()
}