LeetCode 解题记录(swift)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sky_long_fly/article/details/87714597

不定期持续更新

1.给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

    func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
        var index = 0
        while index < nums.count {
            let num = target - nums[index]
            let numIndex:Int = nums.firstIndex(of: num) ?? -1
            if numIndex >= 0 && numIndex != index {
               return [index,numIndex]
            }
            index += 1
        }
        return []
    }

2.给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。

您可以假设除了数字 0 之外,这两个数都不会以 0 开头。

    func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
        let result = ListNode(0)
        var tempResult = result;
        var templ1 = l1
        var templ2 = l2
        var addOne:Bool = false
        while templ1 != nil || templ2 != nil {
            if (templ1 != nil) {
                tempResult.val += (templ1?.val)!
                templ1 = templ1?.next
            }
            
            if (templ2 != nil) {
                tempResult.val += (templ2?.val)!
                templ2 = templ2?.next
            }
            
            if addOne {
                tempResult.val += 1
            }
            
            if tempResult.val >= 10 {
                tempResult.val = tempResult.val%10
                addOne = true
            }else{
                addOne = false
            }
            
            if templ1 != nil || templ2 != nil{
                tempResult.next = ListNode(0);
                tempResult = tempResult.next!;
            }else{
                if addOne{
                    tempResult.next = ListNode(1);
                }
            }
        }
        return result;
    }

3.给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

   /* 本题我自己的解题方式超时,不过能得到答案。swift 能更优的解题如下
     func lengthOfLongestSubstring(_ s: String) -> Int {
     let string = s.utf8CString
     
     var result = 0
     
     var map = [CChar: Int](minimumCapacity: Int(Int8.max))
     var start = 0
     
     for index in 0...string.count - 1{
     let c = string[index]
     if c != 0 {
     if let last = map[c],last >= start{
     start = last + 1
     }else if result < index - start + 1{
     result = index - start + 1
     }
     map[c] = index
     }
     }
     
     return result
     }
     */
    
    func lengthOfLongestSubstring(_ s: String) -> Int {
        if s.count == 1 {
            return 1;
        }
        
        var maxCount:Int = 0
        var index:Int = 0
        while index < s.count {
            let tempStr = s.substring(to: s.index(s.startIndex, offsetBy: index + 1))
            let tempStr1 = s.substring(from: s.index(s.startIndex, offsetBy: index + 1));
            var have = false

            var remTempStr = tempStr
            while remTempStr.count != 0{
                var charStr = remTempStr.remove(at: remTempStr.index(remTempStr.startIndex, offsetBy: 0))
                let charString = String(charStr);
                let rang = remTempStr.range(of:charString)
                if rang != nil {
                    have = true;
                }
            }
            
            if have == false {
                maxCount = max(maxCount, tempStr.count)
            }

            if tempStr1.count > maxCount {
                maxCount = max(maxCount, self.lengthOfLongestSubstring(tempStr1))
            }
         
            index += 1
        }
        return maxCount;
    }

4.给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。

 请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
 
 你可以假设 nums1 和 nums2 不会同时为空。
 func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double {
     var nums = nums1 + nums2;
     nums.sort()
     if nums.count % 2 == 0 {
         return Double((nums[nums.count/2] + nums[nums.count/2 - 1])) / 2
     }else{
         return Double(nums[(nums.count + 1)/2 - 1])
     }
 }

5.给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

这题原本我用OC暴力方法解出来了。但是转swift超时,然后用LeetCode给的解法写了一个发现也超时。
OC 解法

