不定期更新算法题

283 阅读3分钟

2020.8.19

  • 问:在数组中找到2个数之和等于给定的数字,结果返回这两个数字的索引。
  • 思路
    最优的做法时间复杂度可以做到O(n)。 顺序扫描数组,对每一个元素,在Dictionary中找能组合给定值的另一个数字,如果找到了,直接返回下标即可。如果找不到,就把这个数字存入Dictionary中,等待扫描到另一个数字的时候,再取值判断返回结果。
  • 代码
class Solution{
    func twoSum(_ nums:[Int],_ target:Int) -> [Int?] {
        var m = Dictionary<Int,Int>()
        for i in 0...nums.count-1 {
            let another:Int = target - nums[i]
            if let anotherKey = m[another] {
                return [anotherKey,i]
            }
            m[nums[i]] = i
        }
        return [];
    }
}

let  s = Solution.init()
s.twoSum([3,3,6,8], 6)

2020.9.3

  • 问:求第n个斐波那契数
  • 思路
    0 1 1 2 3 5 8 13 .... 斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。定义:F(0) = 0,F(1) = 1
    F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
  • 代码(递归法)
    func fib(_ index:Int) -> Int {
        if index <= 1 {
            return index;
        }
        return fib(index-1) + fib(index-2)
    }//时间复杂度O(2^n)
  • 代码(迭代法)
  func fib2(_ n:Int) -> Int {
        if n <= 1 {
            return n
        }
        var first = 0
        var second = 1
        for _ in 0...n-2 {
            let sum = first + second
            first = second
            second = sum
        }
        return second
    }//时间复杂度O(n)

2020.9.14(滑动窗口)

  • 问:给定一个字符串,找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
  • 思路:“滑动窗口”思想。
    • 滑动窗口就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列。
    • 右边界不断的右移,只要没有重复的字符,就持续向右扩大窗口边界。一旦出现了重复字 符,就需要缩小左边界,直到重复的字符移出了左边界,然后继续移动滑动窗口的右边界。以此类推, 每次移动需要计算当前⻓度,并判断是否需要更新最大⻓度,最终最大的值就是题目中的所求。
  • 代码:需要处理字符串,所用时间比较长。每次碰到重复的就对字符串处理。进行截取。重复判断字符串是否是最大长度
    func lengthOfLongestSubstring(_ s:String ) -> Int {
        if s.count == 1 {return 1}
        if s.count == 0 {return 0}
        var maxString = String()
        var curString = String()
        for char in s {
            while curString.contains(char) {
                curString.remove(at: curString.startIndex)
            }
            curString.append(char)
            if curString.count > maxString.count{
                maxString = curString
            }
        }
        return maxString.count;
    }
  • 代码:数组做临时的存储,当碰到重复字符,删除此字符在数组之前所有字符,包括本身。 每次重复需要判断下是否是最大长度。
    func lengthOfLongestSubstring(_ s:String) -> Int {
        var charArray = Array<Character>()
        var maxLenth = 0
        for char in s {
            if charArray.contains(char) {
                let oldCharIndex:Int? = charArray.firstIndex(of: char)
                charArray.removeFirst(oldCharIndex! + 1)
            }
            charArray.append(char)
            if charArray.count > maxLenth {
                maxLenth = charArray.count
            }
        }
         return maxLenth
    }

2020.9.14(滑动窗口)

  • 问:给你一个字符串 S、一个字符串 T 。请你设计一种算法,可以在O(n) 的时间复杂度内,从字符串 S 里面找出:包含 T 所有字符的最小子串。
  • 思路
    这一题是滑动窗口的题目,在窗口滑动的过程中不断的包含字符串 T,直到完全包含字符串 T 的字符以 后,记下左右窗口的位置和窗口大小。每次都不断更新这个符合条件的窗口和窗口大小的最小值。最后输出结果即可。
  • 代码
    func minWindow2(_ s:String,_ t:String) -> String {
        let sArray = [Character](s)
        
        var window:Dictionary = Dictionary<Character,Int>() //保存滑动窗口字符集
        var need:Dictionary = Dictionary<Character,Int>() //保存需要的字符集
        
        for char in t{
            need[char,default:0] += 1
        }
        
        var left = 0,right = 0 //窗口左右
        var start = 0,end = 0
        
        var match:Int = 0 //match匹配次数
        var minLenth:Int = Int.max
        
        
        while right < sArray.count {
            let rightItem = sArray[right]
            right += 1
            //如果在需要的字符集内,添加到窗口字符集
            if need[rightItem] != nil {
                window[rightItem,default:0] += 1
                //如果当前字符的数量匹配需要的字符数量,则match+1
                if window[rightItem] == need[rightItem] {
                    match += 1
                }
            }else {
                continue
            }
            
            //当所有字符都匹配结束后,开始缩紧窗口
            while match == need.count {
                if right - left < minLenth {
                    start = left
                    end = right
                    minLenth = end - start
                }
                let leftItem = sArray[left]
                left += 1
                if need[leftItem] != nil {
                    // 左指针指向字符数量和需要的字符相等时,右移之后match值就不匹配则减一
                    // 因为window里面的字符数可能比较多,如有10个A,但需要的字符数量可能为3
                    if window[leftItem] == need[leftItem] {
                        match -= 1
                    }
                    window[leftItem]! -= 1
                }
                
            }
        }
        
        return minLenth == Int.max ? "" : String(sArray[start..<end])
    }

2020.9.14(二分查找和二分搜索)