Compare commits

...

3 Commits

Author SHA1 Message Date
cafc1229d5 docs: create 算法/字符串 2024-03-21 11:16:21 +00:00
c588e3de53 docs: create 算法/数组 2024-03-21 11:15:49 +00:00
581b33846f docs: create 算法/链表 2024-03-21 11:15:21 +00:00
3 changed files with 782 additions and 0 deletions

99
算法/字符串.md Normal file
View File

@ -0,0 +1,99 @@
---
title: 字符串
description:
published: true
date: 2024-03-21T11:16:17.692Z
tags: 算法
editor: markdown
dateCreated: 2024-03-21T11:16:17.692Z
---
# 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1
输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2
输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
```ts
/**
Do not return anything, modify s in-place instead.
*/
function reverseString(s: string[]): void {
for (let i = 0, j = s.length - 1; i <= j; i++, j--) {
let tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
};
```
# 反转字符串II
给定一个字符串 s 和一个整数 k从字符串开头算起, 每计数至 2k 个字符,就反转这 2k 个字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入: s = "abcdefg", k = 2
输出: "bacdfeg"
```ts
function reverseStr(s: string, k: number): string {
const str = s?.split('');
let flag = 0;
function reverseString(i: number, j: number): void {
for (; i <= j; i++, j--) {
let tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
};
while (str[flag]) {
if (str[flag + k - 1]) {
reverseString(flag, flag + k - 1)
} else {
reverseString(flag, str?.length - 1)
}
flag += 2 * k
}
return str.join('');
};
```
# 替换数字
给定一个字符串 s它包含小写字母和数字字符请编写一个函数将字符串中的字母字符保持不变而将每个数字字符替换为number。
例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。
对于输入字符串 "a5b",函数应该将其转换为 "anumberb"
输入:一个字符串 s,s 仅包含小写字母和数字字符。
输出打印一个新的字符串其中每个数字字符都被替换为了number
样例输入a1b2c3
样例输出anumberbnumbercnumber
数据范围1 <= s.length < 10000
```ts
const replaceNubmer=(s)=>{
let arr = s.split('');
let str = [];
for(let i = 0;i<arr.length;i++){
if(isNaN(arr[i])){
str=[...str,arr[i]]
}else{
str=[...str,'number']
}
}
return str.join('')
}
```

175
算法/数组.md Normal file
View File

