【问题标题】:Speeding up Swift CodeFight Challenge加速 Swift CodeFight 挑战
【发布时间】:2018-04-24 16:35:01
【问题描述】:

每个 Codefighters:

注意:写一个 O(n) 时间复杂度和 O(1) 额外空间复杂度的解决方案,因为这是你在真实面试中被要求做的事情。

给定一个数组 a,其中仅包含 1 到 a.length 范围内的数字,找到第二次出现具有最小索引的第一个重复数字。换句话说,如果有超过 1 个重复的数字,则返回第二次出现的索引比另一个数字的第二次出现的索引更小的数字。如果没有这样的元素,则返回 -1。

例子

对于 a = [2, 3, 3, 1, 5, 2],输出应该是 firstDuplicate(a) = 3。

有 2 个重复项:数字 2 和 3。第二次出现的 3 比第二次出现的 2 的索引更小,所以答案是 3。

对于 a = [2, 4, 3, 5, 1],输出应该是 firstDuplicate(a) = -1。

所以这就是我想出的。它可以工作,但在最终测试中失败,因为它运行了 4000 毫秒以上。我坚持我还能做什么。有什么提高速度的想法吗?

func firstDuplicate(a : [Int]) -> Int {
var duplicateIndexArray = [Int]()
for firstIndex in 0..<a.count {

    for secondIndex in 0..<a.count {

        if a[firstIndex] == a[secondIndex] && firstIndex != secondIndex {
            print(firstIndex, secondIndex)
            if !(duplicateIndexArray.contains(firstIndex)){
                duplicateIndexArray.append(secondIndex)
                break
            }
        }
    }
}

// Check for duplicacy
if duplicateIndexArray.count > 0 {
    print(duplicateIndexArray)
    return a[duplicateIndexArray.min()!]
}
return -1

}

【问题讨论】:

  • a 是不可变的,还是可以重新排序值?

标签: swift algorithm


【解决方案1】:

O(n) 时间部分很容易,但 O(1) 额外空间有点棘手。通常,可以使用散列集(或您的情况下的位数组)来检查一个数字是否多次出现,但这需要 O(n) 额外的空间。对于 O(1) 额外空间,我们可以将源数组本身用作位数组,方法是将其中的一些数字设为负数。

例如,如果数组中的第一个数字是 3,那么我们将位置 3-1 的数字设为负数。如果数组中的其他数字之一也是 3,我们可以检查位置 3-1 的数字是否为负数。

我对 Swift 没有任何经验,所以我会尝试在pseudocode 中编写一个函数:

function firstDuplicate(a)
    result = -1

    for i = 0 to a.count - 1
         if a[abs(a[i])-1] < 0 then 
             result = a[i] 
             exit for loop
         else
             a[abs(a[i])-1] = -a[abs(a[i])-1]

    // optional restore the negative numbers back to positive
    for i = 0 to a.count - 1
        if a[i] < 0 then 
            a[i] = -a[i]

    return result

【讨论】:

    【解决方案2】:

    替换这一行

    for secondIndex in 0..<a.count
    

    for secondIndex in firstIndex..<a.count
    

    没有双重检查的要求

    所以你的最终代码是

    func firstDuplicate(a : [Int]) -> Int {
        var duplicateIndexArray = [Int]()
        for firstIndex in 0..<a.count {
    
            for secondIndex in firstIndex..<a.count {
    
                if a[firstIndex] == a[secondIndex] && firstIndex != secondIndex {
                    print(firstIndex, secondIndex)
                    if !(duplicateIndexArray.contains(firstIndex))
                    {
                        duplicateIndexArray.append(secondIndex)
                        break
                    }
                }
            }
        }
    
        // Check for duplicacy
        if duplicateIndexArray.count > 0
        {
            print(duplicateIndexArray)
            return a[duplicateIndexArray.min()!]
        }
        return -1
    }
    

    【讨论】:

      【解决方案3】:
      func firstDuplicate(input: [Int]) -> Int{
          var map : [String : Int] = [:]
          var result = -1
          for i in 0 ..< input.count {
              if map["\(input[i])"] != nil {
                  result = i
                  break
              }
              else {
                  map["\(input[i])"] = i
              }
          }
          return result
      }
      

      【讨论】: