Python LeetCode(四)

不同的做法

1. 56. Merge Intervals

这是我的做法,AC,通过反向删除intervals中的值实现,注意在删除的时候删除前面那个,这样数组重新排序后,数组仍然会从最后一位和前面的比较进行比较。如果要反向的话,需要按照后者进行排序。

class Solution(object):
    def merge(self, intervals):
        """
        :type intervals: List[Interval]
        :rtype: List[Interval]
        """
        intervals = sorted(intervals, key=lambda x:x.end)
        for i in range(len(intervals)-2, -1, -1):
            first,second = intervals[i],intervals[i+1]
            if first.end >= second.start:
                if second.start > first.start:
                    second.start = first.start
                intervals.pop(i)
        return intervals

也可以正向

def merge(self, intervals):
        """
        :type intervals: List[Interval]
        :rtype: List[Interval]
        """
        intervals = sorted(intervals, key=lambda x: x.start)
        ans = []
        for i in intervals:
            if ans and ans[-1].end >= i.start:
                ans[-1].end = max(ans[-1].end, i.end)
            else:
                ans.append(i)
        return ans

2. Find Bottom Left Tree Value

class Solution(object):
    max_depth = 1
    def findBottomLeftValue(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        def recursive(cur, depth):
            if cur == None:
                return
            if cur.left:
                recursive(cur.left, depth + 1)
            if cur.right:
                recursive(cur.right, depth + 1)
            if not cur.left and not cur.right:
                if depth > self.max_depth:
                    del nodes[:]
                nodes.append(cur)
            if depth > self.max_depth:
                self.max_depth = depth
        if root is None:
            return None
        elif not root.left and not root.right:
            return root.val
        nodes = []
        recursive(root, 1)
        return nodes[0].val

我想的有些复杂,其实可以不用数组去保存,直接更新一个值就行,因为除非出现深度比当最大大的才更新,更改如下:

class Solution(object):
    max_depth = 1
    val = None
    def findBottomLeftValue(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        def recursive(cur, depth):
            if cur == None:
                return
            if cur.left:
                recursive(cur.left, depth + 1)
            if cur.right:
                recursive(cur.right, depth + 1)
            if depth > self.max_depth and not cur.left and not cur.right:
                self.val = cur.val
            if depth > self.max_depth:
                self.max_depth = depth
        if root is None:
            return None
        elif not root.left and not root.right:
            return root.val
        recursive(root, 1)
        return self.val

迭代做法如下:

class Solution(object):
    def findBottomLeftValue(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        l=[root]
        while True:
            cur=[]
            for i in l:
                if i:
                    if i.left:cur.append(i.left)
                    if i.right:cur.append(i.right)
            if cur:
                l[:]=cur
            else:
                return l[0].val

3. Add and Search Word - Data structure design

这也是一道非常多种做法的题目

字典纪录长度

class WordDictionary(object):
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.words = {}
    def addWord(self, word):
        """
        Adds a word into the data structure.
        :type word: str
        :rtype: void
        """
        l = len(word)
        if l not in self.words:
            self.words[l] = {word,}
        else:
            if word not in self.words[l]:
                self.words[l].add(word)
    def compare(self, word, regex):
        for i in xrange(len(regex)):
            if regex[i] == '.':
                continue
            elif regex[i] is not word[i]:
                return False
        return True 
    def search(self, word):
        """
        Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter.
        :type word: str
        :rtype: bool
        """
        l = len(word)
        if l not in self.words:
            return False
        elif '.' not in set(word):
            return word in self.words[l]
        word_set = self.words[l]
        for x in word_set:
            if self.compare(x, word):
                return True
        return False

defaultdict()

还有一种和上面原理相同的做法,就是使用Python提供的collections.defaultdict(),这种结构继承的是dict,但是比dict更加快速,举个栗子:

from collections import defaultdict
def method1(word):
    d = {}
    for x in word:
        if x not in d:
            d.setdefault(x, 0)
        d[x] += 1
    print(d.items())
def method2(word):
    d = defaultdict(int)
    for x in word:
        d[x] += 1
    print(d.items())
method1('abbc') 
method2('abbc')

两者返回的结果是一样的,都是dict_items([('a', 1), ('b', 2), ('c', 1)]),后者快的原因在于其如果不存在映射的话则会自动添加映射并且完成添加的动作。

class WordDictionary(object):
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.d = collections.defaultdict(list)
    def addWord(self, word):
        """
        Adds a word into the data structure.
        :type word: str
        :rtype: void
        """
        self.d[len(word)].append(word)
    def search(self, word):
        """
        Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter.
        :type word: str
        :rtype: bool
        """
        if not word:
            return False
        if '.' not in word:
            return word in self.d[len(word)]
        if len(word) in self.d:
            for w in self.d[len(word)]:
                for i in range(len(word)):
                    if word[i]!='.' and w[i]!=word[i]:
                       break
                else:
                    return True
        return False

Trie树+回溯

class TrieNode:
    def __init__(self):
        self.leaves = dict()
        self.isWord = False
class WordDictionary:
    def __init__(self):
        self.root = TrieNode()
    def addWord(self, word):
        node = self.root
        for x in word:
            child = node.leaves.get(x, None)
            if child is None:
                child = TrieNode()
                node.leaves[x] = child
            node = child
        node.isWord = True
    def backtrack(self, word, root):
        node = root
        for i, x in enumerate(word):
            if x == '.':
                for leaf in node.leaves.values():
                    if leaf and self.backtrack(word[i + 1:], leaf):
                        return True
                return False
            else:
                child = node.leaves.get(x, None)
                if child is None:
                    return False
                node = child
        return node.isWord
    def search(self, word):
        return self.backtrack(word, self.root)

这道题,显然不太适合用函数递归的方法,耗时太长,直接用字典即可,还可以用zip来做。

优化

1. 472. Concatenated Words

递归做法,把word分成两部分,第一部分拿来比较判断,另一个部分拿来递归。

class Solution(object):
    def findAllConcatenatedWordsInADict(self, words):
        """
        :type words: List[str]
        :rtype: List[str]
        """
        def recursive(word, cnt):
            if word == "":
                if cnt > 1:
                    return True
                else:
                    return False
            for i in range(1, len(word)+1):  # range放在LeetCode中就超时,应该是它以为是python2中的range,在3中,xrange已经改成了range
                if word[0:i] in word_set and recursive(word[i:], cnt+1):
                    return True
            return False
        res = []
        word_set = set(words)
        for word in words:
            if recursive(word, 0):
                res.append(word)
        return res

迭代的做法,需要注意的是visited的设置,之所以要纪录它们的count,是因为如果遇到 word...word 这种多个word重复的单词的情况,如果是单纯的纪录,那么后者将不会进入栈中,所以加了个count,直到它减到0则不能够再访问。还有另外一种做法,就是在stack中纪录下标。

class Solution(object):
    def findAllConcatenatedWordsInADict(self, words):
        word_set = set(words)
        ans = []
        for word in words:
            if not word:
                continue
            stack = [word]
            visited = {word: 0}
            while stack:
                cur = stack.pop() 
                l = len(cur)
                # 表示到了最后
                if cur == "":
                    ans.append(word)
                    break
                for i in xrange(1, l + 1):
                    if cur[:i] in word_set and (cur[:i] not in visited or (cur[:i] in visited and visited[cur[:i]])):
                        stack.append(cur[i:])
                        if cur[:i] in visited:
                            visited[cur[:i]] -= 1
                        else:
                            visited[cur[:i]] = word.count(cur[:i])-1
        return ans

dp做法

class Solution(object):
    def findAllConcatenatedWordsInADict(self, words):
        word_dict = set()  # 记录访问的字母
        words.sort(key=lambda x:len(x))
        res = []
        def can(word):
            if not word:
                return False
            dp = [0] * (len(word)+1)
            dp[0] = True
            # i表示的是word[0:i],dp[i]则表示代表的字符串是否存在于set中
            # 假设当前单词为catcatcat,那么其dp数组中相应的第3、6、9都为True,而后者都取决于由前者
            for i in range(1, len(word)+1):
                for j in range(i):
                    if dp[j] and word[j:i] in word_dict:
                        dp[i] = True
                        break
            return dp[len(word)]
        for word in words:
            if can(word):
                res.append(word)
            word_dict.add(word)
        return res

还有Trie树的做法

class Solution(object):
    def findAllConcatenatedWordsInADict(self, words):
        """
        :type words: List[str]
        :rtype: List[str]
        """
        self.trie = Trie()
        ans = []
        for word in words:
            self.trie.insert(word)
        for word in words:
            if self.search(word):
                ans.append(word)
        return ans
    def search(self, word):
        node = self.trie.root
        for idx, letter in enumerate(word):
            node = node.children.get(letter)
            if node is None:
                return False
            suffix = word[idx+1:]  #取出后缀,判断其是否是个单词或者继续递归
            if node.isWord and (self.trie.search(suffix) or self.search(suffix)):
                return True
        return False
class TrieNode:
    def __init__(self):
        self.children = dict()
        self.isWord = False
class Trie:
    def __init__(self):
        self.root = TrieNode()
    def insert(self, word):
        node = self.root
        for letter in word:
            child = node.children.get(letter)
            if child is None:
                child = TrieNode()
                node.children[letter] = child
            node = child
        node.isWord = True
    def search(self, word):
        node = self.root
        for letter in word:
            node = node.children.get(letter)
            if node is None:
                return False
        return node.isWord

不知道怎么做

1. Gray Code

数学计算

class Solution:
    # @return a list of integers
    '''
    from up to down, then left to right
    
    0   1   11  110
            10  111
                101
                100
                
    start:      [0]
    i = 0:      [0, 1]
    i = 1:      [0, 1, 3, 2]
    i = 2:      [0, 1, 3, 2, 6, 7, 5, 4]
    '''
    def grayCode(self, n):
        results = [0]
        for i in range(n):
            results += [x + pow(2, i) for x in reversed(results)]
        return results

图的DFS

我们可以把这个想象成一个图的问题,每个数字代表一个结点,比如说000,它的邻居结点就有001,结点001的邻居结点就有011(001 ^ 010)

def grayCodeDFS(self, n):
        '''
        depth-first search solution
        '''
        visited = {0}
        seq = [0]
        # 遍历所有结点
        for _ in range(1, 1 << n):
            val = seq[-1]
            for i in range(n):
                # 计算邻居的值
                neighbor = val ^ (1 << i)
                if neighbor not in visited:
                    seq.append(neighbor)
                    visited.add(neighbor)
                    break #加上break是因为避免重复的遍历
        return seq
posted @ 2017-08-05 15:45  banananana  阅读(203)  评论(0)    收藏  举报