-(NSString *)longestPalindrome2:(NSString *)s{
    if (s.length == 1 || s.length == 0) {
        return s;
    }
    NSString * maxString = [s substringWithRange:NSMakeRange(0, 1)];
    NSMutableArray *compareCharArray = [NSMutableArray array];
    for (int i = 0; i < s.length; i++) {
        NSString * charStr = [s substringWithRange:NSMakeRange(i, 1)];
        if ([compareCharArray indexOfObject:charStr] == NSNotFound) {
            NSArray * compareArray = [s componentsSeparatedByString:charStr];
            NSMutableString *  compareStr = [[NSMutableString alloc] init];
            for (int j = 0;j < compareArray.count ;j++) {
                NSString *tempStr = [compareArray objectAtIndex:j];
                if (j > 0) {
                    [compareStr appendString:charStr];
                }
                if (tempStr.length > 0) {
                    [compareStr appendString:tempStr];
                }
                if (j != compareArray.count - 1) {
                    [compareStr appendString:charStr];
                }
                if (compareStr.length > 0
                    && [s rangeOfString:compareStr].location != NSNotFound
                    && compareStr.length > maxString.length
                    &&  [self checkString:compareStr]) {
                    maxString = [compareStr copy];
                }
                
                for (int k = j + 1; k < compareArray.count; k++) {
                    tempStr = [compareArray objectAtIndex:k];
                    if (tempStr.length > 0) {
                        [compareStr appendString:tempStr];
                    }

                    if (k != compareArray.count - 1) {
                        [compareStr appendString:charStr];
                    }
                    
                    if (compareStr.length > 0
                        && [s rangeOfString:compareStr].location != NSNotFound
                        && compareStr.length > maxString.length
                        &&  [self checkString:compareStr]) {
                        maxString = [compareStr copy];
                    }
                    
                    if (k == compareArray.count - 1) {
                        [compareStr replaceCharactersInRange:NSMakeRange(0, compareStr.length) withString:@""];
                    }
                }
            }
            [compareCharArray addObject:charStr];
        }
    }
    return maxString;
}

-(BOOL)checkString:(NSString *)string{
    NSMutableString *compareStr1 = [[NSMutableString alloc] init];
    for (NSInteger k = string.length - 1; k >= 0; k--) {
        [compareStr1 appendString:[string substringWithRange:NSMakeRange(k, 1)]];
    }
    if ([string isEqualToString:compareStr1]) {
        return YES;
    }
 
    return NO;
}

swift 解法

    func longestPalindrome(_ s: String) -> String {
        if s.count == 1 || s.count == 0 {
            return s
        }
        
        var start: Int = 0
        var end: Int = 0
        for i in 0..<s.count {
            let len1: Int = expandAroundCenter(s, left: i, right: i)
            let len2: Int = expandAroundCenter(s, left: i, right: i + 1)
            let len: Int = max(len1, len2)
            if len > end - start {
                start = i - (len - 1) / 2
                end = i + len / 2
            }
        }
        
        
        return (s as NSString).substring(with: NSMakeRange(start, end + 1 - start)) as String
    }
    
    func expandAroundCenter(_ s: String?, left: Int, right: Int) -> Int {
        var L: Int = left
        var R: Int = right
        while L >= 0 && R < s?.count ?? 0  && (s! as NSString).character(at: L) == (s! as NSString).character(at: R) {
            L -= 1
            R += 1
        }
        return R - L - 1
    }

6.将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:

L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);

    func convert(_ s: String, _ numRows: Int) -> String {
        let array:NSMutableArray = NSMutableArray()
        for i in 0..<s.count {
            var line = 1
            if numRows > 2 {
                line = (i+1)%(numRows + numRows - 2)
                if line == 0 {
                    line = 2
                }
                
                if line > numRows{
                    line = numRows - (line - numRows)
                }
                
            }else{
                line = (i%numRows) + 1
            }
            
            let charStr = (s as NSString).substring(with: NSMakeRange(i, 1))
            if array.count != numRows {
                array.add(charStr)
            }else{
                var string = array.object(at: line - 1)
                string = (string as! String) + (charStr as String)
                array.replaceObject(at: line - 1, with: string)
            }
        }
        return array.componentsJoined(by: "")
    }

7.给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

    func reverse(_ x: Int) -> Int {
        let string:String = String.init(x)
        var reverseStr:String =  String()
        for i in 0 ..< string.count {
            let charStr = (string as NSString).substring(with: NSMakeRange(string.count - 1 - i, 1))
            if charStr == "-" {
                reverseStr = charStr + reverseStr
            }else{
                reverseStr.append(charStr)
            }
        }
        var num = (reverseStr as NSString).integerValue
        if num > Int32.max || num < Int32.min {
            num = 0
        }
        return num
    }

8.请你来实现一个 atoi 函数,使其能将字符串转换成整数。

首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。

当我们寻找到的第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字组合起来,作为该整数的正负号;假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成整数。

该字符串除了有效的整数部分之后也可能会存在多余的字符,这些字符可以被忽略,它们对于函数不应该造成影响。

注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换。

在任何情况下,若函数不能进行有效的转换时,请返回 0。

