1. 程式人生 > >LeetCode30-與所有單詞相關聯的字串

LeetCode30-與所有單詞相關聯的字串

https://zhuanlan.zhihu.com/p/51296482 

 

這是我上午花了好長好長好處時間寫的一篇隨筆,該說的話都在這裡面了,我不會赤裸裸的跟大家說:我想推薦大家去看看的。啊哈哈哈哈。


30-與所有單詞相關聯的字串

給定一個字串 和一些長度相同的單詞 words。在 s 中找出可以恰好串聯 words 中所有單詞的子串的起始位置。

注意子串要與 words 中的單詞完全匹配,中間不能有其他字元,但不需要考慮 words 中單詞串聯的順序。

示例 1:

[0,9]

示例 2:

[]

這一題我剛開始做的時候是按照暴力法來做的,沒辦法啊,菜鳥的第一想法就是最簡單最容易理解的暴力搜尋法(其實是最容易想到的,其他更簡單的方法要是能想到,誰還用暴力法啊)

思路:

1)可以先將目標words陣列內的字串元素自由組合,python中可以使用itertools.permutations() 這個函式極為方便,能夠快速的生成給定陣列內元素的排列列表,並且列表內元素不允許重複出現,就跟數學中的排列是一樣的。

2)得到目標words陣列內的排列列表後,就可以依次遍歷字串 s了,只要字串中有與words陣列內的排列列表相等的字串,把對應的下標值記錄下來返回就可。

程式碼如下:

from itertools import permutations


class Solution:
    # 可以先將word陣列內字串自由組合,然後用s.index()函式即可得到答案
    # 要考慮字串s和words中出現的重複字元
    # 此種解法超出時間限制
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """
        if s is None or len(words) == 0 or len(s) < len(words[0] * len(words)):
            return []
        if s is None or len(words) == 0 or len(s) < len(words[0] * len(words)):
            return []
        # 採用itertools.permutations()函式將word陣列內字串自由組合,如[('foo', 'bar'), ('bar', 'foo')]
        words_permutations = permutations(words)
        words_list = set([])
        # 然後依次遍歷words_permutations組合,找到與字串s對應位置相等的字串
        # 完全的暴力法
        for index in words_permutations:
            # 將words_permutations內某一種組合情況合併為一個字串(例如('foo', 'bar')合併為"foobar"),供後面使用
            index = ''.join(list(index))
            if index in s:
                start = s.index(index)
                words_list.add(start)
                for i in range(start, len(s)-len(index)+1):
                    if s[i:i+len(index)] == index:
                        words_list.add(i)
        return list(words_list)


if __name__ == "__main__":
    s = "barfoothefoobarman"
    words = ["foo","bar"]
    result = Solution().findSubstring(s, words)
    print(result)

是不是感覺很簡單,但是要潑一盆冷水的是:最後超出時間限制了,真的是要捶人啊!這是要逼我祭出大招啊——去找度娘,度娘始終是不會讓我失望的,終於是找到了一種更為巧妙的方法。上面的暴力法之所以花費時間較多,是因為我們考慮到了所有的排列情況,這才會時間爆炸,如果我們不需要去考慮排列情況,只需要單純的比較words 陣列對應的字串與字串 的關係,那時間豈不是能省去一大截。答案是:那踏馬肯定是的啊,我都說到這兒了,說的話肯定是對的啊,哈哈哈哈哈。那現在的關鍵就是如何省略排列情況這一步了。

思路:

1)每次從s中切對應長度(words中各個元素的長度之和)的一條子串,
2)然後再把這條子串按words中單個單詞的長度再切成更小子串構成一個list, 把words和list排序後的結果比對一下,看是否完全相同,如果是則我們返回對應的起始點。否則繼續。

程式碼如下:

class Solution:
    # 每次從s中切對應長度(words中各個元素的長度之和)的一條子串,
    # 然後再把這條子串按words中單個單詞的長度再切成更小子串構成一個list, 把words和list排序後的結果比對一下,
    # 看是否完全相同,如果是則我們返回對應的起始點。否則繼續。
    def findSubstring(self, s, words):
        """
        :type s: str
        :type words: List[str]
        :rtype: List[int]
        """

        if s is None or len(words) == 0:
            return []
        word_length = len(words[0])
        words_length = word_length * len(words)
        words.sort()
        word_list = []
        for index in range(len(s) - words_length + 1):
            sub_s = [s[index+i*word_length: index+(i+1)*word_length] for i in range(len(words))]
            sub_s.sort()
            if words == sub_s:
                word_list.append(index)
        return word_list


if __name__ == "__main__":
    s = "aa"
    words = ["aa", "af"]
    result = Solution().findSubstring(s, words)
    print(result)

是不是覺得so so so easy?別急,我還有更好的...好個屁了,寫到這兒已經虐的差不多了,人懶寫不動了,各位讀者要是有更好的想法也可以積極分享哈!