【问题标题】:Finding Longest Substring No Duplicates - Help Optimizing Code [Ruby]查找最长的子串不重复 - 帮助优化代码 [Ruby]
【发布时间】:2019-04-29 07:12:15
【问题描述】:

所以我一直在尝试解决一个Leetcode Question,“给定一个字符串,找出最长子字符串的长度而不重复字符。”

例如

Input: "abcabcbb"
Output: 3 
Explanation: The answer is "abc", with the length of 3. 

目前,在使用哈希表确定子字符串是否唯一时,我优化了我的算法。但是我的代码仍然在 O(n^2) 运行时运行,因此超过了提交期间的时间限制。

我尝试做的基本上是检查每一个可能的子字符串并检查它是否有任何重复值。当谈到这里的蛮力方法时,我是否尽可能高效?我知道还有其他方法,例如滑动窗口方法,但我正在尝试先使用蛮力方法。

# @param {String} s
# @return {Integer}
def length_of_longest_substring(s)
    max_length = 0
    max_string = ""
    n = s.length
    for i in (0..n-1)
        for j in (i..n-1)
            substring = s[i..j]
            #puts substring
            if unique(substring)
                if substring.length > max_length
                    max_length = substring.length
                    max_string = substring
                end
            end
        end
    end
    return max_length
end

def unique(string)
    hash = Hash.new(false)
    array = string.split('')
    array.each do |char|
        if hash[char] == true
            return false
        else
            hash[char] = true
        end
    end
    return true
end

【问题讨论】:

    标签: ruby hash substring


    【解决方案1】:

    接近

    这是一种使用将字符映射到索引的哈希的方法。对于字符串s,假设子字符串s[j..j+n-1] 中的字符是唯一的,因此该子字符串是最长唯一子字符串的候选。因此下一个元素是e = s[j+n] 我们希望确定s[j..j+n-1] 是否包含e。如果不是,我们可以将e 附加到子字符串中,保持其唯一性。

    如果s[j..j+n-1] 包含e,我们确定n(子字符串的大小)是否大于先前已知子字符串的长度,如果是则更新我们的记录。要确定s[j..j+n-1] 是否包含e,我们可以对子字符串执行线性搜索,但维护一个散列c_to_i 更快,其键值对为s[i]=>ii = j..j_n-1。也就是说,c_to_i 将子字符串中的字符映射到它们在完整字符串s 中的索引。这样我们就可以只评估c_to_i.key?(e) 来查看子字符串是否包含e。如果子字符串包含e,我们使用c_to_i 来确定它在s 中的索引并添加一个:j = c_to_i[e] + 1。因此,新子字符串为s[j..j+n-1],新值为j。注意这一步可能会跳过s的几个字符。

    无论子字符串是否包含e,我们现在必须将e 附加到(可能已更新的)子字符串,使其变为s[j..j+n]

    代码

    def longest_no_repeats(str)
      c_to_i = {}
      longest = { length: 0, end: nil }
      str.each_char.with_index do |c,i|
        j = c_to_i[c]
        if j
          longest = { length: c_to_i.size, end: i-1 } if
            c_to_i.size > longest[:length]
          c_to_i.reject! { |_,k| k <= j }
        end
        c_to_i[c] = i
      end
      c_to_i.size > longest[:length] ? { length: c_to_i.size, end: str.size-1 } :
        longest
    end
    

    示例

    a = ('a'..'z').to_a
      #=> ["a", "b",..., "z"]
    
    str = 60.times.map { a.sample }.join
      #=> "ekgdaxxzlwbxixhlfbpziswcoelplhobivoygmupdaexssbuuawxmhprkfms"
    
    longest = longest_no_repeats(str)
      #=> {:length=>14, :end=>44} 
    str[0..longest[:end]]
      #=> "ekgdaxxzlwbxixhlfbpziswcoelplhobivoygmupdaexs" 
    str[longest[:end]-longest[:length]+1,longest[:length]]
      #=>                                "bivoygmupdaexs" 
    

    效率

    这是与@mechnicov 代码的基准比较:

    require 'benchmark/ips'
    
    a = ('a'..'z').to_a
    arr = 50.times.map { 1000.times.map { a.sample }.join }
    
    Benchmark.ips do |x|
      x.report("mechnicov") { arr.sum { |s| max_non_repeated(s)[:length]   } }
      x.report("cary")      { arr.sum { |s| longest_no_repeats(s)[:length] } }
      x.compare!
    end
    

    显示:

    Comparison:
                cary:       35.8 i/s
           mechnicov:        0.0 i/s - 1198.21x  slower
    

    【讨论】:

      【解决方案2】:

      来自您的link

      输入:“pwwkew”

      输出:3

      解释:答案是“wke”,长度为3。

      这意味着您需要第一个不重复的子字符串。

      我建议这里是这样的方法

      def max_non_repeated(string)
        max_string = string.
                       each_char.
                       map.with_index { |_, i| string[i..].split('') }.
                       map do |v|
                         ary = []
                         v.each { |l| ary << l if ary.size == ary.uniq.size }
                         ary.uniq.join
                       end.
                       max
      
        {
          string: max_string,
          length: max_string.length
        }
      end
      
      max_non_repeated('pwwkew')[:string] #=> "wke"
      max_non_repeated('pwwkew')[:length] #=> 3
      

      在 Ruby [i..-1] 而不是 [i..]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-06
        • 2017-04-12
        • 2020-07-04
        • 2016-08-11
        • 2020-12-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多