0%

有效的字母异位词

题目

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。

示例 1:

输入: s = “anagram”, t = “nagaram”

输出: true

示例 2:

输入: s = “rat”, t = “car”

输出: false

提示:

1 <= s.length, t.length <= 5 * 104

s 和 t 仅包含小写字母

题解

  • 两个map比较字母数是否相同

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    function isAnagram(s: string, t: string): boolean {
    const strToMap = (s: string) => {
    const strMap = new Map<string, number>();
    for (let i = 0; i < s.length; i++) {
    strMap.set(s[i], (strMap.get(s[i]) || 0) + 1);
    }
    return strMap;
    };
    const sMap = strToMap(s);
    const tMap = strToMap(t);
    if (sMap.size !== tMap.size) {
    return false;
    }
    for (let i of sMap.keys()) {
    if (sMap.get(i) !== tMap.get(i)) {
    return false;
    }
    }
    return true;
    }
  • 便利第一个字符串为map,便利第二个字符串,如果第一个map有,就减去1,最后看smap的数字是否都是0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function isAnagram(s: string, t: string): boolean {
    const strToMap = (s: string) => {
    const strMap = new Map<string, number>();
    for (let i = 0; i < s.length; i++) {
    strMap.set(s[i], (strMap.get(s[i]) || 0) + 1);
    }
    return strMap;
    };
    const sMap = strToMap(s);
    for (let i = 0; i < t.length; i++) {
    if (!sMap.get(t[i])) {
    return false;
    }
    sMap.set(t[i], sMap.get(t[i])! - 1);
    }
    for (let [, v] of sMap) {
    if (v !== 0) {
    return false;
    }
    }
    return true;
    }
  • 排序后遍历

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function isAnagram(s: string, t: string): boolean {
    if (s.length !== t.length) {
    return false;
    }
    const sArr = s.split("").sort();
    const tArr = t.split("").sort();
    for (let i = 0; i < sArr.length; i++) {
    if (sArr[i] !== tArr[i]) {
    return false;
    }
    }
    return true;
    }
  • 字符替换法,耗时比较长

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function isAnagram(s: string, t: string): boolean {
    if (s.length !== t.length) {
    return false;
    }
    for (let i = 0; i < s.length; i++) {
    t = t.replace(s[i], "");
    console.log(t);
    }
    return !t.length;
    }

    来源

  • 作者:力扣 (LeetCode)

  • 链接:https://leetcode-cn.com/leetbook/read/top-interview-questions-easy/xn96us/

  • 来源:力扣(LeetCode)

  • 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

字符串中的第一个唯一字符

题目

给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

示例:

1
2
3
返回 0

