算法打卡3

12/10/2022打卡算法

#数字范围按位与

地址(opens new window)

function rangeBitwiseAnd(left: number, right: number): number {
    if (left === right || left === 0) {
        return left
    }
    if (left.toString(2).length !== right.toString(2).length) {
        return 0
    }
    let result = left
    for (let i = left + 1; i <= right; i++) {
        result &= i
    }
    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13

#只出现一次的数字 II

地址(opens new window)

function singleNumber(nums: number[]): number {
    const obj = {}
    for(const num of nums) {
        if (!obj[num]) {
            obj[num] = 0
        }
        obj[num] += 1
    }

    for(const num of nums) {
        if (obj[num] === 1) {
            return num
        }
    }
    return nums[0]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 思路:如果3个数相等,那么相加起来一定能被3整除
function singleNumber(nums: number[]): number {
    let ans = 0;
    for (let i = 0; i < 32; ++i) {
        let total = 0;
        for (const num of nums) {
            total += ((num >> i) & 1);
        }

        // 存在
        if (total % 3 !== 0) {
            ans |= (1 << i);
        }
    }
    return ans;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#只出现一次的数字

地址(opens new window)

// 亦或
function singleNumber(nums: number[]): number {
    let result = nums[0]
    for(let i = 1; i < nums.length; i++) {
        result ^= nums[i]
    }
    return result
};
1
2
3
4
5
6
7
8

#颠倒二进制位

地址(opens new window)

function reverseBits(n: number): number {
	return Number.parseInt(n.toString(2).split('').reverse().join('').padEnd(32, '0'),2)
};
1
2
3

#二进制求和

地址(opens new window)

function addBinary(a: string, b: string): string {
    const len = Math.max(a.length, b.length)
    if (a.length < len) {
        a = a.padStart(len, '0')
    } else {
        b = b.padStart(len, '0')
    }

    let result = ''
    let left = 0
    for (let i = len - 1; i >= 0; i--) {
        const sum = Number(a[i]) + Number(b[i]) + left
        if (sum <= 1) {
            left = 0
            result = sum.toString() + result
        } else {
            let val = sum % 2
            result = val.toString() + result
            left = sum - (val === 0 ? 1 : 2)
        }
    }
    if (left > 0) {
        result = '1' + result
    }
    return result
};
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

#最大正方形

地址(opens new window)

function maximalSquare(matrix: string[][]): number {
   // 先循环遍历一遍,统一x轴方向和y轴方向的1
    const m = matrix[0].length
    const n = matrix.length
    const x: number[][] = []
    for(let i = 0; i < n; i++) {
        x[i] = []
        for(let j = 0; j < m; j++) {
            if (j === 0) {
                x[i][j] = matrix[i][j] === '0' ? 0 : 1
            } else {
                if (matrix[i][j] === '0') {
                    x[i][j] = 0
                } else {
                    x[i][j] = x[i][j-1] + 1
                }
            }
        }
    }

    const y: number[][] = []
    for(let i = 0; i < m; i++) {
        y[i] = []
        for(let j = 0; j < n; j++) {
            if (j === 0) {
                y[i][j] = matrix[j][i] === '0' ? 0 : 1
            } else {
                if (matrix[j][i] === '0') {
                    y[i][j] = 0
                } else {
                    y[i][j] = y[i][j-1] + 1
                }
            }
        }
    }

    // 正方形最大面积
    let result = 0
    // i和j表示是否为正方形
    const dp: number[][] = []

    for(let i = 0; i < n; i++) {
        dp[i] = []
        for(let j = 0; j < m; j++) {
            if (matrix[i][j] === '0') {
                dp[i][j] = 0
            } else {
                // 判断是否为正方形
                const val = Math.min(dp[i-1]?.[j-1] ?? -1, x[i][j] - 1, y[j][i] - 1)

                if (val > 0 && x[i][j] > val && y[j][i] > val) {
                    dp[i][j] = val + 1
                } else {
                    dp[i][j] = 1
                }
                result = Math.max(result, dp[i][j] ** 2)
            }
        }
    }
    return result
};
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
function maximalSquare(matrix: string[][]): number {
   // 先循环遍历一遍,统一x轴方向和y轴方向的1
    const m = matrix[0].length
    const n = matrix.length

    // 正方形最大边长
    let result = 0
    // i和j表示以i和j为右下角的最大正方形边长度
    const dp: number[][] = []

    for(let i = 0; i < n; i++) {
        dp[i] = []
        for(let j = 0; j < m; j++) {
            if (matrix[i][j] === '0') {
                dp[i][j] = 0
            } else {
                // 判断是否为正方形
                dp[i][j] = Math.min(dp[i-1]?.[j-1] ?? 0, dp[i-1]?.[j] ?? 0, dp[i][j-1] ?? 0) + 1
                result = Math.max(result, dp[i][j])
            }
        }
    }
    return result ** 2
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#最长回文子串

地址(opens new window)

解题思路(opens new window)

function longestPalindrome(s: string): string {
    // dp[i][j] 表示从i到j是否是回文
    const len = s.length
    const dp: boolean[][] = []
    let str = s[0]

    for(let i = len - 1; i >= 0; i--) {
        dp[i] = []
        for(let j = len - 1; j >= i; j--) {
            if (j - i === 0) {
                dp[i][j] = true
            } else if (j - i === 1) {
                dp[i][j] = s[i] === s[j]
            } else {
                dp[i][j] = dp[i+1][j-1] && s[i] === s[j]
            }

            if (dp[i][j] && j - i + 1 > str.length) {
                str = s.slice(i, j + 1)
            }
        }
    }
    return str
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

#最小路径和

地址(opens new window)

function minPathSum(grid: number[][]): number {
    const m = grid[0].length
    const n = grid.length

    // 第一层直接相加
    for(let i = 1; i < m; i++) {
        grid[0][i] += grid[0][i - 1]
    }

    for(let i = 1; i < grid.length; i++) {
        for(let j = 0; j < m; j++) {
            grid[i][j] += Math.min(grid[i-1][j], grid[i][j-1] ?? grid[i-1][j])
        }
    }
    return grid[n-1][m-1]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#三角形最小路径和

地址(opens new window)

function minimumTotal(triangle: number[][]): number {
    let dp: number[] = [triangle[0][0]]
    for (let i = 1; i < triangle.length; i++) {
        for (let j = 0; j < triangle[i].length; j++) {
            triangle[i][j] += Math.min(dp[j] ?? dp[j - 1], dp[j - 1] ?? dp[j])
        }
        dp = [...triangle[i]]
    }
    return Math.min(...dp)
};
1
2
3
4
5
6
7
8
9
10
// 不需要dp
function minimumTotal(triangle: number[][]): number {
    for (let i = 1; i < triangle.length; i++) {
        for (let j = 0; j < triangle[i].length; j++) {
            triangle[i][j] += Math.min(triangle[i - 1][j] ?? triangle[i - 1][j - 1], triangle[i - 1][j - 1] ?? triangle[i - 1][j])
        }
    }
    return Math.min(...triangle.pop()!)
};
1
2
3
4
5
6
7
8
9

#交错字符串

地址(opens new window)

// 运行失败,但是逻辑是可行的,使用回溯
function isInterleave(s1: string, s2: string, s3: string): boolean {
    const len1 = s1.length
    const len2 = s2.length
    const len3 = s3.length

    if (len1 + len2 !== len3) {
        return false
    }

    const cascader = (s1: string, s2: string, start: number, isS1 = true, m = 0, n = 0) => {
        if (start === len3) {
            return Math.abs(m - n) <= 1
        }

        for (let i = start; i < len3; i++) {
            const word = s3.slice(start, i + 1)
            if (isS1) {
                if (s1.startsWith(word)) {
                    if (cascader(s1.slice(i - start + 1), s2, i + 1, false, m + 1, n)) {
                        return true
                    }
                } else {
                    return false
                }
            } else {
                if (s2.startsWith(word)) {
                    if (cascader(s1, s2.slice(i - start + 1), i + 1, true, m, n + 1)) {
                        return true
                    }
                } else {
                    return false
                }
            }
        }

        return false
    }

    return cascader(s1, s2, 0, false) || cascader(s1, s2, 0, true)
};
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
29
30
31
32
33
34
35
36
37
38
39
40
41
// 动态规划
function isInterleave(s1: string, s2: string, s3: string): boolean {
    const len1 = s1.length
    const len2 = s2.length
    const len3 = s3.length

    if (len1 + len2 !== len3) {
        return false
    }

    if (len1 === 0 && len2 === 0 && len3 === 0) {
        return true
    }

    // dp[i][j] 表示s1的前i个和s2的前j个能否组成s3的前i + j个
    const dp: boolean[][] = []
    dp[0] = [true]
    for(let i = 0; i <= len1; i++) {
        if (!dp[i]) {
            dp[i] = []
        }
        for(let j = 0; j <= len2; j++) {
            if (i > 0) {
                dp[i][j] = s1[i-1] === s3[i+j-1] && dp[i-1][j]
            }

            if (j > 0) {
                dp[i][j] ||= s2[j-1] === s3[i+j-1] && dp[i][j-1]
            }
        }
    }
    return dp[len1][len2]
};
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
29
30
31
32
33

#阶乘后的零

地址(opens new window)

解题思路(opens new window)

function trailingZeroes(n: number): number {
    if (n === 0) {
        return 0
    }
    let result = 0
    let fiveNum = 0

    for (let i = 1; i <= n; i++) {
        let num = i
        while (num % 10 === 0) {
            num /= 10
            result++
        }

        while (num % 5 === 0) {
            num /= 5
            fiveNum++
        }
    }

    return result + Math.min(fiveNum, twoNum)
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#相同的树

地址(opens new window)

function isSameTree(p: TreeNode | null, q: TreeNode | null): boolean {
    if (p && !q || (!p && q)) {
        return false
    }

    if (!p && !q) {
        return true
    }

    return p.val === q.val && isSameTree(p.left, q.left) && isSameTree(p.right, q.right)
};
1
2
3
4
5
6
7
8
9
10
11

#求根节点到叶节点数字之和

地址(opens new window)

递归解法解题思路(opens new window)

// 递归解法
function sumNumbers(root: TreeNode | null): number {
    if (!root) {
        return 0
    }
    let result = 0
    const cascader = (root: TreeNode | null, num = '') => {
        if (!root) {
            return
        }

        if (!root.left && !root.right) {
            result += Number(num + root.val)
            return
        }

        if (root.left) {
            cascader(root.left, num + root.val)
        }
        if (root.right) {
            cascader(root.right, num + root.val)
        }
    }
    cascader(root)
    return result
};
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
// 迭代解法
function sumNumbers(root: TreeNode | null): number {
    if (!root) {
        return 0
    }
    let result = 0
    const nodes = [root]

    while(nodes.length) {
        const node = nodes.shift()!

        if (!node.left && !node.right) {
            result += node.val
        } else {
            if (node.left) {
                node.left.val = Number(node.val.toString() + node.left.val)
                nodes.push(node.left)
            }

            if (node.right) {
                node.right.val = Number(node.val.toString() + node.right.val)
                nodes.push(node.right)
            }
        }
    }

    return result
};
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

#汇总区间

地址(opens new window)

function summaryRanges(nums: number[]): string[] {
    const result: string[] = []
    const len = nums.length
    if (len === 0) {
        return []
    }

    let start = nums[0].toString()
    nums.push(nums[0])
    for (let i = 1; i < nums.length; i++) {
        if (nums[i] - 1 !== nums[i - 1]) {
            if (start !== nums[i - 1].toString()) {
                result.push(`${start}->${nums[i - 1]}`)
            } else {
                result.push(start)
            }
            start = nums[i].toString()
        }
    }

    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

#单词规律

地址(opens new window)

function wordPattern(pattern: string, s: string): boolean {
    const arr = s.split(' ')
    if (arr.length !== pattern.length) {
        return false
    }
    const map = new Map()
    for(let i = 0; i < arr.length; i++) {
        // 避免不同字符对应相同单词
        if (map.has(pattern[i]) || map.has('$' + arr[i])) {
            if (arr[i] !== map.get(pattern[i])) {
                return false
            }
        } else {
            map.set(pattern[i], arr[i])
            map.set('$' + arr[i], pattern[i])
        }
    }
    return true
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function wordPattern(pattern: string, s: string): boolean {
    const arr = s.split(' ')
    if (arr.length !== pattern.length) {
        return false
    }
    const set = new Set()
    for(let i = 0; i < arr.length; i++) {
        if (set.has(arr[i]) || set.has(pattern[i] + '_')) {
            if (!set.has(arr[i] + '_' + pattern[i])) {
                return false
            }
        } else {
            set.add(arr[i])
            set.add(arr[i] + '_' + pattern[i])
            set.add(pattern[i] + '_')
        }
    }
    return true
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#相对名次

地址(opens new window)

function findRelativeRanks(score: number[]): string[] {
    const newArr = [...score].sort((a, b) => b - a)
    const map = new Map<number, number>()
    for(let i = 0; i < newArr.length; i++) {
        map.set(newArr[i], i)
    }
    const result: string[] = []
    for(let i = 0; i < score.length; i++) {
        const index = map.get(score[i])
        if (index === 0) {
            result[i] = 'Gold Medal'
        } else if (index === 1) {
            result[i] = 'Silver Medal'
        } else if (index === 2) {
            result[i] = 'Bronze Medal'
        } else {
            result[i] = (index + 1).toString()
        }
    }
    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

#最长连续序列

地址(opens new window)
解释说明(opens new window)

function longestConsecutive(nums: number[]): number {
    const set = new Set(nums)
    let result = 0

    while(set.size) {
        const value = set.values().next().value
        let loopNum = value - 1
        let val = 1
        while (set.has(loopNum)) {
            set.delete(loopNum)
            val++
            loopNum--
        }

        loopNum = value + 1
        while (set.has(loopNum)) {
            set.delete(loopNum)
            val++
            loopNum++
        }
        result = Math.max(result, val)
        set.delete(value)
    }
    return result
};
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
// 官方解法
function longestConsecutive(nums: number[]): number {
    const set = new Set(nums)
    let result = 0
    for (let num of set) {
        if (!set.has(num - 1)) {
            let val = 1
            while(set.has(num + 1)) {
                num++
                val++
            }
            result = Math.max(result, val)
        }
    }
    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#两数之和 II - 输入有序数组

地址(opens new window)

// 时间复杂度为O(nlogn),空间复杂度O(1)
function twoSum(numbers: number[], target: number): number[] {
    const len = numbers.length

    for (let i = 0; i < len; i++) {
        let prev = i + 1
        let last = len - 1
        const val = target - numbers[i]
        while (prev < last) {
            let mid = Math.ceil((prev + last) / 2)
            if (numbers[mid] === val) {
                return [i + 1, mid + 1]
            } else if (numbers[mid] > val) {
                last = mid - 1
            } else {
                prev = mid
            }
        }

        if (val === numbers[prev]) {
            return [i + 1, prev + 1]
        }
    }

    // 不存在的值
    return [-1, -1]
};
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
function twoSum(numbers: number[], target: number): number[] {
    const len = numbers.length

    for (let i = 0; i < len; i++) {
        if (target - numbers[i] > numbers[len - 1]) {
            continue
        }
        const index = numbers.indexOf(target - numbers[i], i + 1)
        if (index > -1) {
            return [i + 1, index + 1]
        }
    }

    // 不存在的值
    return [-1, -1]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 双指针
// 时间复杂度为O(n),空间复杂度为O(1)
function twoSum(numbers: number[], target: number): number[] {
    let prev = 0
    let last = numbers.length - 1
    while (prev < last) {
        const sum = numbers[prev] + numbers[last]
        if (sum === target) {
            return [prev + 1, last + 1]
        } else if (sum > target) {
            last--
        } else {
            prev++
        }
    }

    // 不存在的值
    return [-1, -1]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#除自身以外数组的乘积

地址(opens new window)

function productExceptSelf(nums: number[]): number[] {
    const len = nums.length

    // 从左扫到右,获取除当前值的乘积
    const resultLeft: number[] = [1]
    const resultRight: number[] = []
    resultRight[len - 1] = 1

    for (let i = 1; i < len; i++) {
        resultLeft[i] = nums[i - 1] * resultLeft[i - 1]
    }

    // 从右扫到左,获取当前值的乘积
    for (let i = len - 2; i >= 0; i--) {
        resultRight[i] = nums[i + 1] * resultRight[i + 1]
    }

    for (let i = 0; i < len; i++) {
        nums[i] = resultLeft[i] * resultRight[i]
    }
    return nums
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function productExceptSelf(nums: number[]): number[] {
    const len = nums.length

    // 从左扫到右,获取除当前值的乘积
    const result: number[] = [1]

    for (let i = 1; i < len; i++) {
        result[i] = nums[i - 1] * result[i - 1]
    }

    let num = nums[len - 1]
    for (let i = len - 2; i >= 0; i--) {
        result[i] *= num
        num *= nums[i]
    }
    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#O(1) 时间插入、删除和获取随机元素

地址(opens new window)

// 解题思路来源于教程
class RandomizedSet {
    private idxVal: Map<number, number>
    private arr: number[] = []

    constructor() {
        this.idxVal = new Map()
    }

    insert(val: number): boolean {
        if (this.idxVal.has(val)) {
            return false
        }
        const index = this.arr.length
        this.arr.push(val)
        this.idxVal.set(val, index)
        return true
    }

    remove(val: number): boolean {
        if (!this.idxVal.has(val)) {
            return false
        }
        const id = this.idxVal.get(val)!
        this.arr[id] = this.arr[this.arr.length - 1]
        this.arr.pop()
        this.idxVal.set(this.arr[id], id)
        this.idxVal.delete(val)
        return true
    }

    getRandom(): number {
        return this.arr[Math.floor(this.arr.length * Math.random())];
    }
}
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
29
30
31
32
33
34
35

#删除有序数组中的重复项 II

地址(opens new window)

解题思路(opens new window)

function removeDuplicates(nums: number[]): number {
    const len = nums.length
    if (len === 1) {
        return 1
    }

    let prev = len - 2
    let num = 1

    while (prev >= 0) {
        // 判断是否需要删除
        if (nums[prev] === nums[prev+1]) {
            num++
            if (num > 2) {
                while (nums[prev] === nums[prev+1] && prev >= 0) {
                    nums.splice(prev, 1)
                    prev--
                }
                num = 1
            }
        } else {
            num = 1
        }
        prev--
    }
    return nums.length
};
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
function removeDuplicates(nums: number[]): number {
    const len = nums.length
    let prev = 1
    let next = 1
    let num = 1

    while (prev < len) {
        // 判断是否需要删除
        if (nums[prev] === nums[prev-1]) {
            num++
            if (num > 2) {
                while (nums[prev] === nums[prev-1] && prev < len) {
                    prev++
                }

                num = 1
            }
        } else {
            num = 1
        }

        if (prev < len) {
            nums[next++] = nums[prev++]
        }
    }

    nums.length = next
    return next
};
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
29

官方解题思路中把num这个变量给删除了,通过排序这个特点来判断是否超过了两个

function removeDuplicates(nums: number[]): number {
    const len = nums.length
    if (len <= 2) {
        return len
    }
    let fast = 2
    let slow = 2

    while (fast < len) {
        if (nums[fast] !== nums[slow - 2]) {
            nums[slow] = nums[fast]
            ++slow
        }
        fast++
    }
    return slow
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#H 指数

地址(opens new window)

// console.log(hIndex([100]));
// console.log(hIndex([1,100]));
// console.log(hIndex([1,2]));
// console.log(hIndex([11,15]));
// console.log(hIndex([1,11,15]));
// console.log(hIndex([2,4,8,9,9,3]));
// console.log(hIndex([0]));
function hIndex(citations: number[]): number {
    const len = citations.length

    // 排序
    citations.sort((a, b) => a - b)
    let result = 0
    let i = 0
    while(i < len) {
        if (citations[i - 1] === citations[i]) {
            i++
        } else {
            if (len - i >= citations[i]) {
                result = citations[i++]
            } else {
                // 这一步容易出错
                result = Math.max(result, len - i)
                break
            }
        }
    }

    return result
};
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
29
30

解题思路(opens new window)

function hIndex(citations: number[]): number {
    const len = citations.length

    // 排序
    citations.sort((a, b) => a - b)
    let result = 0
    let i = 0
    while(i < len) {
        // 起码存在 len - i 篇 论文至少被引用了 citations[i] 次
        if (len - i > citations[i]) {
            // 不满足需求
            i++
        } else if(len - i <= citations[i]) {
            result = len - i
            break
        }
    }

    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

计数排序

// 判断论文数与引用次数篇数
function hIndex(citations: number[]): number {
    const len = citations.length
    const arr = Array.from<number>({ length: len + 1 }).fill(0)
    for (let i = 0; i < len; i++) {
        if (citations[i] >= len) {
            arr[len]++
        } else {
            arr[citations[i]]++
        }
    }
    let result = len
    let total = 0
    while (result > 0) {
        total += arr[result]
        if (total >= result) {
            return result
        }
        result--
    }

    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

#多数元素

地址(opens new window)

// 注意单个的情况
// 时间复杂度O(n),空间复杂度O(n/2)就是O(n)
function majorityElement(nums: number[]): number {
    const len = nums.length
    if (!len) {
        return 0
    }

    if (len === 1) {
        return nums[0]
    }
    const half = Math.floor(len / 2)
    const obj = {}
    for (const num of nums) {
        if (obj[num]) {
            obj[num] += 1
            if (obj[num] > half) {
                return num
            }
        } else {
            obj[num] = 1
        }
    }
    return 0
};
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
// 中间的值肯定是多数元素
// 时间复杂度O(nlogn),空间复杂度为logn
function majorityElement(nums: number[]): number {
    nums.sort((a, b) => a - b)
    return nums[Math.floor(nums.length / 2)]
};
1
2
3
4
5
6
// Boyer-Moore 投票算法
// 基本含义就是不同的数值相互抵消
// 时间复杂度为O(n),空间复杂度为O(1)
function majorityElement(nums: number[]): number {
    let time = 1
    let cur = nums[0]
    for (let i = 1; i < nums.length; i++) {
        if (nums[i] === cur) {
            time++
        } else {
            if (time === 0) {
                cur = nums[i]
            } else {
                time--
            }
        }
    }
    return cur
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#合并两个有序数组

地址(opens new window)

function merge(nums1: number[], m: number, nums2: number[], n: number): void {
    let start = 0
    for(let i = 0; i < n; i++) {
        while(nums2[i] >= nums1[start] && start < m + i) {
            start++
        }

        // 合适的位置插入值
        nums1.splice(start, 0, nums2[i])
    }
    nums1.length = m + n
};
1
2
3
4
5
6
7
8
9
10
11
12
// 逆向双指针
function merge(nums1: number[], m: number, nums2: number[], n: number): void {
    let p1 = m - 1
    let p2 = n - 1
    let all = m + n - 1
    let cur = 0

    while (p1 >= 0 || p2 >= 0) {
        if (p1 < 0) {
            cur = nums2[p2--]
        } else if (p2 < 0) {
            cur = nums1[p1--]
        } else if (nums1[p1] > nums2[p2]) {
            cur = nums1[p1--]
        } else {
            cur = nums2[p2--]
        }
        nums1[all--] = cur
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

#最大连续1的个数 III

地址(opens new window)

function longestOnes(nums: number[], k: number): number {
    let m = 0
    let prev = 0
    let next = 0
    const len = nums.length
    let result = 0

    while(next < len) {
        // 如果遇到1那么什么都不做
        if (nums[next]) {
            next++
            continue
        }

        // 如果碰到0,那么需要判断,如果未达到翻转上限,那么继续下去
        if (m < k) {
            m++
            next++
            continue
        }

        // 达到翻转上限
        result = Math.max(result, next - prev)

        while(prev < len && nums[prev] === 1) {
            prev++
        }
        prev++
        next++
    }
    return Math.max(result, next - prev)
};
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
29
30
31
32

#存在重复元素 II

地址(opens new window)

function containsNearbyDuplicate(nums: number[], k: number): boolean {
    const obj: Record<number, number> = {}
    for(let i = 0; i < nums.length; i++) {
        if (typeof obj[nums[i]] === 'number') {
            if (i - obj[nums[i]] <= k) {
                return true
            }
        }
        obj[nums[i]] = i
    }
    return false
};
1
2
3
4
5
6
7
8
9
10
11
12
// 滑动窗口
function containsNearbyDuplicate(nums: number[], k: number): boolean {
    const set = new Set()
    for(let i = 0; i < nums.length; i++) {
        if (i > k) {
            set.delete(nums[i-k-1])
        }
        if (set.has(nums[i])) {
            return true
        }
        set.add(nums[i])
    }
    return false
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14

#二叉搜索树与双向链表

地址(opens new window)

var treeToDoublyList = function(root) {
   if (!root) {
       return root
   }

   let prev = null
   let head = null

   const cascader = (root) => {
       if (!root) {
           return root
       }

       // 左
       cascader(root.left)
       if (prev) {
        prev.right = root
       } else {
        head = root
       }

       root.left = prev
       prev = root

       // 右
       cascader(root.right)
   }

   cascader(root)
   head.left = prev
   prev.right = head
   return head
};
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
29
30
31
32
33

#单词搜索

地址(opens new window)

function exist(board: string[][], word: string): boolean {
    const m = board.length
    const n = board[0].length
    const obj: Record<string, boolean> = {}

    const cascader = (col = 0, row = 0, len = 0) => {
        if (len === word.length) {
            return true
        }

        if (len > 0) {
            // 如果重复或者不相等
            if (obj[`${col}_${row}`] || board[col][row] !== word[len]) {
                return false
            }

            obj[`${col}_${row}`] = true

            // 往右走
            if (row < n - 1 && cascader(col, row + 1, len + 1)) {
                return true
            }

            // 往左走
            if (row > 0 && cascader(col, row - 1, len + 1)) {
                return true
            }

            // 往上走
            if (col > 0 && cascader(col - 1, row, len + 1)) {
                return true
            }

            // 往下走
             if (col < m - 1 && cascader(col + 1, row, len + 1)) {
                return true
            }

            obj[`${col}_${row}`] = false
            return false
        }

        for(let i = 0; i < m; i++) {
            for(let j = 0; j < n; j++) {
                if (obj[`${i}_${j}`] || board[i][j] !== word[len]) {
                    continue
                }

                if (word.length === 1) {
                    return true
                }

                obj[`${i}_${j}`] = true

                // 往右走
                if (j < n - 1 && cascader(i, j + 1, len + 1)) {
                    return true
                }

                // 往左走
                if (j > 0 && cascader(i, j - 1, len + 1)) {
                    return true
                }

                // 往上走
                if (i > 0 && cascader(i - 1, j, len + 1)) {
                    return true
                }

                if (i < m - 1 && cascader(i + 1, j, len + 1)) {
                    return true
                }

                obj[`${i}_${j}`] = false
            }
        }

        return false
    }

    return cascader()
};
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 把上一个函数优化
function exist(board: string[][], word: string): boolean {
    const m = board.length
    const n = board[0].length
    const obj: Record<string, boolean> = {}

    const cascader = (col = 0, row = 0, len = 0) => {
        // 如果重复或者不相等
        if (obj[`${col}_${row}`] || board[col][row] !== word[len]) {
            return false
        }

        len += 1
        obj[`${col}_${row}`] = true

        if (len === word.length) {
            return true
        }

        // 往右走
        if (row < n - 1 && cascader(col, row + 1, len)) {
            return true
        }

        // 往左走
        if (row > 0 && cascader(col, row - 1, len)) {
            return true
        }

        // 往上走
        if (col > 0 && cascader(col - 1, row, len)) {
            return true
        }

        // 往下走
        if (col < m - 1 && cascader(col + 1, row, len)) {
            return true
        }

        obj[`${col}_${row}`] = false
        len -= 1
        return false
    }

     for(let i = 0; i < m; i++) {
        for(let j = 0; j < n; j++) {
            if (board[i][j] !== word[0]) {
                continue
            }

            if (cascader(i, j, 0)) {
                return true
            }
        }
    }

    return false
};
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

#设计前中后队列

地址(opens new window)

class FrontMiddleBackQueue {
    arr: number[]

    constructor() {
        this.arr = []
    }

    pushFront(val: number): void {
        this.arr.unshift(val)
    }

    pushMiddle(val: number): void {
        const i = Math.floor(this.arr.length / 2)
        this.arr.splice(i, 0, val)
    }

    pushBack(val: number): void {
        this.arr.push(val)
    }

    popFront(): number {
        return this.arr.shift() ?? -1
    }

    popMiddle(): number {
        const i = Math.ceil(this.arr.length / 2) - 1
        return this.arr.splice(i, 1)[0] ?? -1
    }

    popBack(): number {
        return this.arr.pop() ?? -1
    }
}
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
29
30
31
32
33

#将整数减少到零需要的最少操作数

地址(opens new window)

function minOperations(n: number): number {
    let m = 0
    let result = 0

    while (n) {
        m = Math.log2(n)

        if (m === n) {
            return result
        }

        n = Math.min(n - 2 ** Math.floor(m), 2 ** Math.ceil(m) - n)
        result++
    }

    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#合并两个二维数组 - 求和法

地址(opens new window)

function mergeArrays(nums1: number[][], nums2: number[][]): number[][] {
    const result = nums1.map(item => [item[0], item[1]])
    let j = 0
    const len2 = nums2.length
    let i = 0

    while(i < len2) {
        if (result[j]?.[0] === undefined || result[j][0] > nums2[i][0]) {
            result.splice(j, 0, nums2[i])
            j++
            i++
            continue
        }
        if (result[j][0] === nums2[i][0]) {
            result[j][1] += nums2[i][1]
            j++
            i++
            continue
        }
        if (result[j][0] < nums2[i][0]) {
            j++
        }
    }
    return result
};
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

#最小无法得到的或值

地址(opens new window)

function minImpossibleOR(nums: number[]): number {
    const set = new Set([...nums])

    let i = 1
    if (!set.has(1)) {
        return 1
    }

    while (i) {
        if (set.has(i)) {
            i++
            continue
        }

        // 判断是否存在,如果前面都存在,那么求出都是1的二进制的值,然后继续
        const num = Number.parseInt((i - 1).toString(2).replace(/0/g, '1'), 2)
        i = num + 1

        if (set.has(i)) {
            continue
        }

        return i
    }

    return i
};
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

#修改两个元素的最小分数

地址(opens new window)

function minimizeSum(nums: number[]): number {
  const len = nums.length
    if (len === 3) {
        return 0
    }

    nums.sort((a, b) => a - b)
    // 要么修改最前面两个
    // 要么修改最后面两个
    // 要么修改最前一个和最后一个
    return Math.min(nums[len - 1] - nums[2], nums[len - 3] - nums[0], nums[len - 2] - nums[1])
};
1
2
3
4
5
6
7
8
9
10
11
12

#替换一个数字后的最大差值

地址(opens new window)

function minMaxDifference(num: number): number {
    const str = num.toString()
    const len = str.length
    let i = 0
    while(i < len) {
        if (Number(str[i]) < 9) {
            break
        }
        i++
    }

    const max = i === len ? num : str.replace(new RegExp(str[i], 'g'), '9')
    const min = str.replace(new RegExp(str[0], 'g'), '0')
    return Number(max) - Number(min)
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#链表的中间结点

地址(opens new window)

// 时间复杂度O(n),空间复杂度O(1)
function middleNode(head: ListNode | null): ListNode | null {
    if (!head) {
        return head
    }
    let node = head
    let m = 0
    while(node) {
        m++
        node = node.next
    }

    let half = Math.ceil((m - 1) / 2)
    m = 0
    node = head
    while(m < half) {
        node = node.next
        m++
    }
    return node
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function middleNode(head: ListNode | null): ListNode | null {
    if (!head) {
        return head
    }

    let prev = head
    let n = head

    while(n?.next) {
        prev = prev.next
        n = n.next.next
    }

    return prev
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#复制带随机指针的链表

地址(opens new window)

function copyRandomList(head: Node | null): Node | null {
    if (!head) {
        return head
    }
    const map = new WeakMap()
    let node = head
    let i = 0

    const result: Node = new Node(head.val)
    let node1 = result
    const resultArr: Node[] = [node1]

    // 先遍历一遍
    while(node) {
        if (i) {
            node1.next = new Node(node.val)
            node1 = node1.next
            resultArr.push(node1)
        }

        map.set(node, i++)
        node = node.next
    }

    // 设置random
    node = head
    node1 = result
    i = 0

    while(node) {
        node1.random = resultArr[map.get(node.random)]
        node1 = node1.next
        node = node.next
        i++
    }
    return result
};
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
29
30
31
32
33
34
35
36
37

#扁平化多级双向链表

地址(opens new window)

// 拆出值,然后一个一个封装进去
function flatten(head: Node | null): Node | null {
    if (!head) {
        return null
    }

    const arr: number[] = []
    const stack: number[] = []
    let cur = head
    while (cur) {
        arr.push(cur.val)
        if (!cur.child) {
            cur = cur.next
            continue
        }
        let node = cur.next
        let arr1: number[] = []
        while(node) {
            arr1.push(node.val)
            node = node.next
        }
        stack.unshift(...arr1)
        cur = cur.child
    }
    arr.push(...stack)
    let node = new Node(arr[0])
    cur = node
    for(let i = 1; i < arr.length; i++) {
        cur.next = new Node(arr[i], cur)
        cur = cur.next
    }
    return node
};
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
29
30
31
32
33
function flatten(head: Node | null): Node | null {
       if (!head) {
        return null
    }

    let cur = head
    while(cur) {
        // 是否存在子元素
        if (!cur.child) {
            cur = cur.next
            continue
        }

        let node1 = cur.child
        while(node1.next) {
            node1 = node1.next
        }

        // 如果存在next
        if (cur.next) {
            cur.next.prev = node1
            node1.next = cur.next
        }
        cur.child.prev = cur
        cur.next = cur.child
        cur.child = null
        cur = cur.next
    }
    return head
};
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
29
30

#两数相加 II

地址(opens new window)

// 拆分成数组然后从后往前加
function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | null {
    if (!l1) {
        return l2
    }

    if (!l2) {
        return l1
    }

    const arr1: number[] = []
    const arr2: number[] = []
    let node = l1
    while(node) {
        arr1.push(node.val)
        node = node.next
    }
    node = l2
    while(node) {
        arr2.push(node.val)
        node = node.next
    }

    const arr3: number[] = []
    let add = 0
    while(arr1.length || arr2.length) {
        let sum = (arr1.pop() ?? 0) + (arr2.pop() ?? 0) + add
        if (sum > 9) {
            add = 1
        } else {
            add = 0
        }
        sum = sum > 9 ? sum % 10 : sum

        arr3.unshift(sum)
    }
    if (add === 1) {
        arr3.unshift(1)
    }
    let cur = new ListNode(arr3.shift())
    node = cur
    while(arr3.length) {
        node.next = new ListNode(arr3.shift())
        node = node.next
    }
    return cur
};
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

#子字符串异或查询

地址(opens new window)

function substringXorQueries(s: string, queries: number[][]): number[][] {
    const arr: string[] = queries.map(([a, b]) => (b ^ a).toString(2))
    const result: number[][] = []

    for (let j = 0; j < arr.length; j++) {
        const index = s.indexOf(arr[j])
        if (index > -1) {
            result.push([index, arr[j].length + index - 1])
        } else {
            result.push([-1,-1])
        }
    }

    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#找出数组的串联值

地址(opens new window)

function findTheArrayConcVal(nums: number[]): number {
    let sum = 0
    const len = nums.length
    if (!len) {
        return sum
    }

    while(nums.length) {
        if (nums.length === 1) {
            return sum + nums[0]
        }

        sum += Number.parseInt((nums.shift() ?? 0 ).toString() + (nums.pop() ?? 0).toString())
    }

    return sum
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#合并两个链表

地址(opens new window)

// 注意审题,不是相等,是下标
function mergeInBetween(list1: ListNode | null, a: number, b: number, list2: ListNode | null): ListNode | null {
     let delPrev: ListNode | null = null
    let delNext: ListNode | null = null
    const node = new ListNode(0, list1)
    let cur = node
    let n = 0

    while (cur) {
        if (n === a) {
            delPrev = cur
        }

        if (n === b + 1) {
            delNext = cur.next
            break
        }

        cur = cur.next
        n++
    }

    delPrev.next = list2
    cur = list2
    while(cur.next) {
        cur = cur.next
    }

    cur.next = delNext
    return node.next
};
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
29
30
31

#交换链表中的节点

地址(opens new window)

// 时间复杂度为O(n),空间复杂度为O(1)
function swapNodes(head: ListNode | null, k: number): ListNode | null {
    if (!head) {
        return head
    }
    let sum = 0
    let node = head

    // 正数节点
    let fast = head
    while(node) {
        if (sum === k - 1) {
            fast = node
        }
        sum++
        node = node.next
    }

    node = head
    // 倒数节点
    let slow = head
    let n = 0
    while(node) {
        if (n === sum - k) {
            slow = node
            break
        }
        n++
        node = node.next
    }

    n = fast.val
    fast.val = slow.val
    slow.val = n

    return head
};
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
29
30
31
32
33
34
35
36
37
// 时间复杂度为O(n),空间复杂度为O(n)
function swapNodes(head: ListNode | null, k: number): ListNode | null {
    if (!head) {
        return head
    }
    const stack: ListNode[] = []
    let node = head
    while(node) {
        stack.push(node)
        node = node.next
    }
    const num = stack[k-1].val
    const end = stack[stack.length - k]

    stack[k - 1].val = end.val
    end.val = num
    return head
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function swapNodes(head: ListNode | null, k: number): ListNode | null {
    if (!head) {
        return head
    }
    const stack: ListNode[] = []
    let node: ListNode | null = head
    while(node) {
        stack.push(node)
        node = node.next
    }

    // 在中间不需要换
    if (k === stack.length - k + 1) {
        return head
    }

    stack.unshift(new ListNode(0, head))
    let min = k - 1
    let end = stack.length - k - 1
    if (min > end) {
        min = end
        end = k - 1
    }

    const s = stack[min]
    const e = stack[end]

    const n = s.next
    const e2 = e.next

    s.next = s.next?.next ?? null
    e.next = e.next?.next ?? null

    // 相互挨着的情况
    if (end - min === 1) {
        s.next!.next = e
        return stack[0].next
    }

    if (n) {
        n.next = e.next
        e.next = n
    }

    if (e2) {
        e2.next = s.next
        s.next = e2
    }

    return stack[0].next
};
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

#找出临界点之间的最小和最大距离

地址(opens new window)

// 时间复杂度为O(n),空间复杂度为O(1)
function nodesBetweenCriticalPoints(head: ListNode | null): number[] {
    if (!head || !head.next || !head.next.next) {
        return [-1, -1]
    }

    let max = -1
    let min = Infinity
    let minPrev = -1
    let prev = -1
    let end = 0

    while (head.next.next) {
        if (head.next.val > head.val && head.next.val > head.next.next.val || (head.next.val < head.val && head.next.val < head.next.next.val)) {
            if (prev !== -1) {
                max = end - minPrev + 1
                min = Math.min(end - prev + 1, min)
            }

            prev = end + 1
            if (minPrev === -1) {
                minPrev = prev
            }
        }
        end++
        head = head.next
    }

    return [Number.isFinite(min) ? min : -1, max]
};
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
29
30

#螺旋矩阵 IV

地址(opens new window)

// 时间复杂度为O(m * n),空间复杂度为O(m * n)
function spiralMatrix(m: number, n: number, head: ListNode | null): number[][] {
    const result: number[][] = Array.from({ length: m }, () => [])
    let left = 0
    let right = n - 1
    let top = 0
    let bottom = m - 1
    while (top <= bottom) {
        // 从左到右
        for(let i = left; i <= right; i++) {
            if (result[top][i] !== undefined) {
                break
            }
            result[top][i] = head?.val ?? -1
            head = head?.next
        }

        // 从上到下
        for(let i = top + 1; i <= bottom; i++) {
            if (result[i][right] !== undefined) {
                break
            }
            result[i][right] = head?.val ?? -1
            head = head?.next
        }

        // 从右到左
        for(let i = right - 1; i >= left; i--) {
            if (result[bottom][i] !== undefined) {
                break
            }
            result[bottom][i] = head?.val ?? -1
            head = head?.next
        }

        // 从下到上
        for(let i = bottom - 1; i > top; i--) {
            if (result[i][left] !== undefined) {
                break
            }
            result[i][left] = head?.val ?? -1
            head = head?.next
        }

        if (left < right) {
            left++
            right--
        }
        top++
        bottom--
    }
    return result
};
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

#从链表中移除节点

地址(opens new window)

// 时间复杂度O(n)、空间复杂度为O(n)
function removeNodes(head: ListNode | null): ListNode | null {
    if (!head) {
        return null
    }

    const arr: number[] = []
    while(head) {
        while(arr.length && head.val > arr[arr.length - 1]) {
            arr.pop()
        }
        arr.push(head.val)
        head = head.next
    }
    if (!arr.length) {
        return null
    }
    const node = new ListNode(arr[0])
    let cur = node
    for(let i = 1; i < arr.length; i++) {
        cur.next = new ListNode(arr[i])
        cur = cur.next
    }
    return node
};
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
// 递归
// 时间复杂度O(n),空间复杂度O(n)
function removeNodes(head: ListNode | null): ListNode | null {
    if (!head || !head.next) {
        return head
    }

    let node = removeNodes(head.next)
    if (node && head.val < node.val) {
        return node
    }

    head.next = node

    return head
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#搜索旋转排序数组

地址(opens new window)

// 时间复杂度为O(logn),空间复杂度为O(1)
function search(nums: number[], target: number): number {
    let start = 0
    let end = nums.length - 1

    while(start < end) {
        let mid = Math.floor((start + end) / 2)

        if (nums[mid] === target) {
            return mid
        }

        // 中间的值处于左边递增的情况
        if (nums[mid] > nums[end]) {
            if (nums[mid] > target && nums[start] <= target) {
                end = mid
            } else {
                start = mid + 1
            }
            continue
        }

        if (nums[mid] < target && nums[end] >= target) {
            start = mid + 1
        } else {
            end = mid
        }
    }

    return nums[start] === target ? start : -1
};
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
29
30
31
function search(nums: number[], target: number): number {
    let start = 0
    let end = nums.length - 1

    while(start < end) {
        let mid = Math.floor((start + end) / 2)

        if (nums[mid] === target) {
            return mid
        }

        if ((nums[mid] > nums[end] && (nums[mid] < target || nums[start] > target)) || (nums[mid] < nums[end] && nums[mid] < target && nums[end] >= target)) {
            start = mid + 1
        } else {
            end = mid
        }
    }

    return nums[start] === target ? start : -1
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

#合并K个升序链表

地址(opens new window)

// ?时间复杂度O(nm + nlogn),空间复杂度为O(n)
function mergeKLists(lists: Array<ListNode | null>): ListNode | null {
    const nums: number[] = []
    for(let i = lists.length - 1; i >=0; i--) {
        let list = lists[i]
        while(list) {
            nums.push(list.val)
            list = list.next
        }
    }
    if (!nums.length) {
        return null
    }
    nums.sort((a, b) => a - b)
    const head = new ListNode(nums[0])
    let node = head
    for(let i = 1; i < nums.length; i++) {
        node.next = new ListNode(nums[i])
        node = node.next
    }
    return head
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 参考下面的两两合并
// ?时间复杂度为O(n(m+n)),空间复杂度为O(m+n)
function mergeKLists(lists: Array<ListNode | null>): ListNode | null {
    if (!lists.length) {
        return null
    }

    let result = lists[0]
    for(let i = 1; i < lists.length; i++) {
        result = mergeTwoLists(result, lists[i])
    }
    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13

#合并两个有序链表

地址(opens new window)

// 迭代
// 时间复杂度O(m+n),空间复杂度为O(1)
function mergeTwoLists(list1: ListNode | null, list2: ListNode | null): ListNode | null {
    if (!list1) {
        return list2
    }

    if (!list2) {
        return list1
    }

    const result = new ListNode(-100, list1)
    let node = result

    while (node.next && list2) {
        if (node.next.val <= list2.val) {
            node = node.next
            continue
        }
        node.next = new ListNode(list2.val, node.next)
        list2 = list2.next
        node = node.next
    }

    if (!node.next) {
        node.next = list2
    }

    return result.next
};
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
29
30
// 递归
// 时间复杂度为O(m+n),空间复杂度为O(m+n)
function mergeTwoLists(list1: ListNode | null, list2: ListNode | null): ListNode | null {
    if (!list1) {
        return list2
    }

    if (!list2) {
        return list1
    }

    if (list1.val < list2.val) {
        list1.next = mergeTwoLists(list1.next, list2)
        return list1
    }

    list2.next = mergeTwoLists(list1, list2.next)
    return list2
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#删除链表的中间节点

地址(opens new window)

// 快慢指针,时间复杂度为O(n)、空间复杂度为O(1)
function deleteMiddle(head: ListNode | null): ListNode | null {
    if (!head || !head.next) {
        return null
    }

    let slow: ListNode | null = head
    let fast = head.next.next
    while(fast?.next) {
        slow = slow?.next ?? null
        fast = fast.next.next
    }
    if (slow?.next) {
        slow.next = slow.next.next
    }
    return head
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#回文链表

地址(opens new window)

// 时间复杂度为O(n),空间复杂度为O(n)
function isPalindrome(head: ListNode | null): boolean {
    // 也可以使用字符串
    const arr: number[] = []
    while(head) {
        arr.push(head.val)
        head = head.next
    }

    for (let i = 0, j = arr.length - 1; i < j; i++, j--) {
        if (arr[i] !== arr[j]) {
            return false
        }
    }

    return true
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 递归写法
// 时间复杂度 时间复杂度为O(n) 空间复杂度O(n)
function isPalindrome(head: ListNode | null): boolean {
    let prev = head
    const cascader = (cur: ListNode | null) => {
        if (!cur) {
            return true
        }

        let bool = cascader(cur.next)
        if (!bool) {
            return false
        } else if (prev.val !== cur.val) {
            return false
        }

        prev = prev.next
        return true
    }

    return cascader(head)
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 时间复杂度为O(n), 空间复杂度为O(1)
// 先获取中间位置的节点,然后反转右半部分的节点,然后进行对比
function isPalindrome(head: ListNode | null): boolean {
   if (!head || !head.next) {
       return true
   }
   const getMid = (head: ListNode | null) => {
       let slow = head
       let fast = head.next

       while (fast) {
           fast = fast.next?.next
           slow = slow.next
       }

       return slow
   }
   const reverse = (head: ListNode | null) => {
       let prev = null
       let cur = head
       while(cur) {
           let next = cur.next
           cur.next = prev
           prev = cur
           cur = next
       }
       return prev
   }
   let prev = getMid(head)
   let next = reverse(prev)

   while(head && next) {
       if (head.val !== next.val) {
           return false
       }
       head = head.next
       next = next.next
   }

   return true
};
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
29
30
31
32
33
34
35
36
37
38
39
40
41

#对链表进行插入排序

地址(opens new window)

// 时间复杂度O(n^2) 空间复杂度O(1)
function insertionSortList(head: ListNode | null): ListNode | null {
    if (!head) {
        return head
    }

    let node = new ListNode(head.val)
    head = head.next
    while (head) {
        let cur: ListNode | null = node
        while (cur.next && cur.next.val < head.val) {
            cur = cur.next
        }

        if (cur.val > head.val) {
            node = new ListNode(head.val, node)
        } else {
            cur.next = new ListNode(head.val, cur.next)
        }

        head = head.next
    }

    return node
};
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
// 时间复杂度O(n^2) 空间复杂度O(1)
function insertionSortList(head: ListNode | null): ListNode | null {
    if (!head) {
        return head
    }

    // 空节点
    let node = new ListNode(0, head)

    // 排序后链表的最后一个节点
    let lastNode: ListNode | null = head

    // 未排序的第一个节点
    let cur = head.next
    while(cur) {
        if (lastNode!.val <= cur.val) {
            lastNode = lastNode!.next
        } else {

            // 找到需要排序前的一个节点,然后改变指针指向
            let prev = node
            while(prev && prev.next!.val < cur.val) {
                prev = prev.next!
            }
            lastNode!.next = cur.next
            cur.next = prev.next
            prev.next = cur
        }

        cur = lastNode!.next
    }

    return node.next
};
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
29
30
31
32
33
34

#排序链表

地址(opens new window)

// 时间复杂度为O(nlogn),空间复杂度为O(n)
function sortList(head: ListNode | null): ListNode | null {
    const arr: number[] = []
    while(head) {
        arr.push(head.val)
        head = head.next
    }
    arr.sort((a, b) => a - b)
    let node = new ListNode(0)
    let cur = node
    for (const val of arr) {
        cur.next = new ListNode(val)
        cur = cur.next
    }
    return node.next
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#链表组件

地址(opens new window)

// 时间复杂度为O(n),空间复杂度为O(m)
function numComponents(head: ListNode | null, nums: number[]): number {
    const set = new Set(nums)
    let cur = head
    let result = 0
    let num = 0

    while(cur) {
        if (set.has(cur.val)) {
            if (num === 0) {
                result++
            }
            num++
        } else {
            num = 0
        }
        cur = cur.next
    }

    return result
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 参考官方解法,把num改成一个boolean
function numComponents(head: ListNode | null, nums: number[]): number {
    const set = new Set(nums)
    let cur = head
    let result = 0
    let isFirst = true

    while(cur) {
        if (set.has(cur.val)) {
            if (isFirst) {
                result++
                isFirst = false
            }
        } else {
            isFirst = true
        }
        cur = cur.next
    }

    return result
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

#分隔链表

地址(opens new window)

// 时间复杂度O(n)、空间复杂度O(n)
function splitListToParts(head: ListNode | null, k: number): Array<ListNode | null> {
    let sum = 0
    let cur = head
    let arr: (ListNode | null)[] = []

    while(cur) {
        cur = cur.next
        sum++
    }

    cur = head
    let n = Math.ceil(sum / k)
    sum -= n
    k--

    while(cur) {
        if (n === 1) {
            n = Math.ceil(sum / k)
            sum -= n
            k--
            let next = cur.next
            cur.next = null
            arr.push(head)
            head = next
            cur = next
            continue
        }

        cur = cur.next
        n--
    }

    for (let i = 0; i <= k; i++) {
        arr.push(null)
    }

    return arr
};
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
29
30
31
32
33
34
35
36
37
38
39
function splitListToParts(head: ListNode | null, k: number): Array<ListNode | null> {
    let cur = head
    let sum = 0
    let arr: (ListNode | null)[] = []

    while(cur) {
        sum++
        cur = cur.next
    }

    cur = head
    let m = 0
    for (let i = k; i > 0; i--) {
        m = Math.ceil(sum / i)
        sum -= m
        if (m === 0) {
            arr.push(null)
            continue
        }

        while(m > 1) {
            cur = cur.next
            m--
        }
        let next = cur.next
        cur.next = null
        arr.push(head)
        head = next
        cur = next
    }
    return arr
};
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
29
30
31
32
// 递归解法
// 时间复杂度O(n)、空间复杂度O(n)
function splitListToParts(head: ListNode | null, k: number): Array<ListNode | null> {
    let cur = head
    let sum = 0
    let arr: (ListNode | null)[] = []

    while(cur) {
        sum++
        cur = cur.next
    }

    for (let i = k; i > sum; i--) {
        arr.push(null)
        k--
    }

    let n = Math.floor(sum / k)
    sum -= n
    k--
    const cascader = (head: ListNode | null) => {
        if (!head) {
            return head
        }
        const node = cascader(head.next)
        n--

        if (n === -1) {
            n = Math.floor(sum / k)
            k--
            sum -= n
            arr.unshift(node)
            head.next = null
            n--
            return head
        }

        return head
    }

   cascader(head)
   if (head) {
       arr.unshift(head)
   }
   return arr
};
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

#数组中字符串的最大值

地址(opens new window)

function maximumValue(strs: string[]): number {
    // 使用正则判断是否存在字符串
    const reg = /[a-z]/
    let num = 0
    for (const str of strs) {
        num = Math.max(num, reg.test(str) ? str.length : Number.parseInt(str))
    }

    return num
};
1
2
3
4
5
6
7
8
9
10

#更多

Last Updated:5/25/2024, 2:23:06 AM