说明:

假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,qing返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。

 func myAtoi(_ str: String) -> Int {
     var numStr = ""
     for i in 0..<str.count {
         let charStr = (str as NSString).substring(with: NSMakeRange(i, 1))
         if charStr != " "{
             if numStr.count == 0{
                 if charStr == "+" || charStr == "-" || charStr == "0" || (charStr as NSString).integerValue > 0{
                     numStr = charStr
                 }else {
                     break
                 }
             }else{
                 if (charStr as NSString).integerValue > 0  || charStr == "0"{
                     numStr = numStr + charStr
                 }else{
                     break
                 }
             }
         }else{
             if numStr.count > 0 {
                 break
             }
         }
     }

     var num = (numStr as NSString).integerValue
     if num > Int32.max {
         num = Int(Int32.max)
     }
     
     if num < Int32.min {
         num = Int(Int32.min)
     }
     return num
 }

9.判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

    func isPalindrome(_ x: Int) -> Bool {
        if x < 0 {
            return false
        }
        
        let string:String = String.init(x)
        var newString = ""
        for i in 0..<string.count {
            newString += (string as NSString).substring(with: NSMakeRange(string.count - 1 - i, 1))
        }
        
        return (newString as NSString).integerValue == x
    }

10.给定一个字符串 (s) 和一个字符模式 §。实现支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符。
‘*’ 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (s) ,而不是部分字符串。

说明:

s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
备注:个人感觉官网这题有问题,下面是能过的解法。

   func isMatch(_ s: String, _ p: String) -> Bool {
       let sArray = Array(s), pArray = Array(p)
       /*解析:首先 s可以为空的*/
       var rec: [[Bool]] = Array(repeating: Array(repeating: false, count: pArray.count + 1), count: sArray.count + 1)
       
       rec[0][0] = true
       for i in 0..<pArray.count {
           if pArray[i] == "*" {
               rec[0][i + 1] = rec[0][i - 1]
           }
       }
       
       for i in 0..<sArray.count {
           for j in 0..<pArray.count {
               if pArray[j] != "*" {
                   if rec[i][j] {
                       if pArray[j] == "." || pArray[j] == sArray[i] {
                           rec[i + 1][j + 1] = true
                       }
                   }
               } else {
                   if rec[i + 1][j - 1] {
                       rec[i + 1][j + 1] = true
                   } else if rec[i][j - 1] || rec[i][j + 1] {
                       if pArray[j - 1] == sArray[i] || pArray[j - 1] == "."   {
                           rec[i + 1][j + 1] = true
                       }
                   }
               }
           }
       }
       
       return rec[s.count][p.count]
   }

11. 盛最多水的容器

给定 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

 func maxArea(_ height: [Int]) -> Int {
     /*暴力方法
     var maxAreaValue = 0
     for i in 1 ..< height.count {
         for j in 0..<i{
             var value = height[i]
             if height[i] > height[j]{
                 value = height[j]
             }
             if value * (i - j) > maxAreaValue{
                 maxAreaValue = value * (i - j)
             }
         }
     }
     return maxAreaValue*/
     //比较少的计算量
     var ans = 0
     var i = 0
     var j = height.count - 1
     while i < j {
         let h1 = height[i]
         let h2 = height[j]
         let area = abs(i - j) * min(h1, h2)
         ans = max(ans, area)
         if h1 < h2 {
             i += 1
         }
         else {
             j -= 1
         }
     }
     return ans
 }

12. 整数转罗马数字

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。

    func intToRoman(_ num: Int) -> String {
        let char = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]
        let nums = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
        
        var romanStr = ""
        var value = num
        for i in 0..<nums.count{
            if value >= nums[i] {
                let count = value/nums[i]
                for _ in 0..<count {
                    romanStr += char[i]
                }
                value = value%nums[i]
                if value == 0 {
                    break
                }
            }
        }
        return romanStr
    }

13. 罗马数字转整数

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。

    func romanToInt(_ s: String) -> Int {
        let char = ["M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"]
        let nums = [1000,900,500,400,100,90,50,40,10,9,5,4,1]
        
        var romanStr = s
        var value = 0
        while romanStr.count != 0 {
            for i in 0..<char.count {
                if (romanStr as NSString).hasPrefix(char[i]){
                    value += nums[i]
                    romanStr = (romanStr as NSString).substring(from: (char[i] as NSString).length)
                    break
                }
            }
        }
        return value;
    }