``` s = "loveleetcode"

返回 2

提示:你可以假定该字符串只包含小写字母。

题解

  • 双重循环遍历
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function firstUniqChar(s: string): number {
    const strMap = new Map<string, number>();
    for (let i = 0; i < s.length; i++) {
    strMap.set(s[i], (strMap.get(s[i]) || 0) + 1);
    }
    for (let i = 0; i < s.length; i++) {
    if (strMap.get(s[i]) === 1) {
    return i;
    }
    }
    return -1;
    }
  • 索引一致方法
  • 如果找到的第一个索引与倒数找到的最后一个索引相同,代表是第一个
    1
    2
    3
    4
    5
    6
    7
    8
    function firstUniqChar(s: string): number {
    for (let i = 0; i < s.length; i++) {
    if (s.lastIndexOf(s[i]) === s.indexOf(s[i])) {
    return i;
    }
    }
    return -1;
    }

相关链接

题目

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:

1
2
输入:x = 123
输出:321

示例 2:

1
2
输入:x = -123
输出:-321

示例 3:

1
2
输入:x = 120
输出:21

示例 4:

1
2
输入:x = 0
输出:0

答案

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 字符串反转
*/
function reverse(x: number): number {
const isPositive = x >= 0;
const reverseNumberString = `${x}`.replace("-", "").split("").reverse().join("");
const result = isPositive ? +reverseNumberString : -reverseNumberString;
if (result <= (-2) ** 31 || result >= 2 ** 31 - 1) {
return 0;
}
return result;
}

参考链接

啊,年轻时候的我,写的代码还挺规范的嘛。

原来以为那个项目已经挂掉了,没想到现在还在运行。

嗨,从16年开始学前端到现在。。快六年了。真特么快啊。。

擦,刚找自己写的第一个项目竟然没有备案,挂掉了卧槽。

没法装逼,可惜了。

年轻真好…

又想到了以前的很多事情,一个不到20平米的隔断间,住了四个人。

床上睡不下,把床掀了大家一起打地铺。

每天九点上班,五点九下班,下班就去网吧嗨。。

租了一个两室一厅的房子,一个月1200?三个月交一次房租,结果三个月到了,我们没钱交房租了,emmm,直到现在我都不敢一次性交三个月房租。。

啊,那时候是真穷啊。。

不过真的挺快乐。

几个吊毛,天天嗷嗷叫,一起看片,网吧通宵,真刺激

回不去了。。

还是有些对不住的人。。

一时间想起来,有点难过。

emmmm

做的那些事情有用吗。

二十岁的时候,买了十岁买不起的玩具,有什么意义吗

终归是让自己心里好过一点

好多事情,忍不住泪目

果然,晚上不适合瞎J8想。

nestjs 无法注入服务

问题发现

  • 在 viewService 里面导入 UserService,发现一直提示错误,没有找到可以注入的内容
  • 检查了一遍代码,确认逻辑代码没有问题
  • 怀疑是不是循环依赖了,检查代码,发现代码基本与其他 Moduel 的服务相同,没有出现循环依赖的情况
  • 打印 ModuleContainer,在当前 ViewModule 里面找到了导入的 UserModule,也存在 UserService

view.service.ts 尝试打印是否成功导入 UserModule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Injectable()
export class ViewService {
constructor(
private modulesContainer: ModulesContainer,
private userService: UserService,
@InjectRepository(ViewEntity)
private viewEntityRepository: Repository<ViewEntity>
) {
[...modulesContainer.values()].map((module) => {
if (module.metatype.name === "ViewModule") {
console.log("=======imports=======");
console.log(module.imports);
console.log("=======providers======");
console.log(module.providers);
console.log("=======exports======");
console.log(module.exports);

console.log("\n\n\n\n\n");
console.log("=======UserModule exports======");
[...module.imports.values()].map((innerModule) => {
if (innerModule.metatype.name === "UserModule") {
console.log(innerModule.exports);
}
});
}
});
}
}

view.module.ts

1
2
3
4
5
6
7
@Module({
imports: [TypeOrmModule.forFeature([ViewEntity, ViewLikeStatEntity]), UserModule],
controllers: [ViewController],
providers: [ViewService],
exports: [ViewService],
})
export class ViewModule {}

view.service.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export type ViewRelationType = "topic";
export interface JoinListInterface {
uid: string;
avatar: string;
nickname: string;
roler: number;
}
@Injectable()
export class ViewService {
constructor(private readonly userService: UserService, @InjectRepository(ViewEntity) private readonly viewRepository: Repository<ViewEntity>) {}

create(createViewDto: CreateViewDto) {
return "This action adds a new view";
}
...
}

控制台

1
2
3
4
5
6
7
8
[error] 2021-07-28 18:11:32.1 [ExceptionHandler] Nest can't resolve dependencies of the ViewService (?, ViewEntityRepository). Please make sure that the argument dependency at index [0] is available in the ViewModule context.

Potential solutions:
- If dependency is a provider, is it part of the current ViewModule?
- If dependency is exported from a separate @Module, is that module imported within ViewModule?
@Module({
imports: [ /* the Module containing dependency */ ]
})

解决问题

  • 再次检查代码,发现 view.service.ts 导出了三个东西,一个 type,一个 interface,还有一个 viewService 服务
  • 全文查找导出的接口,发现在一个实体里面有这个类型的引入,就是 JoinListInterface.

topic.entity.ts

1
2
3
4
5
6
7
8
9
10
@Entity("topics", { schema: "42how" })
export class TopicEntity {
@PrimaryGeneratedColumn({ type: "bigint", name: "id", unsigned: true })
id: number;

join: {
count?: number;
list?: JoinListInterface[];
} = { count: 0, list: [] };
}
  • 尝试删除 JoinListInterface ,服务注入成功

  • 原本以为 ts 的 interface,type 是不参与到编译过后的 js 文件,检查编译后 topic.entity.js 文件,发现 const view_service_1 = require("../modules/view/view.service"); 这一句,虽然 interface 没有被使用,但是这个 js 文件被引入了。因为这个实体类被引入的比较多,产生了循环依赖,在 nestjs 进行注入的时候,这个文件导出是 undefined,查找不到服务,无法注入。

总结

  • ts 中 export 的类型文件应该单独定义,不要跟逻辑代码放在一个文件。
  • 类型文件虽然没有参与编译,但是会引入文件,如果引用的过于复杂,会导致循环依赖的情况
  • 感谢青木大佬的帮助

想在局域网内访问 wsl 端口

主要工作环境都在wsl里面,有时候想用真机调试,需要局域网访问

TODO
有空写吧

wsl 默认服务启动

原因

习惯了linux的命令行,在windows开发环境下装了wsl2的环境,但是每次windows重启,再打开wsl,服务全都挂了,而且wsl2也没有systemd这种服务,所以想每次打开wsl2的时候,服务都是启动状态

解决

看到印度老哥写的一个脚本

1
2
3
4
5
6
7
8
# /etc/init.wsl
#! /bin/bash
lsof -i:9000 > /dev/null || systemctl start php-fpm
lsof -i:80 > /dev/null || systemctl start nginx
lsof -i:3306 > /dev/null || systemctl start mysqld
lsof -i:6379 > /dev/null || redis-server /etc/redis.conf
# systemctl 是使用的github上一个老哥写的python脚本,好像是这个
# 地址:https://github.com/gdraheim/docker-systemctl-replacement

找个地方保存

然后再打开 .zshrc 或者 .bashrc 再里面把文件的路径填到里面

我的是放再.zshrc里面

1
/etc/init.wsl

这样子每次启动wsl的时候就会启动这些服务

题目

请你判断一个 9x9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

  • 数字 1-9 在每一行只能出现一次。
  • 数字 1-9 在每一列只能出现一次。
  • 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
    数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

注意:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。

题解

  • 暴力解法,用set存数据看是否有重复的
  • 难点在于 方块3*3的计算公式,不知道怎么推导出来的。
  • 自己写的话,需要花好长的时间去慢慢试出来这个公式
  • Math.floor(Math.floor(Math.floor(i / 3) * 3) + Math.floor(j / 3));
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    function isValidSudoku(board: string[][]): boolean {
    for (let i = 0; i < 9; i++) {
    let rowSet = new Set();
    let colSet = new Set();
    let squareSet = new Set();
    for (let j = 0; j < 9; j++) {
    if (board[i][j] != "." && rowSet.has(board[i][j])) {
    return false;
    }
    rowSet.add(board[i][j]);
    if (board[j][i] != "." && colSet.has(board[j][i])) {
    return false;
    }
    colSet.add(board[j][i]);
    let a = Math.floor(Math.floor(Math.floor(i / 3) * 3) + Math.floor(j / 3));
    let b = Math.floor((i % 3) * 3 + (j % 3));
    if (board[a][b] != "." && squareSet.has(board[a][b])) {
    return false;
    }
    squareSet.add(board[a][b]);
    }
    }
    return true;
    }

参考链接

题目

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

1
2
3
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

1
2
输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

1
2
输入:nums = [3,3], target = 6
输出:[0,1]

提示:

1
2
3
4
5
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?

题解

暴力破解

1
2
3
4
5
6
7
8
9
function twoSum(nums: number[], target: number): number[] {
for (let i = 0; i < nums.length - 1; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] === target) {
return [i, j];
}
}
}
}

双指针排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function twoSum(nums: number[], target: number): number[] {
let numsMap = nums.reduce((current, next, index) => {
current.set(index, next);
return current;
}, new Map());
nums = nums.sort((a, b) => a - b);
let rightIndex = nums.findIndex((item) => item > target);
let leftIndex = 0;
rightIndex = rightIndex === -1 ? nums.length - 1 : rightIndex;
while (true) {
if (nums[leftIndex] + nums[rightIndex] === target) {
return [numsMap.get(nums[leftIndex]), numsMap.get(nums[rightIndex])];
}
if (leftIndex % 2 === 0) {
leftIndex++;
} else {
rightIndex--;
}
}
}

map表

1
2
3
4
5
6
7
8
9
10
11
12
function twoSum(nums: number[], target: number): number[] {
let sumMap = new Map();
for (let i = 0; i < nums.length; i++) {
let indexObj = sumMap.get(target - nums[i]);
if (indexObj) {
return [indexObj.index, i];
}
sumMap.set(nums[i], {
index: i,
});
}
}
  • map表解法最优

参考链接

题目

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

1
2
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

说明:

1
2
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
Do not return anything, modify nums in-place instead.
*/
function moveZeroes(nums: number[]): void {
let leftIndex = 0;
let rightIndex = nums.length - 1;
while (leftIndex <= rightIndex) {
if (nums[leftIndex] !== 0) {
leftIndex++;
continue;
}
nums.splice(leftIndex, 1);
nums.push(0);
rightIndex--;
}
}

参考链接