Find and Replace Pattern

You have a list of words and a pattern, and you want to know which words in words matches the pattern.

A word matches the pattern if there exists a permutation of letters p so that after replacing every letter x in the pattern with p(x), we get the desired word.

(Recall that a permutation of letters is a bijection from letters to letters: every letter maps to another letter, and no two letters map to the same letter.)

Return a list of the words in words that match the given pattern. 

You may return the answer in any order.

Example 1:

Input: words = ["abc","deq","mee","aqq","dkd","ccc"], pattern = "abb"
Output: ["mee","aqq"]
Explanation: "mee" matches the pattern because there is a permutation {a -> m, b -> e, ...}. 
"ccc" does not match the pattern because {a -> c, b -> c, ...} is not a permutation,
since a and b map to the same letter.

Note:

  • 1 <= words.length <= 50
  • 1 <= pattern.length = words[i].length <= 20
def F(w):
    m = {}
    return [m.setdefault(c, len(m)) for c in w]
return [w for w in words if F(w) == F(pattern)]

Lowest Common Ancestor with N nodes

Today, I have taken an interview from Wechat.

To be honest, this question is easy, but I do not have sufficient time to complete coding. Maybe I took too much time in same trivial points with the “VERY PROFESSIONAL” interviewer.

The actual question is find the lowest common ancestor of three given nodes, but I thought we can expend this question to N nodes. For testing this question rapidly, I reuse the previous code of constructing a binary tree by the in-order and post-order traversals.

Continue reading

Regex Matching – Finite State Machine

Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '?' and '*'.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).

The matching should cover the entire input string (not partial).

Note:

  • s could be empty and contains only lowercase letters a-z.
  • p could be empty and contains only lowercase letters a-z, and characters like ? or *.

这个时候,有限状态机(FSM)就可以派上用场了。

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        transfer = {}
        state = 0

        # Build a Finite State Machine(FSM)
        for char in p:
            # If pattern is *, it can stay in the current state, or move to the next state via transfer links.
            if char == '*':
                transfer[state, char] = state
            # If pattern is ? or characters, we move to the next state.
            else:
                transfer[state, char] = state + 1
                state += 1

        # the last state (Final one) is the accept state
        accept = state

        # the initial state starts from 0
        state = {0}

        for char in s:
            # There are two ways to achieve state transfer.
            # 1) We can use two rolling sets saving previous and current situations
            # 2) We also can use python syntactic sugar (Actually as same as the first method)
            # I personally think the first method is more readable.

            new_state = set()

            for token in [char, '*', '?']:
                for at in state:
                    # For each previous state, we can parallelly move to next states
                    new_state.add(transfer.get((at, token)))

            # Set the current state as the previous one
            state = new_state

            # the second method (elegant but not readable)
            # state = set([transfer.get((at, token)) for at in state for token in [char, '*', '?']])

        return accept in state


if __name__ == "__main__":
    obj = Solution()
    result = obj.isMatch("aa", "aa")
    print(result)

Using bit manipulation to achieve operators

1)计算负数的逆元

def negative(n):
    return bit_add(~n, 1)

2)加法计算

def bit_add(a, b):
    b &= (2 ** 32 - 1)
    while b:
        tmp = a
        sum = tmp ^ b
        carry = (tmp & b) << 1
    return a

3)减法计算

def bit_sub(a, b):
    return bit_add(a, negative(b))

4)乘法计算

def bit_mul(a, b):
    result = 0

    while b:
        if b & 0x1:
            result = bit_add(result, a)
        b >>= 1
        a <<= 1

    return result

乘法模拟手工计算乘法的流程,将乘数b的二进制表示从左往右移动,当最低位为1时 (b & 0x1 == 1),把被乘数a加到result中,同时将被乘数a向左移动一位。

5)除法计算

def bit_div(x, y):
    result = 0
    for i in range(32)[::-1]:
        if (x >> i) >= y:
            result += (1 << i)
            x -= (y << i)

    return result

考虑32位整数表示 (64位改一下 i 就可以了)。从最大的倍数开始遍历,如果被除数x >> i 大于除数y,说明该位商为1,将1<<i加到结果中,并缩小x。

Find medians from a slide window

实现一个一维的中位数滤波器。

形式化地来说,给出一个长度为n的数列a_1,a_2,a_3,…,a_n,# 求一个数列b_1,b_2,…,b_{n-k+1},使得b_i是子列(a_i,a_{i+1},…,a_{i+k-1})的中位数。

可以理解为一个长度为k的滑窗在长度为n的数列上滑动,每滑一次输出滑窗里面的数的中位数。

a = [1,2,3,12,-5,33]
k = 3
b = [2,3,3,12]b
Continue reading

Maximum XOR of Two Numbers in an Array

Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231.

Find the maximum result of ai XOR aj, where 0 ≤ ij < n.

Could you do this in O(n) runtime?

Example:

Input: [3, 10, 5, 25, 2, 8] 
Output: 28
Explanation: The maximum result is 5 ^ 25 = 28.

这道题是在刷Explore的Trie tree topic里面看到的。首先一拿到题目,下意识的反应就是这道题没那么简单。最暴力的方法就是穷举遍历了,这样的话time complexity就会达到O(n^2)。

之后联想Trie tree和Binary之间的关系,可以画出上面这个图。这样问题就被转换为了找到最高的具有1节点的父节点,然后向下尽量找a^b = 1的分支 (我感觉我没有说清楚。。。)

之后看了讨论版里一位大佬的题解,真的是颇为震撼。他用了位运算的方法省去了很多不必要的步骤。 其中比较不好理解的是:

result += any(result ^ 1 ^ p in prefixes for p in prefixes)

为了理解这句话,首先我们得知道:a^b^a=b.

在这里result^1 == a^b, p = a, 所以result^1^p = b。如果在prefixes中有任意两个数a,b可以得到result^1, 而且这两个数a,b构成了previous result,那么新的result就可以是result += 1了,不然只能是result <<= 1(末位为0)。

class Solution:
    def findMaximumXOR(self, nums: List[int]) -> int:
        result = 0
        
        for i in range(32)[::-1]:
            result <<= 1
            prefixes = {num >> i for num in nums}
            result += any(result ^ 1 ^ p in prefixes for p in prefixes)
            
        return result