14.编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。

    func longestCommonPrefix(_ strs: [String]) -> String {
        if strs.count == 0 {
            return ""
        }
        let string = strs[0] 
        var prefixStr = ""
        var broken = false
        for i in 0..<string.count {
            let temPreStr = (string as NSString).substring(to: i+1)
            for tempStr in strs {
                if !((tempStr as NSString).hasPrefix(temPreStr)){
                    broken = true
                    break
                }
            }
            if broken {
                break
            }else{
                prefixStr = temPreStr
            }
        }
        
        return prefixStr
    }

15.给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

    func threeSum(_ nums: [Int]) -> [[Int]] {
        var nums = nums.sorted()
        var result = [[Int]]()
        
        for i in 0..<nums.count {
            if i == 0 || i > 0 && nums[i] != nums[i-1] {
                var left = i + 1, right = nums.count - 1
                let sum = 0 - nums[i]
                while left < right {
                    if nums[left] + nums[right] == sum {
                        result.append([nums[left], nums[right], nums[i]])
                        while left < right && nums[left] == nums[left + 1]{
                            left += 1
                        }
                        while left < right && nums[right] == nums[right - 1]{
                            right -= 1
                        }
                        left += 1
                        right -= 1
                    } else if nums[left] + nums[right] < sum {
                        left += 1
                    } else {
                        right -= 1
                    }
                }
            }
        }
        return result
    }

16. 最接近的三数之和

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

    func threeSumClosest(_ nums: [Int], _ target: Int) -> Int {
        if nums.count < 3 {
            return 0
        }
        
        var  tempNums = nums
        tempNums.sort() //数字先排序
        
        var closestNum = tempNums[0] + tempNums[1] + tempNums[2]
        if tempNums.count > 3 {
            for f in 0 ..< tempNums.count - 2 {
                for s in (f + 1)..<tempNums.count - 1 {
                    for t in (s + 1)..<tempNums.count {
                        let threeNum = tempNums[f] + tempNums[s] + tempNums[t]
                        if abs(target - threeNum) < abs( target - closestNum) {
                            closestNum = threeNum
                        }
                    }
                }
            }
        }
        
        return closestNum
    }

17. 电话号码的字母组合

 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
 
 给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
    func letterCombinations(_ digits: String) -> [String] {
        if digits.count == 0 {
            return []
        }
        
        let numsArray:[[String]] = [["a","b","c"],["d","e","f"],["g","h","i"],["j","k","l"],["m","n","o"],["p","q","r","s"],["t","u","v"],["w","x","y","z"]]
        
        var strArray:[String] = []
        for i in 0..<digits.count {
            let charStr = (digits as NSString).substring(with: NSMakeRange(i, 1))//数字
            let charArray:[String] = numsArray[(charStr as NSString).integerValue - 2]//数字代表 字符数组
            var newStrArray:[String] = []
            for char in charArray{
                for str in strArray{
                    newStrArray.append(str+char)
                }
                
                if strArray.count == 0 {
                    newStrArray.append(char)
                }
            }
         
            strArray = newStrArray
        }
        
        return strArray
    }

18. 四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
(参考三数之和)

  func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] {
            let count = nums.count
            guard count >= 4 else { return [] }
            let nums = nums.sorted()
        
            var result = [[Int]]()
            for i in 0..<count - 3 {
                if i > 0 && nums[i] == nums[i - 1] {
                    continue
                }
                let threeSum = target - nums[i]
                
                for j in i + 1..<count - 2 {
                    if j > i + 1 && nums[j] == nums[j - 1] {
                        continue
                    }
                    let twoSum = threeSum - nums[j]
                    var left = j + 1, right = count - 1
                    while left < right {
                        if nums[left] + nums[right] == twoSum {
                            result.append([nums[i], nums[j], nums[left], nums[right]])
                            while left < right && nums[left] == nums[left + 1] {
                                left += 1
                            }
                            while left < right && nums[right] == nums[right - 1] {
                                right -= 1
                            }
                            left += 1
                            right -= 1
                        } else if nums[left] + nums[right] < twoSum {
                            left += 1
                        } else {
                            right -= 1
                        }
                    }
                }
            }
        return result
    }

猜你喜欢

转载自blog.csdn.net/sky_long_fly/article/details/87714597