@ -0,0 +1,175 @@
---
title: 数组
description:
published: true
date: 2024-03-21T11:15:46.175Z
tags: 算法
editor: markdown
dateCreated: 2024-03-21T11:15:46.175Z
---
# 二分法
```ts
function search(nums: number[], target: number): number {
let left:number = 0;
let right:number = nums.length - 1;
while (left <= right) {
let mid:number = left + ((right - left) >> 1);
if (nums[mid] < target) {
left = mid + 1;
} else if (nums[mid] > target) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
};
```
# 移除元素
给你一个数组 nums 和一个值 val你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
```ts
function removeElement(nums: number[], val: number): number {
let fast: number = 0, slow: number = 0;
while (fast < nums.length) {
if (nums[fast] !== val) {
nums[slow++]=nums[fast]
}
fast++;
}
return slow;
};
```
# 有序数组的平方
给你一个按 非递减顺序 排序的整数数组 nums返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1
输入nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]
示例 2
输入nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
```ts
function sortedSquares(nums: number[]): number[] {
let resArr: number[] = [];
let i: number = 0, j: number = nums?.length - 1;
while (i <= j) {
if (Math.abs(nums[i]) >= nums[j]) {
resArr.unshift(nums[i] ** 2)
i++;
} else {
resArr.unshift(nums[j] ** 2)
j--;
}
}
return resArr;
};
```
# 长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入s = 7, nums = [2,3,1,2,4,3]
输出2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
```ts
function minSubArrayLen(target: number, nums: number[]): number {
let res: number = nums.length + 1;
let sum: number = 0;
let i: number = 0;
for (let j = 0; j < nums?.length; j++) {
sum += nums[j];
if (sum >= target) {
while (sum - nums[i] >= target) {
sum -= nums[i++];
}
res = Math.min(res, j - i + 1);
}
}
return res === nums.length + 1 ? 0 : res;
};
```
# 螺旋矩阵II
给定一个正整数 n生成一个包含 1 到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。
示例:
输入: 3 输出: [ [ 1, 2, 3 ], [ 8, 9, 4 ], [ 7, 6, 5 ] ]
```ts
function generateMatrix(n: number): number[][] {
let di: number = 0;
const res: number[][] = new Array(n).fill(1).map(i => new Array(n));
let num = 1;
while (di <= n >> 1) {
for (let j: number = di; j < n - di - 1; j++) {
res[di][j] = num++;
}
for (let j: number = di; j < n - di - 1; j++) {
res[j][n - di - 1] = num++;
}
for (let j: number = n - di - 1; j > di; j--) {
res[n - di - 1][j] = num++;
}
for (let j: number = n - di - 1; j > di; j--) {
res[j][di] = num++;
}
di++
}
if (n % 2 === 1) {
res[di - 1][di - 1] = num;
}
return res;
};
```
# 三数之和
给你一个包含 n 个整数的数组 nums判断 nums 中是否存在三个元素 abc ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4]
满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
```ts
function threeSum(nums: number[]): number[][] {
nums.sort((a, b) => a - b);
let length = nums.length;
let left: number = 0,
right: number = length - 1;
let resArr: number[][] = [];
for (let i = 0; i < length; i++) {
if (nums[i]>0) {
return resArr; //nums经过排序后只要nums[i]>0, 此后的nums[i] + nums[left] + nums[right]均大于0,可以提前终止循环。
}
if (i > 0 && nums[i] === nums[i - 1]) {
continue;
}
left = i + 1;
right = length - 1;
while (left < right) {
let total: number = nums[i] + nums[left] + nums[right];
if (total === 0) {
resArr.push([nums[i], nums[left], nums[right]]);
left++;
right--;
while (nums[right] === nums[right + 1]) {
right--;
}
while (nums[left] === nums[left - 1]) {
left++;
}
} else if (total < 0) {
left++;
} else {
right--;
}
}
}
return resArr;
};
```

508
算法/链表.md Normal file
View File

