150

150

Q114.ts

 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
/**
 * 展开后的单链表应该同样使用 TreeNode 
 * 其中 right 子指针指向链表中下一个结点,
 * 而左子指针始终为 null 
 * 展开后的单链表应该与二叉树 先序遍历 顺序相同。
 */

class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;
    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = val === undefined ? 0 : val;
        this.left = left === undefined ? null : left;
        this.right = right === undefined ? null : right;
    }
}

/**
 Do not return anything, modify root in-place instead.
 */
function flatten(root: TreeNode | null): void {
    let cur = root;
    let next, pre;
    while (cur !== null) {
        if (cur.left !== null) {
            next = cur.left;
            pre = next;
            while (pre.right !== null) pre = pre.right;
            pre.right = cur.right;
            cur.left = null;
            cur.right = next;
        }
        cur = cur.right;
    }
}

Q120.ts

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * 给定一个三角形 triangle ,找出自顶向下的最小路径和。
 * 每一步只能移动到下一行中相邻的结点上。
 * 相邻的结点 在这里指的是 下标 与 上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。
 * 也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 i 或 i + 1 。
 * @param triangle
 * @returns
 */
function minimumTotal(triangle: number[][]): number {
    let len: number = triangle.length,
        floor: Array<number> = new Array(len);
    floor[0] = triangle[0][0];

    for (let i: number = 1; i < len; i++) {
        floor[i] = floor[i - 1] + triangle[i][i];
        for (let j: number = i - 1; j > 0; j--) {
            floor[j] = Math.min(floor[j - 1], floor[j]) + triangle[i][j];
        }
        floor[0] += triangle[i][0];
    }
    return Math.min.apply(Math, floor);
}

Q121.ts

 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
/**
 * 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。
设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
 
提示:
1 <= prices.length <= 105
0 <= prices[i] <= 104
 */

function maxProfit(prices: number[]): number {
    let minPrice = prices[0],
        maxProfit = 0,
        tmp = 0;
    if (prices.length < 2) return 0;
    for (let i = 1; i < prices.length; i++) {
        tmp = prices[i];
        if (tmp < minPrice) {
            minPrice = tmp;
        } else if (tmp - minPrice > maxProfit) {
            maxProfit = tmp - minPrice;
        }
    }
    return maxProfit;
}

Q122.ts

 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
/**
 * 给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。
你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

 

示例 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 
这笔交易所能获得利润 = 5 - 1 = 4。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 
这笔交易所能获得利润 = 6 - 3 = 3。
最大总利润为 4 + 3 = 7 。
示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 
这笔交易所能获得利润 = 5 - 1 = 4。
最大总利润为 4 。
示例 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0。
 

提示:

1 <= prices.length <= 3 * 104
0 <= prices[i] <= 104
 * @param prices 
 */

// 其实找出每次升值的区间(非减区间),将每次的升值求和即可,可用贪心,以1为单位
function maxProfit(prices: number[]): number {
    let maxProfit = 0;
    for (let i = 1; i < prices.length; i++) {
        maxProfit += Math.max(0, prices[i] - prices[i - 1]);
    }
    return maxProfit;
}

Q129.ts

 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
/**
 * 给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0  9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:

例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 
计算从根节点到叶节点生成的 所有数字之和 

叶节点 是指没有子节点的节点。
 */

class TreeNode {
    val: number;
    left: TreeNode | null;
    right: TreeNode | null;
    constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
        this.val = val === undefined ? 0 : val;
        this.left = left === undefined ? null : left;
        this.right = right === undefined ? null : right;
    }
}

const dfs = (root: TreeNode | null, prevSum: number) => {
    if (root === null) {
        return 0;
    }
    const sum = prevSum * 10 + root.val;
    if (root.left == null && root.right == null) return sum;
    return dfs(root.left, sum) + dfs(root.right, sum);
};

function sumNumbers(root: TreeNode | null): number {
    return dfs(root, 0);
}

Q134.ts

 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
/**
 * 在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。
你从其中的一个加油站出发,开始时油箱为空。
给定两个整数数组 gas  cost ,如果你可以按顺序绕环路行驶一周,
则返回出发时加油站的编号,否则返回 -1 。如果存在解,则 保证 它是 唯一 的。
 */

function canCompleteCircuit(gas: number[], cost: number[]): number {
    let i = 0;
    while (i < gas.length) {
        let sumOfGas = 0,
            sumOfCost = 0;
        let count = 0;
        while (count < gas.length) {
            const next = (i + count) % gas.length; // 
            sumOfCost += cost[next];
            sumOfGas += gas[next];
            if (sumOfCost > sumOfGas) break;
            count++;
        }
        if (count == gas.length) {
            return i;
        } else {
            // 开不到count+1,直接到count+1的加油站
            i = i + count + 1;
        }
    }
    return -1;
}

Q138.js

 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
function _Node(val, next, random) {
    this.val = val;
    this.next = next;
    this.random = random;
}

/**
 * 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random 
 * 该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 
深拷贝应该正好由 n  全新 节点组成,
其中每个新节点的值都设为其对应的原节点的值。
新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,
并使原链表和复制链表中的这些指针能够表示相同的链表状态。
复制链表中的指针都不应指向原链表中的节点 

例如,如果原链表中有 X  Y 两个节点,
其中 X.random --> Y 
那么在复制链表中对应的两个节点 x  y ,同样有 x.random --> y 

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0  n-1);如果不指向任何节点,则为  null 
你的代码  接受原链表的头节点 head 作为传入参数。

 * @param {_Node} head
 * @return {_Node}
 */

var copyRandomList = function (head) {
    if (head === null) return null;
    for (let node = head; node !== null; node = node.next.next) {
        const nodeNew = new _Node(node.val, node.next, node.random);
        node.next = nodeNew;
    }
    for (let node = head; node != null; node = node.next.next) {
        const nodeNew = node.next;
        nodeNew.random = node.random !== null ? node.random.next : null;
    }
    const headNew = head.next;
    for (let node = head; node !== null; node = node.next) {
        const nodeNew = node.next;
        node.next = node.next.next;
        nodeNew.next = nodeNew.next !== null ? nodeNew.next.next : null;
    }
    return headNew;
};

Q139.ts

 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
/**
 * 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。
 * 如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true
 * 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。
 * @param s
 * @param wordDict
 * @returns
 */
function wordBreak(s: string, wordDict: string[]): boolean {
    const len: number = s.length;
    const wordDictSet: Set<string> = new Set(wordDict);
    const dp: Array<boolean> = new Array(len + 1).fill(false);

    dp[0] = true;
    for (let i = 1; i <= len; i++) {
        // dp里存的第0-n个字母在不在里面
        // 第一个循环判断第一个字母在不在里面
        // 第二个循环判断前两个不行的话判断第1-2
        for (let j = 0; j < i; j++) {
            if (dp[j] && wordDictSet.has(s.substring(j, i))) {
                dp[i] = true;
                break;
            }
        }
    }
    return dp[len];
}
Licensed under CC BY-NC-SA 4.0
最后更新于 Mar 30, 2025 10:07 UTC