这次只做出了前三题。最后一题我算了一下枚举复杂度也大概是 10!=3628800 左右,但是就老是 TLE。今天早上用 C 重新写了一下就过了。有点郁闷。

第一题Find N Unique Integers Sum up to Zero

找 n 个和为 0 且各不相同的数。

每次加入 i 和 -i 就能保证和为0。如果 n 是奇数,那么我们要添加 0。

class Solution:
    def sumZero(self, n: int) -> List[int]:
        ans = []
        if n & 1:
            ans.append(0)
        for i in range(1, n//2 + 1):
            ans.append(i)
            ans.append(-i)
        return ans

第二题All Elements in Two Binary Search Trees

按升序排列两二叉搜索树中的所有树。

二叉搜索树中序遍历能给出升序的数列,我们可以按照这个性质合并这两二叉搜索树:得到两个排好序的数列,然后合并这两个数列。但是为了快速写出这道题,我就将所有数收集到一个数组,调用函数排个序。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def getAllElements(self, root1: TreeNode, root2: TreeNode) -> List[int]:
        ans = []

        def dfs(root):
            if not root:
                return
            ans.append(root.val)
            dfs(root.left)
            dfs(root.right)

        dfs(root1)
        dfs(root2)

        ans.sort()

        return ans

第三题Jump Game III

给定一个数组 arr。在 i 位置时,我们可以跳到 i + arr[i] 或者 i - arr[i]。 问:从 start 出发,是否可以跳到一个值为 0 的位置。

宽度优先搜索:每次跳到下一个可以跳到而且没有跳到过的点,一直到值为 0 的位置或者没有办法继续跳为止。

class Solution:
    def canReach(self, arr: List[int], start: int) -> bool:
        if arr[start] == 0:
            return True
        n = len(arr)
        visited = set()
        stack = [start]
        visited.add(start)

        while stack:
            x = stack.pop()
            for y in [x + arr[x], x - arr[x]]:
                if 0 <= y < n and y not in visited:
                    if arr[y] == 0:
                        return True
                    stack.append(y)
                    visited.add(y)
        return False

第四题Verbal Arithmetic Puzzle

给定一个以单词组成的等式,问是否存在字母与数字的一一对应,使得等式成立。

首先做一个预处理,由这个单词组成等式变成字母的等式。比如

SEND + MORE = MONEY

可以变成
1000S + 100E + 10N + D + 1000M + 100O + 10R + E - 10000M - 1000O - 100N - 10E - Y = 0,

进一步化简为
1000S + 91E - 90N + D - 9000M - 900O + 10R - Y = 0.

现在我们可以枚举字母可能对应的数字即可。这里要注意一个限制,单词中第一个字母不能为 0。我们可以给出每个字母对应的数字范围。一般的字母的数字范围是从 0 到 9,而出现在单词首端的字母则从 1 到 9。我们还可以利用等式缩小某些字母的数字范围。

我用 Python 实现上述算法总是 TLE,连利用等式缩小数字范围这种优化也没有逃过 TLE。然后今天早上用 C 实现一下就过了。。。不用优化也能过的那种。

int get_multiplier(int *mult, int *nonzero, char *word, int p) {
    int n = strlen(word);
    char *str = word + n;
    while (str != word) {
        str --;
        int idx = *str - 'A';
        if (str == word)
            nonzero[idx] = 1;
        mult[idx] += p;
        p *= 10;
    }
    return 0;
}

int dfs(int *low, int *high, int *vals, int n, int i, int cur, int used, bool *ret) {
    if (*ret)
        return 0;
    if (i == n) {
        if (cur == 0)
            *ret = true;
        return 0;
    }
    for (int d = low[i]; d <= high[i]; d ++) {
        if ((used >> d) & 1)
            continue;
        dfs(low, high, vals, n, i+1, cur+d*vals[i], used|(1<<d), ret);
    }
    return 0;
}

bool isSolvable(char ** words, int wordsSize, char * result){
    int mult[26] = {0};
    int nonzero[26] = {0};
    int n = 0;
    int vals[26];
    int low[26];
    int high[26];
    bool ret = false;
    for (int i = 0; i < wordsSize; i ++)
        get_multiplier(mult, nonzero, words[i], 1);
    get_multiplier(mult, nonzero, result, -1);
    for (int i = 0; i < 26; i ++)
        if (mult[i] != 0) {
            vals[n] = mult[i];
            low[n] = 0;
            high[n] = 9;
            if (nonzero[i])
                low[n] = 1;
            n ++;
        }
    if (n > 10)
        return false;

    // 以下这段是优化,使用之后能使运行时间从 ~550ms 减到 ~250ms
    /*
    int m = 0;
    for (int i = 0; i < n; i ++)
        if (vals[i] > vals[m])
            m = i;
    if (vals[m] < 0)
        return false;
    int s = 0;
    for (int i = 0; i < n; i ++)
        if (vals[i] < 0)
            s -= vals[i];
    int t = 0;
    for (int i = 0; i < n; i ++)
        if (i != m && vals[i] > 0)
            t += vals[i];
    if (1 + (9 * s - t) / vals[m] < high[m])
        high[m] = 1 + (9 * s - t) / vals[m];
    if ((s - 9 * t) / vals[m] > low[m])
        low[m] = (s - 9*t) / vals[m];

    for (int i = 0; i < n; i ++)
        if (vals[i] < vals[m])
            m = i;
    if (vals[m] > 0)
        return false;
    s = 0;
    for (int i = 0; i < n; i ++)
        if (vals[i] > 0)
            s += vals[i];
    t = 0;
    for (int i = 0; i < n; i ++)
        if (i != m && vals[i] < 0)
            t -= vals[i];
    if (1 + (9 * s - t) / (-vals[m]) < high[m])
        high[m] = 1 + (9 * s - t) / (-vals[m]);
    if ((s - 9 * t) / (-vals[m]) > low[m])
        low[m] = (s - 9*t) / (-vals[m]);
    */

    dfs(low, high, vals, n, 0, 0, 0, &ret);
    return ret;
}