@ -0,0 +1,508 @@
---
title: 链表
description:
published: true
date: 2024-03-21T11:15:17.596Z
tags: 算法
editor: markdown
dateCreated: 2024-03-21T11:15:17.596Z
---
# 移除链表元素
题意:删除链表中等于给定值 val 的所有节点。
示例 1 输入head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]
示例 2 输入head = [], val = 1 输出:[]
示例 3 输入head = [7,7,7,7], val = 7 输出:[]
```ts
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function removeElements(head: ListNode | null, val: number): ListNode | null {
let now = head;
while (now?.next) {
if (now.next.val === val) {
now.next = now.next.next
}else{
now = now.next
}
}
if (head?.val === val) {
head = head?.next
}
return head;
};
```
# 设计链表
在链表类中实现这些功能:
get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度则不会插入节点。如果index小于0则在头部插入节点。
deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
## 我的解法
```ts
// class ListNode {
// public val: number;
// public next: ListNode | null;
// constructor(val?: number, next?: ListNode | null) {
// this.val = val === undefined ? 0 : val;
// this.next = next === undefined ? null : next;
// }
// }
class MyLinkedList {
private head: ListNode | null;
constructor(head?: ListNode | null) {
this.head = head !== undefined ? head : null;
}
get(index: number): number {
let nowIndex = 0;
let now = this.head;
while (nowIndex++ < index) {
if (now.next === null) return -1;
now = now.next;
}
console.log('now', now)
return now?.val !== undefined ? now?.val : -1;
}
addAtHead(val: number): void {
let now = new ListNode();
now.val = val;
now.next = this.head;
this.head = now;
}
addAtTail(val: number): void {
let insertNode = new ListNode();
let virHead = new ListNode();
virHead.next = this.head;
let now = virHead;
while (now.next !== null) {
now = now.next;
}
insertNode.val = val;
now.next = insertNode;
this.head = virHead.next;
}
addAtIndex(index: number, val: number): void {
let nowIndex = -1;
let insertNode = new ListNode();
let virHead = new ListNode();
virHead.next = this.head;
let now = virHead;
while (nowIndex++ < index - 1) {
if (now.next === null) return;
now = now.next;
}
insertNode.next = now?.next || null;
insertNode.val = val;
now.next = insertNode;
this.head = virHead.next;
}
deleteAtIndex(index: number): void {
let nowIndex = -1;
let virHead = new ListNode();
virHead.next = this.head;
let now = virHead;
while (nowIndex++ < index - 1) {
if (now.next === null) return;
now = now.next;
}
now.next = now.next?.next || null;
this.head = virHead.next;
}
}
```
## 带size
```ts
class LinkedNode {
public val: number;
public next: LinkedNode;
constructor(val: number) {
this.val = val;
this.next = null;
}
}
class MyLinkedList {
private size: number
private head: LinkedNode;
constructor() {
this.size = 0;
this.head = new LinkedNode(-1);
}
get(index: number): number {
if (index < 0 || index >= this.size) {
return -1;
}
let curr = this.head;
let i = 0;
while (i < index + 1) {
curr = curr.next;
i++;
}
return curr.val;
}
addAtHead(val: number): void {
this.addAtIndex(0, val);
}
addAtTail(val: number): void {
this.addAtIndex(this.size, val);
}
addAtIndex(index: number, val: number): void {
if (index < 0 || index > this.size ) {
return;
}
let curr = this.head;
let i = 0;
while (i < index) {
curr = curr.next;
i++;
}
const node = new LinkedNode(val);
node.next = curr.next;
curr.next = node;
this.size++;
}
deleteAtIndex(index: number): void {
if (index < 0 || index >= this.size) {
return;
}
let curr = this.head;
let i = 0;
while (i < index) {
curr = curr.next;
i++;
}
curr.next = curr.next.next;
this.size--;
}
}
```
## 带tail
```ts
// class ListNode {
// public val: number;
// public next: ListNode | null;
// constructor(val?: number, next?: ListNode | null) {
// this.val = val === undefined ? 0 : val;
// this.next = next === undefined ? null : next;
// }
// }
class MyLinkedList {
// 记录链表长度
private size: number;
private head: ListNode | null;
private tail: ListNode | null;
constructor() {
this.size = 0;
this.head = null;
this.tail = null;
}
// 获取链表中第 index个节点的值
get(index: number): number {
// 索引无效的情况
if (index < 0 || index >= this.size) {
return -1;
}
let curNode = this.getNode(index);
// 这里在前置条件下,理论上不会出现 null的情况
return curNode.val;
}
// 在链表的第一个元素之前添加一个值为 val的节点。插入后新节点将成为链表的第一个节点。
addAtHead(val: number): void {
let node: ListNode = new ListNode(val, this.head);
this.head = node;
if (!this.tail) {
this.tail = node;
}
this.size++;
}
// 将值为 val 的节点追加到链表的最后一个元素。
addAtTail(val: number): void {
let node: ListNode = new ListNode(val, null);
if (this.tail) {
this.tail.next = node;
} else {
// 还没有尾节点,说明一个节点都还没有
this.head = node;
}
this.tail = node;
this.size++;
}
// 在链表中的第 index个节点之前添加值为 val的节点。
// 如果 index等于链表的长度则该节点将附加到链表的末尾。如果 index大于链表长度则不会插入节点。如果 index小于0则在头部插入节点。
addAtIndex(index: number, val: number): void {
if (index === this.size) {
this.addAtTail(val);
return;
}
if (index > this.size) {
return;
}
// <= 0 的情况都是在头部插入
if (index <= 0) {
this.addAtHead(val);
return;
}
// 正常情况
// 获取插入位置的前一个 node
let curNode = this.getNode(index - 1);
let node: ListNode = new ListNode(val, curNode.next);
curNode.next = node;
this.size++;
}
// 如果索引 index有效则删除链表中的第 index个节点。
deleteAtIndex(index: number): void {
if (index < 0 || index >= this.size) {
return;
}
// 处理头节点
if (index === 0) {
this.head = this.head!.next;
// 如果链表中只有一个元素,删除头节点后,需要处理尾节点
if (index === this.size - 1) {
this.tail = null
}
this.size--;
return;
}
// 索引有效
let curNode: ListNode = this.getNode(index - 1);
curNode.next = curNode.next!.next;
// 处理尾节点
if (index === this.size - 1) {
this.tail = curNode;
}
this.size--;
}
// 获取指定 Node节点
private getNode(index: number): ListNode {
// 这里不存在没办法获取到节点的情况,都已经在前置方法做过判断
// 创建虚拟头节点
let curNode: ListNode = new ListNode(0, this.head);
for (let i = 0; i <= index; i++) {
// 理论上不会出现 null
curNode = curNode.next!;
}
return curNode;
}
}
```
# 翻转链表
## 双指针
```ts
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function reverseList(head: ListNode | null): ListNode | null {
let preNode: ListNode | null = null,
curNode: ListNode | null = head,
tempNode: ListNode | null;
while (curNode) {
tempNode = curNode.next;
curNode.next = preNode;
preNode = curNode;
curNode = tempNode;
}
return preNode;
};
```
## 递归
```ts
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function reverseList(head: ListNode | null): ListNode | null {
function reserve(tail, head) {
if (head === null) {
return tail;
}
let tmp = head.next;
head.next = tail;
tail = head;
return reserve(tail, tmp)
}
return reserve(null, head)
};
```
# 两两交换链表中的节点
示例 1
输入head = [1,2,3,4]
输出:[2,1,4,3]
示例 2
输入head = []
输出:[]
示例 3
输入head = [1]
输出:[1]
```ts
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function swapPairs(head: ListNode | null): ListNode | null {
let virHead = new ListNode();
virHead.next = head;
let cur = virHead;
while (cur.next && cur.next.next) {
let temp = cur.next;
let temp2Next = cur.next.next.next;
cur.next = temp.next;
temp.next.next = temp;
temp.next = temp2Next;
cur = cur.next.next
}
return virHead.next
};
```
# 删除链表的倒数第N个节点
输入head = [1,2,3,4,5], n = 2 输出:[1,2,3,5] 示例 2
输入head = [1], n = 1 输出:[] 示例 3
输入head = [1,2], n = 1 输出:[1]
```ts
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
let times = 0;
const virHead = new ListNode();
virHead.next = head;
let tail = virHead;
let del = virHead;
while (times < n && tail?.next) {
tail = tail.next;
times++
}
if (times < n) return head;
while (tail.next) {
del = del.next;
tail = tail.next;
}
del.next = del.next.next
return virHead.next;
};
```
# 链表相交
![32TO.jpeg](https://img.ocer.cc/images/2024/02/21/32TO.jpeg)
```js
var getIntersectionNode = function (headA, headB) {
let curA = headA;
let curB = headB;
let sizeA = 0, sizeB = 0;
while (curA?.next) {
curA = curA.next;
sizeA++
}
while (curB?.next) {
curB = curB.next;
sizeB++
}
const diffNum = Math.abs(sizeA - sizeB);
curA = headA;
curB = headB;
if (sizeA >= sizeB) {
for (let n = 0; n < diffNum; n++) {
curA = curA.next;
}
} else {
for (let n = 0; n < diffNum; n++) {
curB = curB.next;
}
}
while (curA !== curB) {
curA = curA?.next;
curB = curB?.next;
}
return curA;
};
```
# 环形链表II
![39SV.jpeg](https://img.ocer.cc/images/2024/02/21/39SV.jpeg)
```ts
function detectCycle(head: ListNode | null): ListNode | null {
let fast = head, slow = head;
while (fast !== null && fast.next !== null) {
fast = fast.next.next;
slow = slow.next;
if (fast === slow) {
let index1 = head;
let index2 = fast;
while (index1 !== index2) {
index1 = index1.next;
index2 = index2.next;
}
return index2
}
}
return null;
};
```