├── LICENSE ├── README.md └── solutions ├── 108_Convert_Sorted_Array_to_Binary_Search_Tree.playground ├── Contents.swift └── contents.xcplayground ├── 10_Regular_Expression_Matching.playground ├── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── daiyuesmacbook.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── timeline.xctimeline ├── 11_Container_With_Most_Water.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 12_Integer_to_Roman.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 136_Single_Number.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 13_Roman_to_Integer.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 14_Longest_Common_Prefix.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 15_3Sum.playground ├── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── daiyuesmacbook.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── timeline.xctimeline ├── 160_Intersection_of_Two_Linked_Lists.playground ├── Contents.swift └── contents.xcplayground ├── 16_3Sum_Closest.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 17_Letter_Combinations_of_a_Phone_Number.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 18_4Sum.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 198_House_Robber.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 19_Remove_Nth_Node_From_End_of_List.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 1_Two_Sum.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 20_Valid_Parentheses.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 212_Word_Search_II.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 217_Contains_Duplicate.playground ├── Contents.swift └── contents.xcplayground ├── 219_Contains_Duplicate_II.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 21_Merge_Two_Sorted_Lists.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 220_Contains_Duplicate_III.playground ├── Contents.swift └── contents.xcplayground ├── 221_Maximal_Square.playground ├── Contents.swift └── contents.xcplayground ├── 227_Basic_Calculator_II.playground ├── Contents.swift └── contents.xcplayground ├── 22_Generate_Parentheses.playground ├── Contents.swift └── contents.xcplayground ├── 23_Merge_k_Sorted_Lists.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 24_Swap_Node_In_Pairs.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 25_Reverse_Nodes_in_k-Group.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 269_Alien_Dictionary.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 26_Remove_Duplicates_from_Sorted_Array.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 27_Remove_Element.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 28_Implement_strStr.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 29_Divide_Two_Integers.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 2_Add_Two_Numbers.playground ├── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── daiyuesmacbook.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── timeline.xctimeline ├── 30_Substring_with_Concatenation_of_All_Words.playground ├── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── daiyuesmacbook.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── timeline.xctimeline ├── 31_Next_Permutation.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 32_Longest_Valid_Parentheses.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 336_Palindrome_Pair.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 33_Search_in_Rotated_Sorted_Array.playground ├── Contents.swift └── contents.xcplayground ├── 34_Search_for_a_Range.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 35_Search_Insert_Position.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 36_Valid_Sudoku.playground ├── Contents.swift ├── contents.xcplayground └── timeline.xctimeline ├── 37_Sudoku_Solver.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 385_Mini_Parser.playground ├── Contents.swift └── contents.xcplayground ├── 3_Longest_Substring_Without_Repeating_Characters.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 415_Add_Strings.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 4_Median_of_two_sorted_arrays.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 5_Longest_Palindromic_Substring.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 68_Text_Justification.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 6_ZigZag_conversion.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 7_Reverse_Integer.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate ├── 8_String_to_Integer.playground ├── Contents.swift ├── contents.xcplayground └── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate └── 9_Palindrome_Number.playground ├── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace ├── contents.xcworkspacedata └── xcuserdata │ └── daiyuesmacbook.xcuserdatad │ └── UserInterfaceState.xcuserstate └── timeline.xctimeline /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Dai Yue 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Leet code Swift 题解 2 | 3 | 仅为个人学习用,只能保证在 Leet code 上通过,也可能有的语法不完全规范,或者有更好的解法。讨论欢迎留 issue :) 4 | 5 | | # | 题目 | 题解 | 6 | | ------------- |:-------------:| -----:| 7 | | 1 | [Two Sum](https://leetcode.com/problems/two-sum/) | [题解](./solutions/1_Two_Sum.playground/Contents.swift) | 8 | | 2 | [Add Two Numbers](https://leetcode.com/problems/add-two-numbers/)   | [题解](./solutions/2_Add_Two_Numbers.playground/Contents.swift) | 9 | | 3 | [Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/) | [题解](./solutions/3_Longest_Substring_Without_Repeating_Characters.playground) | 10 | | 4 | [Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays/) | [题解](./solutions/4_Median_of_two_sorted_arrays.playground/Contents.swift) | 11 | | 5 | [Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring/) | [题解](./solutions/5_Longest_Palindromic_Substring.playground/Contents.swift) | 12 | | 6 | [ZigZag Conversion](https://leetcode.com/problems/zigzag-conversion/) | [题解](./solutions/6_ZigZag_conversion.playground/Contents.swift) | 13 | | 7 | [Reverse Integer](https://leetcode.com/problems/reverse-integer/) | [题解](./solutions/7_Reverse_Integer.playground/Contents.swift) | 14 | | 8 | [String to Integer](https://leetcode.com/problems/string-to-integer/) | [题解](./solutions/8_String_to_Integer.playground/Contents.swift) | 15 | | 9 | [Palindrome Number](https://leetcode.com/problems/palindrome-number/) | [题解](./solutions/9_Palindrome_Number.playground/Contents.swift) | 16 | | 10 | [Regular Expression Matching](https://leetcode.com/problems/regular-expression-matching/) | [题解](./solutions/10_Regular_Expression_Matching.playground/Contents.swift) | 17 | | 11 | [Container With Most Water](https://leetcode.com/problems/container-with-most-water/) | [题解](./solutions/11_Container_With_Most_Water.playground/Contents.swift) | 18 | | 12 | [Integer to Roman](https://leetcode.com/problems/integer-to-roman/) | [题解](./solutions/12_Integer_to_Roman.playground/Contents.swift) | 19 | | 13 | [Roman to Integer](https://leetcode.com/problems/roman-to-integer/) | [题解](./solutions/13_Roman_to_Integer.playground/Contents.swift) | 20 | | 14 | [Longest Common Prefix](https://leetcode.com/problems/longest-common-prefix/) | [题解](./solutions/14_Longest_Common_Prefix.playground/Contents.swift) | 21 | | 15 | [3Sum](https://leetcode.com/problems/3sum/) | [题解](./solutions/15_3Sum.playground/Contents.swift) | 22 | | 16 | [3Sum closest](https://leetcode.com/problems/3sum-closest/) | [题解](./solutions/16_3Sum_Closest.playground/Contents.swift) | 23 | | 17 | [Letter Combinations of a Phone Number](https://leetcode.com/problems/letter-combinations-of-a-phone-number/) | [题解](./solutions/17_Letter_Combinations_of_a_Phone_Number.playground/Contents.swift) | 24 | | 18 | [4Sum](https://leetcode.com/problems/4sum/) | [题解](./solutions/18_4Sum.playground/Contents.swift) | 25 | | 19 | [Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list) | [题解](./solutions/19_Remove_Nth_Node_From_End_of_List.playground/Contents.swift) | 26 | | 20 | [Valid Parentheses](https://leetcode.com/problems/valid-parentheses/) | [题解](./solutions/20_Valid_Parentheses.playground/Contents.swift) | 27 | | 21 | [Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists/) | [题解](./solutions/21_Merge_Two_Sorted_Lists.playground/Contents.swift) | 28 | | 22 | [Generate Parentheses](https://leetcode.com/problems/generate-parentheses/) | [题解](./solutions/22_Generate_Parentheses.playground/Contents.swift) | 29 | | 23 | [Merge k Sorted Lists](https://leetcode.com/submissions/detail/90095220/) | [题解](./solutions/23_Merge_k_Sorted_Lists.playground/Contents.swift) | 30 | | 24 | [Swap Node in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs/) | [题解](./solutions/24_Swap_Node_In_Pairs.playground/Contents.swift) | 31 | | 25 | [Reverse Nodes in k-Group](https://leetcode.com/problems/reverse-nodes-in-k-group/) | [题解](./solutions/25_Reverse_Nodes_in_k-Group.playground/Contents.swift) | 32 | | 26 | [Remove Duplicates from Sorted Array](https://leetcode.com/problems/remove-duplicates-from-sorted-array/) | [题解](./solutions/26_Remove_Duplicates_from_Sorted_Array/Contents.swift) | 33 | | 27 | [Remove Element](https://leetcode.com/problems/remove-element/) | [题解](./solutions/27_Remove_Element.playground/Contents.swift) | 34 | | 28 | [Implement strStr()](https://leetcode.com/problems/implement-strstr/) | [题解](./solutions/28_Implement_strStr.playground/Contents.swift) | 35 | | 29 | [Divide Two Integers](https://leetcode.com/problems/divide-two-integers/) | [题解](./solutions/29_Divide_Two_Integers.playground/Contents.swift) | 36 | -------------------------------------------------------------------------------- /solutions/108_Convert_Sorted_Array_to_Binary_Search_Tree.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #108 Convert Sorted Array to Binary Search Tree https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/?tab=Description 2 | // 简单的数据结构题,只要知道 BST 的定义就能做出来。树的题一般都是递归的方法比较方便。 3 | // 我奇怪的是为啥这道题我做得这么慢呢,加上判断只能 beat 12%。其他人怎么做的?是不是非递归比较快呢。 4 | // 时间复杂度:O(n) 空间复杂度:O(n) 5 | 6 | public class TreeNode { 7 | public var val: Int 8 | public var left: TreeNode? 9 | public var right: TreeNode? 10 | public init(_ val: Int) { 11 | self.val = val 12 | self.left = nil 13 | self.right = nil 14 | } 15 | } 16 | 17 | class Solution { 18 | func sortedArrayToBST(_ nums: [Int]) -> TreeNode? { 19 | guard nums.count > 0 else { 20 | return nil 21 | } 22 | 23 | let middleIndex = nums.count / 2 24 | let node = TreeNode(nums[middleIndex]) 25 | node.left = sortedArrayToBST(Array(nums[0 ..< middleIndex])) 26 | node.right = sortedArrayToBST(Array(nums[middleIndex + 1 ..< nums.count])) 27 | 28 | return node 29 | } 30 | } -------------------------------------------------------------------------------- /solutions/108_Convert_Sorted_Array_to_Binary_Search_Tree.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/10_Regular_Expression_Matching.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #10 Regular Expression Matching https://leetcode.com/problems/regular-expression-matching/ 2 | // 评级为 hard,但感觉这题不难…… 就是递归一位一位往后读,遇到 * 就分两种情况,用尽这个 token 或者下轮接着用这个 token。 3 | // 一个问题就是直接递归会超时。需要先把正则式处理一下: 4 | // 1. a*a* 合并为 a* 5 | // 2. a*.*b* 合并为 .*(就是 .* 前后所有的 x* 全都去掉)。 6 | // 时间复杂度:O(n) 空间复杂度:O(n) 7 | 8 | struct Token { 9 | var char:Character 10 | var isStar:Bool 11 | } 12 | 13 | class Solution { 14 | func isMatch(_ s: String, _ p: String) -> Bool { 15 | return isMatch(sChars: [Character](s.characters), tokens: generateTokensFrom(pattern: p)) 16 | } 17 | 18 | func generateTokensFrom(pattern:String) -> [Token] { 19 | let chars = [Character](pattern.characters) 20 | var tokens = [Token]() 21 | var index = 0 22 | while index < chars.count { 23 | let char = chars[index] 24 | let nextChar = index + 1 < chars.count ? chars[index + 1] : " " 25 | 26 | if nextChar == "*" { 27 | index = index + 2 28 | let lastToken = tokens.count > 0 ? tokens.last! : Token(char: " ", isStar: false) 29 | if lastToken.isStar == true && (lastToken.char == char || lastToken.char == ".") { 30 | continue // ignore x* after x* or .* 31 | } 32 | if char == "." { 33 | while tokens.count > 0 && tokens.last?.isStar == true { 34 | tokens.popLast() // remove every x* before .* 35 | } 36 | } 37 | tokens.append(Token(char: char, isStar: true)) 38 | } else { 39 | index = index + 1 40 | tokens.append(Token(char: char, isStar: false)) 41 | } 42 | } 43 | 44 | return tokens 45 | } 46 | 47 | func isMatch(sChars : [Character], tokens : [Token]) -> Bool { 48 | guard tokens.count > 0 else { 49 | return sChars.count == 0 ? true : false 50 | } 51 | 52 | guard sChars.count > 0 else { 53 | for token in tokens { 54 | if !token.isStar { 55 | return false 56 | } 57 | } 58 | return true 59 | } 60 | 61 | let token = tokens[0] 62 | let sChar = sChars[0] 63 | let nextS = Array(sChars.dropFirst()) 64 | let nextTokens = Array(tokens.dropFirst()) 65 | 66 | let match = token.char == "." || token.char == sChar 67 | if token.isStar { 68 | if match && (isMatch(sChars:nextS, tokens:nextTokens) || isMatch(sChars:nextS, tokens:tokens)) { 69 | return true 70 | } 71 | return isMatch(sChars:sChars, tokens:nextTokens) 72 | } else { 73 | return match && isMatch(sChars:nextS, tokens:nextTokens) 74 | } 75 | } 76 | } 77 | 78 | Solution().isMatch("aa", "a") 79 | Solution().isMatch("aa", "aa") 80 | Solution().isMatch("aaa", "aa") 81 | Solution().isMatch("aa", "a*") 82 | Solution().isMatch("aa", ".*") 83 | Solution().isMatch("ab", ".*") 84 | Solution().isMatch("aab", "c*a*b") 85 | Solution().isMatch("a", "ab*") 86 | Solution().isMatch("bbacbcabbbbbcacabb", "aa*c*b*a*.*a*a.*.") 87 | -------------------------------------------------------------------------------- /solutions/10_Regular_Expression_Matching.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/10_Regular_Expression_Matching.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/10_Regular_Expression_Matching.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/10_Regular_Expression_Matching.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/10_Regular_Expression_Matching.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /solutions/11_Container_With_Most_Water.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #11 Container With Most Water https://leetcode.com/problems/container-with-most-water/ 2 | // 本来想的是搜索加剪枝,搜以每个点做一端的。最坏情况 O(n^2),结果最后有两组数据(就是最坏情况)过不去,超时。 3 | // 改成题解里这样,从两边往中间搜,结果变成 O(n) 了。想改成记忆化搜索,发现很难。 4 | // 搜索的顺序果然还是非常重要!很多东西从后往前搜,从中间往两边搜,从两边往中间搜,就差得多了…… 5 | // 时间复杂度:O(n) 空间复杂度:O(1) 6 | 7 | class Solution { 8 | func maxArea(_ height: [Int]) -> Int { 9 | var maxArea = 0 10 | var i = 0, j = height.count - 1 11 | while i < j { 12 | let area = (j - i) * min(height[i], height[j]) 13 | maxArea = max(maxArea, area) 14 | if height[i] < height[j] { 15 | i = i + 1 16 | } else { 17 | j = j - 1 18 | } 19 | } 20 | return maxArea 21 | } 22 | } 23 | 24 | Solution().maxArea([1, 1]) 25 | -------------------------------------------------------------------------------- /solutions/11_Container_With_Most_Water.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/11_Container_With_Most_Water.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/11_Container_With_Most_Water.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/11_Container_With_Most_Water.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/12_Integer_to_Roman.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #12 Integer to Roman https://leetcode.com/problems/integer-to-roman/ 2 | // 很简单的递归,没什么可说的。就是细心一点吧。 3 | // 看到题解是把 1000、900、500 都存起来,这样确实快很多,因为不用考虑往左加的情况。另外非递归因为不用算 10 次幂可能略快一点。 4 | // 时间复杂度:O(lgn) 空间复杂度:O(1) 5 | 6 | class Solution { 7 | func intToRoman(_ num: Int) -> String { 8 | guard num > 0 else { 9 | return "" 10 | } 11 | 12 | let lettersForOne = ["O", "I", "X", "C", "M"] 13 | let lettersForFive = ["O", "V", "L", "D"] 14 | 15 | var digits = 1 16 | var numToCompare = 1 17 | while numToCompare * 10 <= num { 18 | numToCompare = numToCompare * 10 19 | digits += 1 20 | } 21 | 22 | let highestDigit = num / numToCompare 23 | var leftPart = "", middlePart = "", rightPart = "" 24 | if highestDigit <= 3 { 25 | for _ in 1...highestDigit { 26 | middlePart.append(lettersForOne[digits]) 27 | } 28 | 29 | } else if highestDigit <= 5 { 30 | middlePart = lettersForFive[digits] 31 | if highestDigit == 4 { 32 | leftPart = lettersForOne[digits] 33 | } 34 | 35 | } else if highestDigit <= 8 { 36 | middlePart = lettersForFive[digits] 37 | for _ in 6...highestDigit { 38 | rightPart.append(lettersForOne[digits]) 39 | } 40 | 41 | } else { // highestDigit = 9 42 | middlePart = lettersForOne[digits + 1] 43 | leftPart = lettersForOne[digits] 44 | } 45 | rightPart += intToRoman(num - highestDigit * numToCompare) 46 | 47 | return leftPart + middlePart + rightPart 48 | } 49 | 50 | } 51 | 52 | Solution().intToRoman(3) 53 | Solution().intToRoman(31) 54 | Solution().intToRoman(5) 55 | Solution().intToRoman(4) 56 | Solution().intToRoman(41) 57 | Solution().intToRoman(9) 58 | Solution().intToRoman(99) 59 | Solution().intToRoman(89) 60 | Solution().intToRoman(10) 61 | Solution().intToRoman(3999) -------------------------------------------------------------------------------- /solutions/12_Integer_to_Roman.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/12_Integer_to_Roman.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/12_Integer_to_Roman.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/12_Integer_to_Roman.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/136_Single_Number.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #136 Single Number https://leetcode.com/problems/single-number/?tab=Description 2 | // 以前在什么书上看到过这道题,感觉这种题完全没意义…… 就是听说过的会做,没听过的不会做。 3 | // 利用一个数异或两次还等于原本的数的特点,直接把每个数都异或一遍。初始的数是 0 ,所以最后所剩的结果就是单独的数本身。 4 | // 时间复杂度:O(n) 空间复杂度:O(1) 5 | 6 | class Solution { 7 | func singleNumber(_ nums: [Int]) -> Int { 8 | var temp = 0 9 | for num in nums { 10 | temp = temp ^ num 11 | } 12 | return temp 13 | } 14 | } -------------------------------------------------------------------------------- /solutions/136_Single_Number.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/136_Single_Number.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/136_Single_Number.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/136_Single_Number.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/13_Roman_to_Integer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #13 Roman to Integer https://leetcode.com/problems/roman-to-integer/ 2 | // 很简单的题,没啥可说的。分情况讨论,简单递归即可(我怎么这么喜欢递归……) 3 | // 题解的思路挺巧妙,倒着往前扫,比前一位大就往上加,没前一位大就减掉。算是利用了罗马数字一个很好的特性吧。 4 | // 不过想了想好像没啥倒过来的必要啊…… 直接从前往后扫也是一样 O O 5 | // 时间复杂度:O(n) 空间复杂度:O(n) 6 | 7 | class Solution { 8 | func romanToInt(_ s:String) -> Int { 9 | let chars = [Character](s.characters) 10 | 11 | var result = 0 12 | for i in 0 ..< chars.count - 1 { 13 | let num1 = romanLetterToInt(chars[i]), num2 = romanLetterToInt(chars[i + 1]) 14 | if num1 < num2 { 15 | result -= num1 16 | } else { 17 | result += num1 18 | } 19 | } 20 | result += romanLetterToInt(chars.last!) 21 | 22 | return result 23 | } 24 | 25 | func romanToInt_recursive(_ s: String) -> Int { 26 | let chars = [Character](s.characters) 27 | guard chars.count > 0 else { 28 | return 0 29 | } 30 | let num1 = romanLetterToInt(chars[0]) 31 | guard chars.count > 1 else { 32 | return num1 33 | } 34 | let num2 = romanLetterToInt(chars[1]) 35 | var result = 0 36 | if num1 < num2 { 37 | result = num2 - num1 + romanToInt(String(chars.suffix(from: 2))) 38 | } else { 39 | var i = 1 40 | while i < chars.count && chars[i] == chars[0] { 41 | i += 1 42 | } 43 | result = num1 * i + romanToInt(String(chars.suffix(from: i))) 44 | } 45 | return result 46 | } 47 | 48 | func romanLetterToInt(_ char: Character) -> Int { 49 | let letterNumDict : [Character : Int] = ["I" : 1, "V" : 5, "X" : 10, "L" : 50, "C" : 100, "D" : 500, "M" : 1000] 50 | return letterNumDict[char] != nil ? letterNumDict[char]! : 0 51 | } 52 | } 53 | 54 | Solution().romanToInt("XLIV") 55 | Solution().romanToInt("III") 56 | Solution().romanToInt("XXXI") 57 | Solution().romanToInt("XI") 58 | -------------------------------------------------------------------------------- /solutions/13_Roman_to_Integer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/13_Roman_to_Integer.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/13_Roman_to_Integer.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/13_Roman_to_Integer.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/14_Longest_Common_Prefix.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #14 Longest Common Prefix https://leetcode.com/problems/longest-common-prefix/ 2 | // 太简单的字符串处理,没什么可说的。 3 | // 时间复杂度:O(nm) 空间复杂度:O(nm) 4 | 5 | 6 | class Solution { 7 | func longestCommonPrefix(_ strs: [String]) -> String { 8 | guard strs.count > 0 else { 9 | return "" 10 | } 11 | 12 | var charss : [[Character]] = [] 13 | for string in strs { 14 | charss.append([Character](string.characters)) 15 | } 16 | 17 | var maxPrefixLength = 1 18 | let firstChars = charss[0] 19 | while maxPrefixLength <= firstChars.count { 20 | let firstChar = firstChars[maxPrefixLength - 1] 21 | for chars in charss { 22 | if maxPrefixLength > chars.count || chars[maxPrefixLength - 1] != firstChar { 23 | return String(firstChars[0 ..< maxPrefixLength - 1]) 24 | } 25 | } 26 | maxPrefixLength += 1 27 | } 28 | 29 | return String(firstChars[0 ..< maxPrefixLength - 1]) 30 | } 31 | } 32 | 33 | Solution().longestCommonPrefix(["aa", "aa"]) 34 | -------------------------------------------------------------------------------- /solutions/14_Longest_Common_Prefix.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/14_Longest_Common_Prefix.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/14_Longest_Common_Prefix.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/14_Longest_Common_Prefix.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/15_3Sum.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #15 3Sum https://leetcode.com/problems/3sum/ 2 | // 我用的还是 hash 方法,先找第一个数、再找第二个数…… 去重的方法就是要求三个数的序关系,这样就不会重了。 3 | // 看到一个题解用的是先排序,然后先定第一个数,第二个数左头,第三个数右头。然后大了挪小的、小了挪大的…… 这样。算是另一种思路吧。 4 | // 时间复杂度:O(n^2) 空间复杂度:O(n) 5 | 6 | class Solution { 7 | func threeSum(_ nums: [Int]) -> [[Int]] { 8 | var numDict : [Int:Int] = [:] 9 | for i in nums { 10 | if numDict[i] == nil { 11 | numDict[i] = 1 12 | } else { 13 | numDict[i] = numDict[i]! + 1 14 | } 15 | } 16 | 17 | var results : [[Int]] = [] 18 | for (num1, count1) in numDict { 19 | numDict[num1] = count1 - 1 20 | 21 | for (num2, count2) in numDict { 22 | let num3 = 0 - num1 - num2 23 | guard count2 > 0 && num1 <= num2 && num2 <= num3 else { 24 | continue 25 | } 26 | 27 | if (num2 == num3 && count2 >= 2) || (num2 != num3 && numDict[num3] != nil) { 28 | results.append([num1, num2, num3]) 29 | } 30 | } 31 | 32 | numDict[num1] = count1 33 | } 34 | 35 | return results 36 | } 37 | } 38 | 39 | Solution().threeSum([-1, 0, 1, 2, -1, -4]) 40 | Solution().threeSum([1,2,-2,-1]) 41 | Solution().threeSum([0, 0, 0]) 42 | -------------------------------------------------------------------------------- /solutions/15_3Sum.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/15_3Sum.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/15_3Sum.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/15_3Sum.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/15_3Sum.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /solutions/160_Intersection_of_Two_Linked_Lists.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #202 Happy Number https://leetcode.com/problems/happy-number/?tab=Description 2 | // 简单模拟。没什么好说的。 3 | // 值得一提的是,在题解里看到一个很有趣的解法,可以不用 hash 排重。就是用两个数,一个往前推一步,一个往前推两步,直到他俩重合…… 再判断是否是 1。跟单链表里存在环的判断差不多。 4 | // 时间/空间复杂度:... 不知道 >< 大概需要点证明了。 5 | 6 | class Solution { 7 | func isHappy(_ n: Int) -> Bool { 8 | var numSet = Set() 9 | var num = n 10 | while !numSet.contains(num) && num != 1 { 11 | numSet.insert(num) 12 | 13 | var sum = 0 14 | while num > 0 { 15 | let lastDigit = num % 10 16 | sum += lastDigit * lastDigit 17 | num /= 10 18 | } 19 | 20 | num = sum 21 | } 22 | 23 | return num == 1 24 | } 25 | } 26 | 27 | Solution().isHappy(18) -------------------------------------------------------------------------------- /solutions/160_Intersection_of_Two_Linked_Lists.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/16_3Sum_Closest.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #16 3Sum Closest https://leetcode.com/problems/3sum-closest/ 2 | // 这时候就用上上一题的排序思路了。先排好序,然后指定第一个数从左往右,第二个为第一个数右边(剩下区间的最左端),第三个数为最右端。然后小了把左边的往右挪、大了把右边的往左挪…… 3 | // 时间复杂度:O(n^2) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | func threeSumClosest(_ nums: [Int], _ target: Int) -> Int { 7 | guard nums.count >= 3 else { 8 | return 0 9 | } 10 | 11 | var sortedNums = nums.sorted(by:{$0 < $1}) 12 | var minDifference = Int.max 13 | 14 | for i in 0 ... sortedNums.count - 3 { 15 | if i > 0 && sortedNums[i] == sortedNums[i - 1] { 16 | continue 17 | } 18 | 19 | var left = i + 1 20 | var right = sortedNums.count - 1 21 | while left < right { 22 | let sum = sortedNums[i] + sortedNums[left] + sortedNums[right] 23 | let difference = target - sum 24 | if abs(difference) < abs(minDifference) { 25 | minDifference = difference 26 | if difference == 0 { 27 | return target 28 | } 29 | } 30 | 31 | if sum < target { 32 | repeat { 33 | left += 1 34 | } while (left < right && sortedNums[left] == sortedNums[left - 1]) 35 | } else { 36 | repeat { 37 | right -= 1 38 | } while (left < right && sortedNums[right] == sortedNums[right + 1]) 39 | } 40 | } 41 | } 42 | 43 | return target - minDifference 44 | } 45 | } 46 | 47 | Solution().threeSumClosest([-1, 2, 1, -4], 1) -------------------------------------------------------------------------------- /solutions/16_3Sum_Closest.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/16_3Sum_Closest.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/16_3Sum_Closest.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/16_3Sum_Closest.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/17_Letter_Combinations_of_a_Phone_Number.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #17 Letter Combinations of a Phone Number https://leetcode.com/problems/letter-combinations-of-a-phone-number/ 2 | // 懒癌犯了…… 明明一道广搜的题,又写成“递归”了,仅仅是因为懒得开两个数组…… 是不是已经没得救了 O O 3 | // 好吧,后面老实补了一个正常版本。然后发现“递归”版本快得多…… 完全想不到任何原因呀,明明“递归”版本无谓地构造了一些后缀字符串,难道是拷贝数组很慢? 4 | // 时间复杂度:3^n 空间复杂度:3^n 5 | 6 | class Solution { 7 | func letterCombinations(_ digits: String) -> [String] { 8 | let lettersOfNums : [Character : [String]] = ["1":[], 9 | "2":["a", "b", "c"], 10 | "3":["d", "e", "f"], 11 | "4":["g", "h", "i"], 12 | "5":["j", "k", "l"], 13 | "6":["m", "n", "o"], 14 | "7":["p", "q", "r", "s"], 15 | "8":["t", "u", "v"], 16 | "9":["w", "x", "y", "z"]] 17 | 18 | let characters = [Character](digits.characters) 19 | guard characters.count > 0 else { 20 | return [] 21 | } 22 | 23 | var combinations : [String] = [] 24 | for digit in characters { 25 | guard let letters = lettersOfNums[digit] else { 26 | return [] 27 | } 28 | guard combinations.count > 0 else { 29 | combinations = letters 30 | continue 31 | } 32 | 33 | var nextCombinations : [String] = [] 34 | for combination in combinations { 35 | for letter in letters { 36 | nextCombinations.append(combination + letter) 37 | } 38 | } 39 | 40 | combinations = nextCombinations 41 | } 42 | 43 | return combinations 44 | } 45 | 46 | func letterCombinations_recursive(_ digits: String) -> [String] { 47 | let lettersOfNums : [Character : [String]] = ["1":[], 48 | "2":["a", "b", "c"], 49 | "3":["d", "e", "f"], 50 | "4":["g", "h", "i"], 51 | "5":["j", "k", "l"], 52 | "6":["m", "n", "o"], 53 | "7":["p", "q", "r", "s"], 54 | "8":["t", "u", "v"], 55 | "9":["w", "x", "y", "z"]] 56 | 57 | let characters = [Character](digits.characters) 58 | guard characters.count > 0 else { 59 | return [] 60 | } 61 | 62 | let firstDigit = characters[0] 63 | guard let letters = lettersOfNums[firstDigit] else { 64 | return [] 65 | } 66 | guard characters.count > 1 else { 67 | return letters 68 | } 69 | 70 | let restCombinations = letterCombinations_recursive(String(characters.suffix(from: 1))) 71 | var combinations : [String] = [] 72 | for letter in letters { 73 | for restCombination in restCombinations { 74 | combinations.append(letter + restCombination) 75 | } 76 | } 77 | return combinations 78 | } 79 | } 80 | 81 | Solution().letterCombinations("23") -------------------------------------------------------------------------------- /solutions/17_Letter_Combinations_of_a_Phone_Number.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/17_Letter_Combinations_of_a_Phone_Number.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/17_Letter_Combinations_of_a_Phone_Number.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/17_Letter_Combinations_of_a_Phone_Number.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/18_4Sum.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #18 4Sum https://leetcode.com/problems/4sum/ 2 | // 在 3Sum 基础上的延伸,先排序,再循环前两位,后两位左右夹逼。听说这样会超时?然而并没有,时间还在中位数左右。500多ms 3 | // 一些简单的剪枝,比如夹逼时最小的两个数都不够小、最大的两个数都不够大,那也就没必要继续了。加了这些剪枝,虽然代码长了很多很多,但是嗖快嗖快的,只要 52 ms。一下 beats 100% submissions,好有成就感呀。 4 | // 时间复杂度:O(n^3) 空间复杂度:O(n) 5 | 6 | class Solution { 7 | func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] { 8 | guard nums.count >= 4 else { 9 | return [] 10 | } 11 | 12 | var sortedNums = nums.sorted(by:{$0 < $1}) 13 | var result : [[Int]] = [] 14 | 15 | for i in 0 ... sortedNums.count - 4 { 16 | if i > 0 && sortedNums[i] == sortedNums[i - 1] { 17 | continue 18 | } 19 | 20 | // pruning 21 | let minSum = sortedNums[i] + sortedNums[i + 1] + sortedNums[i + 2] + sortedNums[i + 3] 22 | if minSum > target { 23 | break 24 | } else if minSum == target { 25 | result.append([sortedNums[i], sortedNums[i + 1], sortedNums[i + 2], sortedNums[i + 3]]) 26 | break 27 | } 28 | 29 | let maxSum = sortedNums[i] + sortedNums[sortedNums.count - 1] + sortedNums[sortedNums.count - 2] + sortedNums[sortedNums.count - 3] 30 | if maxSum < target { 31 | continue 32 | } else if maxSum == target { 33 | result.append([sortedNums[i], sortedNums[sortedNums.count - 1], sortedNums[sortedNums.count - 2], sortedNums[sortedNums.count - 3]]) 34 | continue 35 | } 36 | 37 | for j in i + 1 ... sortedNums.count - 3 { 38 | if j > i + 1 && sortedNums[j] == sortedNums[j - 1] { 39 | continue 40 | } 41 | 42 | let partialTarget = target - sortedNums[i] - sortedNums[j] 43 | 44 | // pruning 45 | let minSum = sortedNums[j + 1] + sortedNums[j + 2] 46 | if minSum > partialTarget { 47 | break 48 | } else if minSum == partialTarget { 49 | result.append([sortedNums[i], sortedNums[j], sortedNums[j + 1], sortedNums[j + 2]]) 50 | break 51 | } 52 | 53 | let maxSum = sortedNums[sortedNums.count - 1] + sortedNums[sortedNums.count - 2] 54 | if maxSum < partialTarget { 55 | continue 56 | } else if maxSum == partialTarget { 57 | result.append([sortedNums[i], sortedNums[j], sortedNums[sortedNums.count - 1], sortedNums[sortedNums.count - 2]]) 58 | continue 59 | } 60 | 61 | var left = j + 1 62 | var right = sortedNums.count - 1 63 | 64 | while left < right { 65 | let sum = sortedNums[left] + sortedNums[right] 66 | if sum == partialTarget { 67 | result.append([sortedNums[i], sortedNums[j], sortedNums[left], sortedNums[right]]) 68 | } 69 | 70 | if sum < partialTarget { 71 | repeat { 72 | left += 1 73 | } while (left < right && sortedNums[left] == sortedNums[left - 1]) 74 | } else { 75 | repeat { 76 | right -= 1 77 | } while (left < right && sortedNums[right] == sortedNums[right + 1]) 78 | } 79 | } 80 | } 81 | } 82 | 83 | return result 84 | } 85 | } 86 | 87 | Solution().fourSum([1, 0, -1, 0, -2, 2], 0) -------------------------------------------------------------------------------- /solutions/18_4Sum.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/18_4Sum.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/18_4Sum.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/18_4Sum.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/198_House_Robber.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #198 House Robber https://leetcode.com/problems/house-robber/?tab=Description 2 | // 一个很简单的动归…… 我写的是二维的转移方程,f[i][0] 代表从 i 往前,不偷第 i 家的最大值;f[i][1] 代表从 i 往前,且偷第 i 家的最大值。看了下题解,发现一维转移方程就可以了。直接 f[i] = max(f[i - 2] + n[i] , f[i - 1]) 就行了。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | func rob(_ nums: [Int]) -> Int { 7 | guard nums.count > 0 else { 8 | return 1 9 | } 10 | 11 | var money = Array(repeating: [0,0], count: nums.count) 12 | money[0][0] = 0 13 | money[0][1] = nums[0] 14 | 15 | for i in 1 ..< nums.count { 16 | money[i][0] = max(money[i - 1][0], money[i - 1][1]) 17 | money[i][1] = money[i - 1][0] + nums[i] 18 | } 19 | 20 | return max(money[nums.count - 1][0], money[nums.count - 1][1]) 21 | } 22 | } 23 | 24 | Solution().rob([1,2]) 25 | -------------------------------------------------------------------------------- /solutions/198_House_Robber.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/198_House_Robber.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/198_House_Robber.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/198_House_Robber.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/19_Remove_Nth_Node_From_End_of_List.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #19 Remove Nth Node From End of List https://leetcode.com/problems/remove-nth-node-from-end-of-list/ 2 | // 挺简单的题,没什么可说的。只要两个指针,第一个指向头部,第二个指向第 n 个节点;然后把两个指针同时往后挪,当第二个指针到尾部时,第一个指针指向的就是就是倒数第 n 个节点,把它去了就行了。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | public class ListNode { 6 | public var val: Int 7 | public var next: ListNode? 8 | public init(_ val: Int) { 9 | self.val = val 10 | self.next = nil 11 | } 12 | } 13 | 14 | class Solution { 15 | func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { 16 | var length = 1 17 | var queueHead = head, currentNode = head?.next 18 | 19 | while currentNode != nil { 20 | if length >= n + 1 { 21 | queueHead = queueHead?.next 22 | } else { 23 | length += 1 24 | } 25 | 26 | currentNode = currentNode?.next 27 | } 28 | 29 | if length < n { 30 | return head 31 | } else if length == n { 32 | return head?.next 33 | } else { 34 | queueHead?.next = queueHead?.next?.next 35 | return head 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /solutions/19_Remove_Nth_Node_From_End_of_List.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/19_Remove_Nth_Node_From_End_of_List.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/19_Remove_Nth_Node_From_End_of_List.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/19_Remove_Nth_Node_From_End_of_List.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/1_Two_Sum.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #1 Two Sum https://leetcode.com/problems/two-sum/ 2 | // 很简单的 hash。一个小技巧是,对于每个数先看和为 target 所需的数是否已经在 dict 里,如果已经在则直接返回,否则才把自身放进 dict 里。这样只需循环一次,不用先构建 hash、再遍历,循环两次。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | import UIKit 6 | 7 | class Solution { 8 | // func twoSum(_ nums: [Int], _ target: Int) -> [Int] { 9 | // 10 | // var array:[[Int]] = [] 11 | // nums.enumerated().forEach { (offset: Int, element: Int)in 12 | // if let index = nums.index(where: { (target - element) == $0}) { 13 | // if index != offset { 14 | // array.append([index,offset]) 15 | // } 16 | // } 17 | // } 18 | // return array[0] 19 | // } 20 | 21 | func twoSum(_ nums: [Int], _ target: Int) -> [Int] { 22 | 23 | var numberIndexDict = [Int:Int]() 24 | 25 | for (index, num) in nums.enumerated() { 26 | guard let pairedIndex = numberIndexDict[target - num] else { 27 | numberIndexDict[num] = index 28 | continue 29 | } 30 | 31 | return [pairedIndex, index] 32 | } 33 | 34 | return [-1, -1] 35 | } 36 | } 37 | 38 | let solution = Solution() 39 | solution.twoSum([3,2,4], 6) 40 | -------------------------------------------------------------------------------- /solutions/1_Two_Sum.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/1_Two_Sum.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/1_Two_Sum.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/1_Two_Sum.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/20_Valid_Parentheses.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #20 Valid Parentheses https://leetcode.com/problems/valid-parentheses/ 2 | // 大概是栈的最简单的一道题了。如果是左括号,push;是右括号,pop,如果不匹配返回 false。结束后如果栈空则返回 true,否则返回 false。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | func isValid(_ s: String) -> Bool { 7 | let chars = [Character](s.characters) 8 | 9 | var stack: [Character] = [] 10 | for char in chars { 11 | if char == "(" || char == "[" || char == "{" { 12 | stack.append(char) 13 | } else if char == ")" || char == "]" || char == "}" { 14 | if isMatch(stack.last, c2: char) { 15 | stack.removeLast() 16 | } else { 17 | return false 18 | } 19 | } 20 | } 21 | 22 | return stack.count == 0 23 | } 24 | 25 | func isMatch(_ c1: Character?, c2:Character?) -> Bool { 26 | return c1 == "(" && c2 == ")" || c1 == "[" && c2 == "]" || c1 == "{" && c2 == "}" 27 | } 28 | } 29 | 30 | Solution().isValid("()") 31 | Solution().isValid("()[]{}") 32 | Solution().isValid("(]") 33 | Solution().isValid("([)]") 34 | -------------------------------------------------------------------------------- /solutions/20_Valid_Parentheses.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/20_Valid_Parentheses.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/20_Valid_Parentheses.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/20_Valid_Parentheses.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/212_Word_Search_II.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #212 Word Search II https://leetcode.com/problems/word-search-ii/?tab=Description 2 | // 这道题我一遍过的…… 实在写得累死了!不过轻松打败了 100% 的提交,我只用了 1342 ms,图上看其他人都用了 6000多 ms 哈哈 3 | // 总体来说就是一个深搜,从每个字母开始上下左右…… 这样。深搜用递归比较方便,而且我喜欢在递归方法开头判边界,而不是调用下一轮之前,这样代码可以短一点。用过的字母放到 hash 里,防止重复。 4 | // 然后存单词用的是一个字典树,凡是这种一个字母一个字母往下找的题都会很适合用字典树。最终结果用 Set 排重。 5 | // 时间复杂度:O(nm) 空间复杂度:O(n^2) 6 | 7 | class TrieNode { 8 | var char : Character 9 | var nextDict : [Character : TrieNode] = [:] 10 | var word : String? 11 | 12 | init(char: Character) { 13 | self.char = char 14 | } 15 | 16 | func addWord(_ word:String) { 17 | addWord(word: word, chars:[Character](word.characters), charIndex: 0) 18 | } 19 | 20 | func addWord(word:String, chars: [Character], charIndex: Int) { 21 | guard charIndex < chars.count else { 22 | self.word = word 23 | return 24 | } 25 | 26 | let char = chars[charIndex] 27 | 28 | var nextNode = nextDict[char] 29 | if nextNode == nil { 30 | nextNode = TrieNode(char: char) 31 | nextDict[char] = nextNode 32 | } 33 | 34 | nextNode!.addWord(word: word, chars: chars, charIndex: charIndex + 1) 35 | } 36 | } 37 | 38 | 39 | 40 | class Solution { 41 | func findWords(_ board: [[Character]], _ words: [String]) -> [String] { 42 | let tree = TrieNode(char: " ") 43 | for word in words { 44 | tree.addWord(word) 45 | } 46 | 47 | var usedPosition = [[Bool]]() 48 | for i in 0 ..< board.count { 49 | usedPosition.append(Array(repeating: false, count: board[i].count)) 50 | } 51 | 52 | var results = Set() 53 | for i in 0 ..< board.count { 54 | let line = board[i] 55 | for j in 0 ..< line.count { 56 | let partResult = findWords(board: board, usedPosition: &usedPosition, position: (x : i, y : j), trieParentNode: tree) 57 | for word in partResult { 58 | results.insert(word) 59 | } 60 | } 61 | } 62 | 63 | return Array(results) 64 | } 65 | 66 | func findWords(board: [[Character]], usedPosition: inout [[Bool]], position: (x:Int, y:Int), trieParentNode: TrieNode) -> [String] { 67 | guard position.x >= 0 && position.x < board.count else { 68 | return [] 69 | } 70 | let line = board[position.x] 71 | guard position.y >= 0 && position.y < line.count else { 72 | return [] 73 | } 74 | 75 | if usedPosition[position.x][position.y] { 76 | return [] 77 | } 78 | 79 | let char = line[position.y] 80 | guard let trieNode = trieParentNode.nextDict[char] else { 81 | return [] 82 | } 83 | 84 | var result = [String]() 85 | if trieNode.word != nil { 86 | result.append(trieNode.word!) 87 | } 88 | 89 | usedPosition[position.x][position.y] = true 90 | 91 | // up 92 | result.append(contentsOf:findWords(board: board, usedPosition: &usedPosition, position: (x:position.x - 1, y: position.y), trieParentNode: trieNode)) 93 | // down 94 | result.append(contentsOf:findWords(board: board, usedPosition: &usedPosition, position: (x:position.x + 1, y: position.y), trieParentNode: trieNode)) 95 | // left 96 | result.append(contentsOf:findWords(board: board, usedPosition: &usedPosition, position: (x:position.x, y: position.y - 1), trieParentNode: trieNode)) 97 | // right 98 | result.append(contentsOf:findWords(board: board, usedPosition: &usedPosition, position: (x:position.x, y: position.y + 1), trieParentNode: trieNode)) 99 | 100 | usedPosition[position.x][position.y] = false 101 | 102 | return result 103 | } 104 | } 105 | 106 | Solution().findWords([Array("oaan".characters),Array("etae".characters),Array("ihkr".characters),Array("iflv".characters)], ["oath","pea","eat","rain"]) 107 | -------------------------------------------------------------------------------- /solutions/212_Word_Search_II.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/212_Word_Search_II.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/212_Word_Search_II.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/212_Word_Search_II.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/217_Contains_Duplicate.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #217 Contains Duplicate https://leetcode.com/problems/contains-duplicate/?tab=Description 2 | // 最简单的 hash,没什么可说的。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | func containsDuplicate(_ nums: [Int]) -> Bool { 7 | var set = Set() 8 | for num in nums { 9 | if set.contains(num) { 10 | return true 11 | } 12 | set.insert(num) 13 | } 14 | return false 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /solutions/217_Contains_Duplicate.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/219_Contains_Duplicate_II.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #219 Contains Duplicate II https://leetcode.com/problems/contains-duplicate-ii/ 2 | // 简单的 hash。没什么可说的。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | func containsNearbyDuplicate(_ nums: [Int], _ k: Int) -> Bool { 7 | var dict = [Int : Int]() 8 | for (index, num) in nums.enumerated() { 9 | let previousNumPosition = dict[num] 10 | if previousNumPosition != nil { 11 | if index - previousNumPosition! <= k { 12 | return true 13 | } 14 | } 15 | dict[num] = index 16 | } 17 | 18 | return false 19 | } 20 | } 21 | 22 | Solution().containsNearbyDuplicate([1,2,1], 0) -------------------------------------------------------------------------------- /solutions/219_Contains_Duplicate_II.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/219_Contains_Duplicate_II.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/219_Contains_Duplicate_II.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/219_Contains_Duplicate_II.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/21_Merge_Two_Sorted_Lists.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #21 Merge Two Sorted Lists https://leetcode.com/problems/merge-two-sorted-lists/ 2 | // 很简单的归并排序,两个指针分别指向两个链表头,比较哪个指向的节点小就把哪个节点加入结果,然后把指针往后移就行了 3 | // 现在我也学会了像题解那样,在链表头部搞一个 dummy,简化代码。另外这道题可以用到 swift 的 ?? 运算符 4 | // 时间复杂度:O(n) 空间复杂度:O(1) 5 | 6 | public class ListNode { 7 | public var val: Int 8 | public var next: ListNode? 9 | public init(_ val: Int) { 10 | self.val = val 11 | self.next = nil 12 | } 13 | } 14 | 15 | class Solution { 16 | func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { 17 | var p1 = l1, p2 = l2; 18 | let head = ListNode(0) 19 | var tail = head 20 | while p1 != nil && p2 != nil { 21 | if p1!.val <= p2!.val { 22 | tail.next = p1 23 | p1 = p1!.next 24 | } else { 25 | tail.next = p2 26 | p2 = p2!.next 27 | } 28 | tail = tail.next! 29 | } 30 | 31 | tail.next = p1 ?? p2 32 | return head.next 33 | } 34 | } -------------------------------------------------------------------------------- /solutions/21_Merge_Two_Sorted_Lists.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/21_Merge_Two_Sorted_Lists.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/21_Merge_Two_Sorted_Lists.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/21_Merge_Two_Sorted_Lists.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/220_Contains_Duplicate_III.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #220 Contains Duplicated III https://leetcode.com/problems/contains-duplicate-iii/?tab=Description 2 | // 做这道题太折腾了,一开始想得很好,维护一个最大堆最小堆,随着窗口往后挪,往里插一个删一个。都写到一半了,才发现插一个好插,删一个不好删……原来用堆是不够的,得用平衡树啊 O O 3 | // 但是平衡树也太难写了…… 看了下题解,发现用桶排序很好。有个陷阱是在 0 两侧会有两个桶,所以我把所有负数的桶都 -1 往后挪了一位。 4 | // 时间复杂度:O(n) 空间复杂度:O(t) 5 | 6 | //class BinaryHeapNode { 7 | // var val : Int 8 | // var parent : BinaryHeapNode? 9 | // var leftChild : BinaryHeapNode? 10 | // var rightChild : BinaryHeapNode? 11 | // 12 | // init(_ val:Int) { 13 | // self.val = val 14 | // } 15 | // 16 | // static func < (left: BinaryHeapNode, right: BinaryHeapNode) -> Bool { 17 | // return left.val < right.val 18 | // } 19 | // 20 | // static func > (left: BinaryHeapNode, right: BinaryHeapNode) -> Bool { 21 | // return left.val > right.val 22 | // } 23 | //} 24 | 25 | //class BinaryHeap { 26 | // var nodes = [Int]() 27 | // var comparator : (Int, Int) -> Bool 28 | // 29 | // init(comparator : @escaping (Int, Int) -> Bool) { 30 | // self.comparator = comparator 31 | // } 32 | // 33 | // func insert(node: Int) { 34 | // nodes.append(node) 35 | // var index = nodes.count - 1 36 | // while index > 0 { 37 | // let parentIndex = (index - 1) / 2 38 | // if !comparator(nodes[parentIndex], nodes[index]) { 39 | // swap(&nodes[parentIndex], &nodes[index]) 40 | // index = parentIndex 41 | // } 42 | // } 43 | // } 44 | // 45 | // 46 | //} 47 | 48 | class Solution { 49 | func containsNearbyAlmostDuplicate(_ nums: [Int], _ k: Int, _ t: Int) -> Bool { 50 | guard k > 0 && nums.count > 0 && t >= 0 else { 51 | return false 52 | } 53 | 54 | let bucketSize = t + 1 55 | var bucketDict = [Int : Int]() 56 | for (index, num) in nums.enumerated() { 57 | let bucket = bucketOfNum(bucketSize: bucketSize, num: num) 58 | if bucketDict[bucket] != nil { 59 | return true 60 | } 61 | if let leftBucketNum = bucketDict[bucket - 1] { 62 | if num - leftBucketNum <= t { 63 | return true 64 | } 65 | } 66 | if let rightBucketNum = bucketDict[bucket + 1] { 67 | if rightBucketNum - num <= t { 68 | return true 69 | } 70 | } 71 | 72 | if bucketDict.count >= k { 73 | let bucketToRemove = bucketOfNum(bucketSize: bucketSize, num: nums[index - k]) 74 | bucketDict.removeValue(forKey: bucketToRemove) 75 | } 76 | bucketDict[bucket] = num 77 | } 78 | 79 | return false 80 | } 81 | 82 | func bucketOfNum(bucketSize: Int, num: Int) -> Int { 83 | if num > 0 { 84 | return num / bucketSize 85 | } 86 | return num / bucketSize - 1 87 | } 88 | } 89 | 90 | Solution().containsNearbyAlmostDuplicate([1, 3, 1], 1, 1) -------------------------------------------------------------------------------- /solutions/220_Contains_Duplicate_III.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/221_Maximal_Square.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #221 Maximal Square https://leetcode.com/problems/maximal-square/?tab=Description 2 | // 我用的是很简单的迭代,每次 size 扩大 1,记住上一轮结果,扩大时只用验证新扩展的那两条边即可。 3 | // 看了下题解,还有 O(n^2) 的 DP 做法,非常巧妙,写出来也非常简单,但感觉并不容易凭空想出。把 i , j 矩阵分为 (i - 1) , (j - 1) 和 i, j - 1 和 i - 1, j 三个小一圈的矩阵,可以证明在 i, j 点为 1 的情况下 i, j 的矩阵大小恰恰等于那三个小矩阵的最小值(可证不大于也不小于)。我觉得只能说遇到过这样的题就把它背下来,下次遇到矩阵的题就想到把它分成 3 个小矩阵去想吧,短时间内应该是很难凭空发明这个想法的。 4 | // 时间复杂度:O(n^3) 空间复杂度:O(n^2) 5 | 6 | class Solution { 7 | func maximalSquare(_ matrix: [[Character]]) -> Int { 8 | let n = matrix.count 9 | guard n > 0 else { 10 | return 0 11 | } 12 | let m = matrix[0].count 13 | guard m > 0 else { 14 | return 0 15 | } 16 | 17 | var valid = [[Bool]]() 18 | var size = 1 19 | while size <= n && size <= m { 20 | var nextValid = Array(repeating: Array(repeating: false, count: m), count: n) 21 | var hasValid = false 22 | 23 | for i in 0 ... n - size { 24 | for j in 0 ... m - size { 25 | if size == 1 { 26 | nextValid[i][j] = matrix[i][j] == "1" 27 | if nextValid[i][j] { 28 | hasValid = true 29 | } 30 | continue 31 | } 32 | 33 | guard valid[i][j] else { 34 | continue 35 | } 36 | 37 | var isValid = true 38 | let lasti = i + size - 1, lastj = j + size - 1 39 | for checkj in j ... lastj { 40 | if matrix[lasti][checkj] != "1" { 41 | isValid = false 42 | break 43 | } 44 | } 45 | if !isValid { 46 | nextValid[i][j] = false 47 | continue 48 | } 49 | for checki in i ..< lasti { 50 | if matrix[checki][lastj] != "1" { 51 | isValid = false 52 | break 53 | } 54 | } 55 | nextValid[i][j] = isValid 56 | if isValid { 57 | hasValid = true 58 | } 59 | } 60 | } 61 | 62 | guard hasValid else { 63 | break 64 | } 65 | valid = nextValid 66 | size += 1 67 | } 68 | return (size - 1) * (size - 1) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /solutions/221_Maximal_Square.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/227_Basic_Calculator_II.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #227 Basic Calculator II https://leetcode.com/problems/basic-calculator-ii/?tab=Description 2 | // 经典的表达式求值,用一个符号栈和一个数字栈。往符号栈压入的时候,如果栈顶优先级 >= 当前符号就 pop、计算、再push,直到栈空或优先级 < 当前符号。这题还有一个略微变化是含有若干多余空格。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | func calculate(_ s: String) -> Int { 7 | let chars = [Character](s.characters) 8 | guard chars.count > 0 else { 9 | return 0 10 | } 11 | 12 | var nums = [Int]() 13 | var operators = [Character]() 14 | var numStartIndex = -1, numEndIndex = -1 15 | for (index, char) in chars.enumerated() { 16 | switch char { 17 | case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9": 18 | if numStartIndex < 0 { 19 | numStartIndex = index 20 | } 21 | numEndIndex = index 22 | 23 | case "+", "-", "*", "/": 24 | let rightOperand = Int(String(chars[numStartIndex ... numEndIndex]))! 25 | numStartIndex = -1 26 | numEndIndex = -1 27 | nums.append(rightOperand) 28 | 29 | var lastOperator = operators.last 30 | while lastOperator != nil && priorityOfOperator(lastOperator!) >= priorityOfOperator(char) { 31 | let rightOperand = nums.popLast()! 32 | let leftOperand = nums.popLast()! 33 | nums.append(calculate(left: leftOperand, operand: lastOperator!, right: rightOperand)) 34 | operators.popLast() 35 | lastOperator = operators.last 36 | } 37 | 38 | operators.append(char) 39 | 40 | default: break 41 | } 42 | } 43 | 44 | let rightOperand = Int(String(chars[numStartIndex ... numEndIndex]))! 45 | nums.append(rightOperand) 46 | operators 47 | 48 | while operators.count > 0 { 49 | let rightOperand = nums.popLast()! 50 | let leftOperand = nums.popLast()! 51 | let operatorChar = operators.popLast()! 52 | calculate(left: leftOperand, operand: operatorChar, right: rightOperand) 53 | nums.append(calculate(left: leftOperand, operand: operatorChar, right: rightOperand)) 54 | } 55 | 56 | nums 57 | return nums[0] 58 | } 59 | 60 | func priorityOfOperator(_ char: Character) -> Int { 61 | switch char { 62 | case "+", "-": 63 | return 1 64 | case "*", "/": 65 | return 2 66 | default: 67 | return -1 68 | } 69 | } 70 | 71 | func calculate(left: Int, operand: Character, right: Int) -> Int { 72 | switch operand { 73 | case "+": 74 | return left + right 75 | 76 | case "-": 77 | return left - right 78 | 79 | case "*": 80 | return left * right 81 | 82 | case "/": 83 | return left / right 84 | 85 | default: 86 | return 0 87 | } 88 | } 89 | } 90 | 91 | Solution().calculate("1*2-3/4+5*6-7*8+9/10") -------------------------------------------------------------------------------- /solutions/227_Basic_Calculator_II.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/22_Generate_Parentheses.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #22 Generate Parentheses https://leetcode.com/problems/generate-parentheses/ 2 | // 我用的方法是从短到长构建,记录每个串的括号深度(每有一个左括号深度 +1,右括号深度 -1)。长度每增加 1,就在之前的每个串基础上往后拼“(”、")"并剪去深度低于 0 的情况(如 "())")。最后在所有长度为 2n 的串里找深度为 0 的就行了。 3 | // 看到题解用的也是从短到长构建,是一对一对括号往上加的,每一轮往任意位置插“()”。不过这样会出现很多重复,因此用 Set 排重。这样的方法要比我的方法慢不少,不过还是可以过的。 4 | // 因为结果集实在是很大,是指数级的,所以 case 很小,不过 8 个 case。 5 | // 时间复杂度: O(2^n) 空间复杂度:O(2^n) 6 | 7 | class ParenthesisPrefix { 8 | let content: String 9 | let depth: Int 10 | 11 | init(content: String, depth: Int) { 12 | self.content = content 13 | self.depth = depth 14 | } 15 | } 16 | 17 | 18 | class Solution { 19 | func generateParenthesis(_ n: Int) -> [String] { 20 | guard n >= 1 else { 21 | return [] 22 | } 23 | var prefixes = [ParenthesisPrefix(content: "(", depth: 1)] 24 | for _ in 2 ... n * 2 { 25 | var nextPrefixes : [ParenthesisPrefix] = [] 26 | for prefix in prefixes { 27 | nextPrefixes.append(ParenthesisPrefix(content: prefix.content + "(", depth: prefix.depth + 1)) 28 | if prefix.depth > 0 { 29 | nextPrefixes.append(ParenthesisPrefix(content: prefix.content + ")", depth: prefix.depth - 1)) 30 | } 31 | } 32 | prefixes = nextPrefixes 33 | } 34 | var validParenthesis : [String] = [] 35 | for parenthesisPrefix in prefixes { 36 | if parenthesisPrefix.depth == 0 { 37 | validParenthesis.append(parenthesisPrefix.content) 38 | } 39 | } 40 | 41 | return validParenthesis 42 | } 43 | } 44 | 45 | Solution().generateParenthesis(3) 46 | -------------------------------------------------------------------------------- /solutions/22_Generate_Parentheses.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/23_Merge_k_Sorted_Lists.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #23 Merge k Sorted Lists https://leetcode.com/submissions/detail/90095220/ 2 | // 看起来很简单的一道题,不知道为什么评级为 HARD。结果果然超时…… 3 | // 一开始想的方法是(见下面 mergeKLists_timeLimitExceeds)把所有 head 聚集起来排个序,然后取出一个最小的,把它的 next 加进去…… 看起来维护一个堆即可。我下面写的是插入排序,没有写堆,因为我发现超时的那组数据链表长度全部为 1,跟后面用什么数据结构是没关系的,只能说上来一 sort 就超时了。 4 | // 于是只好改另一种做法,两两归并。结果将将过了。评估这两种算法的时间复杂度,方法二是 knlogk,方法一是 klogk + knlogk,相当于同样是 knlogk。可能常数项有点差别,所以导致一个能过一个不过…… 5 | // 时间复杂度:O(knlogk) 空间复杂度:O(k) 6 | 7 | 8 | public class ListNode { 9 | public var val: Int 10 | public var next: ListNode? 11 | public init(_ val: Int) { 12 | self.val = val 13 | self.next = nil 14 | } 15 | } 16 | 17 | class Solution { 18 | 19 | func mergeKLists(_ lists: [ListNode?]) -> ListNode? { 20 | var lists : [ListNode] = lists.flatMap{$0} 21 | 22 | while lists.count > 1 { 23 | var nextLists = [ListNode]() 24 | for i in stride(from: 0, to:lists.count - 1 , by: 2) { 25 | nextLists.append(mergeTwoLists(lists[i], lists[i + 1])) 26 | } 27 | if lists.count % 2 == 1 { 28 | nextLists.append(lists.last!) 29 | } 30 | lists = nextLists 31 | } 32 | 33 | return lists.count > 0 ? lists[0] : nil 34 | } 35 | 36 | func mergeTwoLists(_ l1: ListNode, _ l2: ListNode) -> ListNode { 37 | var p1 : ListNode? = l1, p2 : ListNode? = l2; 38 | let head = ListNode(0) 39 | var tail = head 40 | while p1 != nil && p2 != nil { 41 | if p1!.val <= p2!.val { 42 | tail.next = p1 43 | p1 = p1!.next 44 | } else { 45 | tail.next = p2 46 | p2 = p2!.next 47 | } 48 | tail = tail.next! 49 | } 50 | 51 | tail.next = p1 ?? p2 52 | return head.next! 53 | } 54 | 55 | func mergeKLists_timeLimitExceeds(_ lists: [ListNode?]) -> ListNode? { 56 | var listHeads : [ListNode] = lists.flatMap{$0} 57 | let dummyHead = ListNode(0) 58 | var tail : ListNode = dummyHead 59 | listHeads.sort(by: {$0.val < $1.val}) 60 | 61 | while listHeads.count > 0 { 62 | let smallestHead = listHeads[0] 63 | tail.next = smallestHead 64 | tail = smallestHead 65 | 66 | guard let nextHead = smallestHead.next else { 67 | listHeads.remove(at: 0); 68 | continue 69 | } 70 | var inserted = false 71 | for i in 1 ..< listHeads.count { 72 | if listHeads[i].val >= nextHead.val { 73 | listHeads[i - 1] = nextHead 74 | inserted = true 75 | break 76 | } else { 77 | listHeads[i - 1] = listHeads[i] 78 | } 79 | } 80 | if !inserted { 81 | listHeads[listHeads.count - 1] = nextHead 82 | } 83 | } 84 | 85 | return dummyHead.next 86 | } 87 | } 88 | 89 | //[[0,2,5]] 90 | 91 | -------------------------------------------------------------------------------- /solutions/23_Merge_k_Sorted_Lists.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/23_Merge_k_Sorted_Lists.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/23_Merge_k_Sorted_Lists.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/23_Merge_k_Sorted_Lists.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/24_Swap_Node_In_Pairs.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #24 Swap Node in Pairs https://leetcode.com/problems/swap-nodes-in-pairs/ 2 | // 非常简单的链表操作,一组两个 node,换过再往下,从头顺到尾即可。 3 | // 发现单链表的题,前面加一个 dummy 真的应用很广泛,我已经用上瘾啦。 4 | // 时间复杂度:O(n) 空间复杂度:O(1) 5 | 6 | public class ListNode { 7 | public var val: Int 8 | public var next: ListNode? 9 | public init(_ val: Int) { 10 | self.val = val 11 | self.next = nil 12 | } 13 | } 14 | 15 | class Solution { 16 | func swapPairs(_ head: ListNode?) -> ListNode? { 17 | let dummy = ListNode(0) 18 | dummy.next = head 19 | 20 | var prev = dummy // prev = A 21 | while prev.next != nil && prev.next?.next != nil { // A->B->C->D => A->C->B->D 22 | let current = prev.next! // current = B 23 | 24 | prev.next = current.next // A -> C 25 | current.next = current.next?.next // B -> D 26 | prev.next?.next = current // C -> B 27 | 28 | prev = current 29 | } 30 | 31 | return dummy.next 32 | } 33 | } 34 | 35 | Solution().swapPairs(ListNode(1)) -------------------------------------------------------------------------------- /solutions/24_Swap_Node_In_Pairs.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/24_Swap_Node_In_Pairs.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/24_Swap_Node_In_Pairs.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/24_Swap_Node_In_Pairs.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/25_Reverse_Nodes_in_k-Group.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #25 Reverse Nodes in k-Group https://leetcode.com/problems/reverse-nodes-in-k-group/ 2 | // 虽然评级为 HARD,不过题并不难,只是略为繁琐…… 画个图就明白了。 3 | // 每次循环交换一组,先找到本组末尾,然后从后往前连起来,最后把本组头部连到前一组尾部后。 4 | // 时间复杂度:O(n) 空间复杂度:O(1) 5 | 6 | public class ListNode { 7 | public var val: Int 8 | public var next: ListNode? 9 | public init(_ val: Int) { 10 | self.val = val 11 | self.next = nil 12 | } 13 | } 14 | 15 | class Solution { 16 | func reverseKGroup(_ head: ListNode?, _ k: Int) -> ListNode? { 17 | let dummy = ListNode(0) 18 | dummy.next = head 19 | 20 | var prev = dummy // prev = A 21 | while prev.next != nil { // A->B->C->D->E => A->D->C->B->E 22 | var groupTail : ListNode? = prev 23 | for _ in 1...k { 24 | groupTail = groupTail?.next 25 | } 26 | guard groupTail != nil else { // groupTail = D 27 | break 28 | } 29 | 30 | let nextGroupHead = groupTail!.next // nextGroupHead = E 31 | var last = nextGroupHead // last = E 32 | var current : ListNode? = prev.next! // current = B 33 | while current != nil && current !== nextGroupHead { 34 | let next = current!.next // next = C 35 | current!.next = last // B -> E 36 | last = current // last = B 37 | current = next // current = C 38 | } 39 | 40 | groupTail = prev.next 41 | prev.next = last 42 | prev = groupTail! 43 | } 44 | 45 | return dummy.next 46 | } 47 | 48 | } 49 | 50 | let node1 = ListNode(1) 51 | let node2 = ListNode(2) 52 | let node3 = ListNode(3) 53 | let node4 = ListNode(4) 54 | node1.next = node2 55 | node2.next = node3 56 | node3.next = node4 57 | Solution().reverseKGroup(node1, 2)?.next?.next?.val 58 | -------------------------------------------------------------------------------- /solutions/25_Reverse_Nodes_in_k-Group.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/25_Reverse_Nodes_in_k-Group.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/25_Reverse_Nodes_in_k-Group.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/25_Reverse_Nodes_in_k-Group.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/269_Alien_Dictionary.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #269 Alien Dictionary https://leetcode.com/problems/alien-dictionary/?tab=Description 2 | // 在 leet code 上做到的第一道图论题。字典序由相邻每两个单词得到两个字母的序关系,形成有向图的一条边。然后按拓扑排序输出即可。 3 | // (大学毕业了这么多年我还记得拓扑排序我可真对得起老师呀~~) 4 | // 时间复杂度:O(nm) 空间复杂度:O(mn^2) 5 | 6 | class Node { 7 | var char : Character 8 | var prevs : [Character:Node] = [:] 9 | var nexts : [Character:Node] = [:] 10 | 11 | init(char: Character) { 12 | self.char = char 13 | } 14 | } 15 | 16 | class Solution { 17 | func alienOrder(_ words: [String]) -> String { 18 | guard words.count > 0 else { 19 | return "" 20 | } 21 | 22 | // build graph 23 | var nodeDict = [Character:Node]() 24 | for word in words { 25 | let chars = [Character](word.characters) 26 | for char in chars { 27 | if nodeDict[char] == nil { 28 | nodeDict[char] = Node(char: char) 29 | } 30 | } 31 | } 32 | for i in 1 ..< words.count { 33 | let currentChars = [Character](words[i].characters) 34 | let previousChars = [Character](words[i - 1].characters) 35 | 36 | var j = 0 37 | while j < currentChars.count && j < previousChars.count && currentChars[j] == previousChars[j] { 38 | j += 1 39 | } 40 | 41 | if j >= currentChars.count || j >= previousChars.count { 42 | continue 43 | } 44 | 45 | // previousChar -> currentChar 46 | let currentChar = currentChars[j] 47 | let previousChar = previousChars[j] 48 | let currentNode = nodeDict[currentChar] 49 | let previousNode = nodeDict[previousChar] 50 | 51 | previousNode!.nexts[currentChar] = currentNode 52 | currentNode!.prevs[previousChar] = previousNode 53 | } 54 | 55 | // output sequece 56 | var result = "" 57 | var nodeToOutput : Node? = nil 58 | while nodeDict.count > 0 { 59 | if nodeToOutput == nil { 60 | for (_, node) in nodeDict { 61 | if node.prevs.count == 0 { 62 | nodeToOutput = node 63 | break 64 | } 65 | } 66 | 67 | if nodeToOutput == nil { 68 | return "" 69 | } 70 | } 71 | 72 | result.append(nodeToOutput!.char) 73 | nodeDict.removeValue(forKey: nodeToOutput!.char) 74 | 75 | var nextNodeToOutput : Node? = nil 76 | for (_, nextNode) in nodeToOutput!.nexts { 77 | nextNode.prevs.removeValue(forKey:nodeToOutput!.char) 78 | if nextNode.prevs.count == 0 { 79 | nextNodeToOutput = nextNode 80 | } 81 | } 82 | 83 | nodeToOutput = nextNodeToOutput 84 | } 85 | return result 86 | } 87 | } -------------------------------------------------------------------------------- /solutions/269_Alien_Dictionary.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/269_Alien_Dictionary.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/269_Alien_Dictionary.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/269_Alien_Dictionary.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/26_Remove_Duplicates_from_Sorted_Array.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #26 Remove Duplicates from Sorted Array https://leetcode.com/problems/remove-duplicates-from-sorted-array/ 2 | // 很简单的数组处理。一个指针往后读,一个指针指向写入的位置,读到不重复的(跟前一位不一样的)就在写指针的位置写入,不然继续往后读即可。 3 | // 从这道题我们也可以学到如何在 swift 的函数里传进一个可变的参数~ 4 | // 时间复杂度:O(n) 空间复杂度:O(1) 5 | 6 | class Solution { 7 | func removeDuplicates(_ nums: inout [Int]) -> Int { 8 | guard nums.count > 0 else { 9 | return 0 10 | } 11 | 12 | var writeIndex = 1 13 | for readIndex in 1 ..< nums.count { 14 | if nums[readIndex] != nums[readIndex - 1] { 15 | nums[writeIndex] = nums[readIndex] 16 | writeIndex += 1 17 | } 18 | } 19 | 20 | return writeIndex 21 | } 22 | } 23 | 24 | var array = [1,2,2,2] 25 | Solution().removeDuplicates(&array) -------------------------------------------------------------------------------- /solutions/26_Remove_Duplicates_from_Sorted_Array.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/26_Remove_Duplicates_from_Sorted_Array.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/26_Remove_Duplicates_from_Sorted_Array.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/26_Remove_Duplicates_from_Sorted_Array.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/27_Remove_Element.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #27 Remove Element https://leetcode.com/problems/remove-element/ 2 | // 跟上一题基本完全一样,两个指针,一个读一个写。 3 | // 要注意在循环中更改数组本来是一件并不安全的事,不过在这两个例子里还好。首先长度没有改变,其次改变的部分都是读过的(废弃的)区域。总之要多想一下。 4 | // 有一点就是 removeElement2 逻辑上基本是完全一样的,不过 removeElement 跑完全部 case 是 39 ms,removeElement2 是 22 ms。差了将近一倍,看样子 for in 还是有开销 >< 不过该用肯定还是要用的。 5 | // 另外,https://leetcode.com/articles/remove-element/ 这里有一个如果需要换的元素很少时的解法,把每个不要的元素 swap 到末尾,可以减少很多写入。不过跑完全部 case 的时间是 48 ms,更多了有木有 >< 看来 case 并不符合需要去掉的元素很稀疏这个特点。 6 | // 时间复杂度:O(n) 空间复杂度:O(1) 7 | 8 | class Solution { 9 | func removeElement(_ nums: inout [Int], _ val: Int) -> Int { 10 | var writeIndex = 0 11 | for num in nums { 12 | if num != val { 13 | nums[writeIndex] = num 14 | writeIndex += 1 15 | } 16 | } 17 | return writeIndex 18 | } 19 | 20 | func removeElement2(_ nums: inout [Int], _ val: Int) -> Int { 21 | var writeIndex = 0 22 | for readIndex in 0 ..< nums.count { 23 | if nums[readIndex] != val { 24 | nums[writeIndex] = nums[readIndex] 25 | writeIndex += 1 26 | } 27 | } 28 | return writeIndex 29 | } 30 | 31 | func removeElement3(_ nums: inout [Int], _ val: Int) -> Int { 32 | var numsEndIndex = nums.count - 1, readIndex = 0 33 | while readIndex <= numsEndIndex { 34 | if nums[readIndex] == val { 35 | nums[readIndex] = nums[numsEndIndex] 36 | numsEndIndex -= 1 37 | } else { 38 | readIndex += 1 39 | } 40 | } 41 | return numsEndIndex + 1 42 | } 43 | } 44 | 45 | 46 | var array = [1, 2, 3] 47 | Solution().removeElement(&array, 1) 48 | array 49 | -------------------------------------------------------------------------------- /solutions/27_Remove_Element.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/27_Remove_Element.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/27_Remove_Element.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/27_Remove_Element.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/28_Implement_strStr.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #28 Implement strStr() https://leetcode.com/problems/implement-strstr/ 2 | // 这道题让我惊讶地发现 swift 里的 string 类不带 contains 方法,虽然它有 hasPrefix、hasSuffix 方法。有一个 range(of:) 是需要 import UIKit 的。 3 | // 正经做法是 KMP,偷懒不写,于是需要注意搜的时候不要搜到头,发现后面长度不够时停掉就可以了,不然超时。 4 | // 时间复杂度:O(nm) 空间复杂度:O(n) 5 | 6 | class Solution { 7 | func strStr(_ haystack: String, _ needle: String) -> Int { 8 | let hayChars = [Character](haystack.characters) 9 | let needleChars = [Character](needle.characters) 10 | guard needleChars.count > 0 else { 11 | return 0 12 | } 13 | guard hayChars.count >= needleChars.count else { 14 | return -1 15 | } 16 | 17 | for i in 0 ... hayChars.count - needleChars.count { 18 | var j = 0 19 | while j < needleChars.count && hayChars[i + j] == needleChars[j] { 20 | j += 1 21 | } 22 | if j == needleChars.count { 23 | return i 24 | } 25 | } 26 | return -1 27 | } 28 | } 29 | 30 | Solution().strStr("abc", "c") 31 | Solution().strStr("abc", "ab") 32 | Solution().strStr("abc", "d") -------------------------------------------------------------------------------- /solutions/28_Implement_strStr.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/28_Implement_strStr.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/28_Implement_strStr.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/28_Implement_strStr.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/29_Divide_Two_Integers.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #29 Divide Two Integers https://leetcode.com/problems/divide-two-integers/ 2 | // 别看这道题题目很简单,实际写起来非常麻烦…… 看到的很多题解都是不规范的,因为 Int32.min 不管是负一下还是取一下 abs 都会溢出…… 往往只是借用了更大的 Int 才不会溢出的 = = 或者像我一样偷懒,单判一下 Int32.min …… 不然 if 条件不知道要写的多复杂 3 | // 坑的是不让用乘除法,我就默认 << >> 也都不能用了,所以每次循环的时候,硬是把除数加到被除数的最大值。还好每次加的时候是翻倍加,所以能快一点。朴素地把被除数减除数、一个一个往下减的方法是会超时的。如果能用 << >> 就好多了,先 << 到最大,减到不能减了再 >> 1 接着减即可。 4 | // 时间复杂度:O((lgn)^2) 空间复杂度:O(1) 5 | 6 | class Solution { 7 | func divide(_ dividend: Int, _ divisor: Int) -> Int { 8 | guard divisor != 0 else { 9 | return Int(Int32.max) 10 | } 11 | guard divisor > Int(Int32.min) else { 12 | return dividend == Int(Int32.min) ? 1 : 0 13 | } 14 | 15 | let sign = divisor > 0 && dividend > 0 || divisor < 0 && dividend < 0 ? 1 : -1 16 | let divisor = sign == 1 ? divisor : -divisor 17 | 18 | var remainDividend = dividend 19 | var result = 0 20 | while ((dividend > 0 && remainDividend >= divisor) || (dividend < 0 && remainDividend <= divisor)) { 21 | var target = divisor 22 | var times = sign 23 | while (remainDividend > 0 && target < remainDividend - target) || (remainDividend < 0 && target > remainDividend - target) { 24 | target = target + target 25 | times = times + times 26 | } 27 | 28 | remainDividend -= target 29 | if sign > 0 && result >= Int(Int32.max - times) { 30 | return Int(Int32.max) 31 | } else if sign < 0 && result <= Int(Int32.min - times) { 32 | return Int(Int32.min) 33 | } 34 | result += times 35 | } 36 | 37 | return result 38 | } 39 | } 40 | 41 | Solution().divide(1, -1) 42 | -------------------------------------------------------------------------------- /solutions/29_Divide_Two_Integers.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/29_Divide_Two_Integers.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/29_Divide_Two_Integers.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/29_Divide_Two_Integers.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/2_Add_Two_Numbers.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #2 Add Two Numbers https://leetcode.com/problems/add-two-numbers/ 2 | // 简单的单链表处理。考虑几种情况:1. 两个数位数相等,且最高位不需进位 2. 两个数位数相等,且最高位需要进位 3. 两个数位数不相等 3 | // 有些算法会在结果的头部先创建一个 dummy,val 任意,真正的头结点直接往 dummy 后面插。最后返回 dummy -> next 4 | // 时间复杂度:O(n) 空间复杂度:O(1) 5 | 6 | public class ListNode { 7 | public var val: Int 8 | public var next: ListNode? 9 | public init(_ val: Int) { 10 | self.val = val 11 | self.next = nil 12 | } 13 | } 14 | 15 | class Solution { 16 | func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { 17 | if l1 == nil { 18 | return l2 19 | } 20 | 21 | if l2 == nil { 22 | return l1 23 | } 24 | 25 | var l1Tail:ListNode? = l1 26 | var l2Tail:ListNode? = l2 27 | 28 | var head:ListNode? = nil 29 | var tail:ListNode? = nil 30 | 31 | var carry = 0 32 | while l1Tail != nil || l2Tail != nil { 33 | let sum = (l1Tail?.val ?? 0) + (l2Tail?.val ?? 0) + carry 34 | carry = sum / 10 35 | let val = sum % 10 36 | 37 | let node = ListNode(val) 38 | 39 | if head == nil { 40 | head = node 41 | } else { 42 | tail!.next = node 43 | } 44 | tail = node 45 | 46 | l1Tail = l1Tail?.next 47 | l2Tail = l2Tail?.next 48 | } 49 | 50 | if carry != 0 { 51 | tail?.next = ListNode(carry) 52 | } 53 | 54 | return head; 55 | } 56 | } 57 | 58 | let n1 = ListNode(2) 59 | let n2 = ListNode(4) 60 | n1.next = n2 61 | let n3 = ListNode(9) 62 | n2.next = n3 63 | 64 | let n4 = ListNode(5) 65 | let n5 = ListNode(6) 66 | n4.next = n5 67 | let n6 = ListNode(4) 68 | n5.next = n6 69 | 70 | let solution = Solution(); 71 | let nr = solution.addTwoNumbers(n1, n4) 72 | 73 | -------------------------------------------------------------------------------- /solutions/2_Add_Two_Numbers.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/2_Add_Two_Numbers.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/2_Add_Two_Numbers.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/2_Add_Two_Numbers.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/2_Add_Two_Numbers.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /solutions/30_Substring_with_Concatenation_of_All_Words.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #30 Substring with Concatenation of All Words 2 | // 呼…… 这是我写过代码最长的一题吧!但并不难,只是较为繁琐。 3 | // 首先把原串按单词长度划成数个子串。因为答案可能从原串的任意地方开始,所以每次循环从第 0...wordLength - 1 个字母开始,就能覆盖到所有情况。每个子串匹配到的单词存到 matchedWords 里。 4 | // 剩下的问题就是判断何时连续出现所有单词了…… 下面用到的方法虽然写起来很繁琐,但效率是 O(n) 的,就是一个窗口逐渐右移,两个指针分别指向两头。窗口长度不够时,右指针往右挪;遇到重复元素,左指针往右到重复元素的右边;遇到 nil,窗口跳到它的右边继续。 5 | // 最后用时 718 ms,轻松 beats 100% ~ 看一个题解 https://soulmachine.gitbooks.io/algorithm-essentials/content/java/simulation/substring-with-concatenation-of-all-words.html ,java 似乎不用这个窗口方法也能过,但翻译成 swift(下面的 findSubstring2)就会超时 :( 6 | // 时间复杂度:O(nm) 空间复杂度:O(n) 7 | 8 | class Solution { 9 | func findSubstring(_ s: String, _ words: [String]) -> [Int] { 10 | let wordLength = words[0].characters.count 11 | let sChars = [Character](s.characters) 12 | 13 | var result = [Int]() 14 | for startIndex in 0...wordLength - 1 { 15 | var targetWordDict = [String:Int]() 16 | for word in words { 17 | targetWordDict[word] = targetWordDict[word] == nil ? 1 : targetWordDict[word]! + 1 18 | } 19 | 20 | var matchedWords = [String?]() 21 | for i in stride(from: startIndex, through: sChars.count - wordLength, by: wordLength) { 22 | let word = String(sChars[i ..< i + wordLength]) 23 | sChars.count - wordLength 24 | matchedWords.append(targetWordDict[word] == nil ? nil : word) 25 | } 26 | 27 | var leftPointer = 0, rightPointer = 0, currentWordCount = 0 28 | var wordDict = targetWordDict 29 | while leftPointer < matchedWords.count && rightPointer < matchedWords.count { 30 | guard let word = matchedWords[rightPointer] else { 31 | rightPointer += 1 // jump over nil 32 | leftPointer = rightPointer 33 | 34 | wordDict = targetWordDict 35 | currentWordCount = 0 36 | continue 37 | } 38 | 39 | if wordDict[word]! == 0 { 40 | // already has word 41 | while leftPointer < rightPointer { 42 | let wordToRemove = matchedWords[leftPointer]! 43 | leftPointer += 1 44 | if wordToRemove == word { 45 | break 46 | } else { 47 | currentWordCount -= 1 48 | wordDict[wordToRemove] = wordDict[wordToRemove]! + 1 49 | } 50 | } 51 | } else { 52 | // doesn't have word 53 | wordDict[word] = wordDict[word]! - 1 54 | currentWordCount += 1 55 | } 56 | rightPointer += 1 57 | 58 | if currentWordCount == words.count { 59 | result.append(startIndex + leftPointer * wordLength) 60 | 61 | let wordToRemove = matchedWords[leftPointer]! 62 | wordDict[wordToRemove] = wordDict[wordToRemove]! + 1 63 | leftPointer += 1 64 | currentWordCount -= 1 65 | } 66 | } 67 | } 68 | 69 | return result 70 | } 71 | 72 | func findSubstring2(_ s: String, _ words: [String]) -> [Int] { 73 | let wordLength = words[0].characters.count 74 | let sChars = [Character](s.characters) 75 | 76 | if sChars.count < wordLength * words.count { 77 | return [] 78 | } 79 | 80 | var result = [Int]() 81 | 82 | var targetWordDict = [String:Int]() 83 | for word in words { 84 | targetWordDict[word] = targetWordDict[word] == nil ? 1 : targetWordDict[word]! + 1 85 | } 86 | for startIndex in 0...sChars.count - wordLength * words.count { 87 | var wordDict = targetWordDict 88 | 89 | for i in stride(from: startIndex, to: startIndex + wordLength * words.count, by: wordLength) { 90 | let word = String(sChars[i ..< i + wordLength]) 91 | if wordDict[word] ?? 0 <= 0 { 92 | break 93 | } else { 94 | wordDict[word] = wordDict[word]! - 1 95 | } 96 | } 97 | 98 | var isValid = true 99 | for value in wordDict.values { 100 | if value != 0 { 101 | isValid = false 102 | break 103 | } 104 | } 105 | 106 | if isValid { 107 | result.append(startIndex) 108 | } 109 | } 110 | 111 | return result 112 | } 113 | } 114 | 115 | Solution().findSubstring("a", ["a","a"]) 116 | -------------------------------------------------------------------------------- /solutions/30_Substring_with_Concatenation_of_All_Words.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/30_Substring_with_Concatenation_of_All_Words.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/30_Substring_with_Concatenation_of_All_Words.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/30_Substring_with_Concatenation_of_All_Words.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/30_Substring_with_Concatenation_of_All_Words.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /solutions/31_Next_Permutation.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #31 Next Permutation https://leetcode.com/problems/next-permutation/ 2 | // 代码写起来很简单,数学推导稍微多一些。方法如下: 3 | // 从右往左找第一个比右边小的数字(如果找不到,逆转整个数组即可),其 index 为 leftNumIndex。再找它右边比它大的数字(一定存在)里最小的,由于右边是降序,从右往左找的第一个即是,index 为 rightNumIndex。swap 两个 index 的 num。 4 | // leftNumIndex 左边是不变的,下面看右边。右边本来是降序,能保证 swap 过后也是(不严格的)降序。换成升序,只需逆转这部分。 5 | // 时间复杂度:O(n) 空间复杂度:O(1) 6 | 7 | class Solution { 8 | func nextPermutation(_ nums: inout [Int]) { 9 | var leftNumIndex = -1 10 | for (index, num) in nums.enumerated().reversed() { 11 | if index != nums.count - 1 && num < nums[index + 1] { 12 | leftNumIndex = index 13 | break 14 | } 15 | } 16 | 17 | if leftNumIndex == -1 { 18 | reverse(&nums, fromIndex: 0) 19 | return 20 | } 21 | 22 | var rightNumIndex = -1 23 | for (index, num) in nums.enumerated().reversed() { 24 | if num > nums[leftNumIndex] { 25 | rightNumIndex = index 26 | break 27 | } 28 | } 29 | 30 | swap(&nums[leftNumIndex], &nums[rightNumIndex]) 31 | reverse(&nums, fromIndex: leftNumIndex + 1) 32 | } 33 | 34 | func reverse(_ nums: inout [Int], fromIndex: Int) { 35 | var leftIndex = fromIndex, rightIndex = nums.count - 1 36 | while leftIndex < rightIndex { 37 | swap(&nums[leftIndex], &nums[rightIndex]) 38 | leftIndex += 1 39 | rightIndex -= 1 40 | } 41 | } 42 | } 43 | 44 | var nums = [3, 1, 2] 45 | Solution().nextPermutation(&nums) 46 | nums -------------------------------------------------------------------------------- /solutions/31_Next_Permutation.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/31_Next_Permutation.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/31_Next_Permutation.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/31_Next_Permutation.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/32_Longest_Valid_Parentheses.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #32 Longest Valid Parentheses https://leetcode.com/problems/longest-valid-parentheses/ 2 | // 我想到的这个做法是需要扫两遍的,先从头到尾记录深度,如果深度到 0 就记录当前长度,< 0 就把起始位置跳到当前位置后面。扫到最后,如果深度还 > 0,再从后往前倒着扫一遍。看了下题解,代码写法几乎除了命名之外完全一致 >< 3 | // 还有另一个做法是只需要扫一遍的,就是需要把所有左括号的位置记到一个栈里。每次遇到右括号的时候出栈,如果栈空就记从起始位置的长度(例如 ()() 长度为4),不空就记从栈顶开始的长度(例如 ()((()) 记为4)。 4 | // 时间复杂度:O(n) 空间复杂度:O(1) 5 | 6 | class Solution { 7 | func longestValidParentheses(_ s: String) -> Int { 8 | let sChars = [Character](s.characters) 9 | guard sChars.count >= 2 else { 10 | return 0 11 | } 12 | 13 | var maxLength = 0, startIndex = 0, depth = 0 14 | for (index, char) in sChars.enumerated() { 15 | if char == "(" { 16 | depth += 1 17 | } else if char == ")" { 18 | depth -= 1 19 | } 20 | if depth < 0 { 21 | startIndex = index + 1 22 | depth = 0 23 | } else if depth == 0 { 24 | maxLength = max(maxLength, index - startIndex + 1) 25 | } 26 | } 27 | 28 | if depth <= 0 { 29 | return maxLength 30 | } 31 | 32 | depth = 0 33 | startIndex = sChars.count - 1 34 | for (index, char) in sChars.enumerated().reversed() { 35 | if char == ")" { 36 | depth += 1 37 | } else if char == "(" { 38 | depth -= 1 39 | } 40 | if depth < 0 { 41 | startIndex = index - 1 42 | depth = 0 43 | } else if depth == 0 { 44 | maxLength = max(maxLength, startIndex - index + 1) 45 | } 46 | } 47 | 48 | return maxLength 49 | } 50 | } 51 | 52 | Solution().longestValidParentheses(")(((((()())()()))()(()))") -------------------------------------------------------------------------------- /solutions/32_Longest_Valid_Parentheses.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/32_Longest_Valid_Parentheses.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/32_Longest_Valid_Parentheses.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/32_Longest_Valid_Parentheses.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/336_Palindrome_Pair.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #336 Palindrome Pair https://leetcode.com/problems/palindrome-pairs/?tab=Description 2 | // 这个题我并没有通过,现在还是超时状态。但我不打算继续做了。从理论分析,我现在的解法跟 Solution 里的并无区别,过不了想来就是 swift 的锅…… 比如 reverse 字符串…… 我懒得去为这种语言单独优化细节了。 3 | // 顺便说,我觉得 case 里的 "" 真是毫无意义,这应该算是不好的 case。 4 | // 时间复杂度:O(n * m^2) 空间复杂度:O(n) 5 | 6 | class Solution { 7 | func palindromePairs(_ words: [String]) -> [[Int]] { 8 | var wordDict = [String : Int]() 9 | for (index, word) in words.enumerated() { 10 | wordDict[word] = index 11 | } 12 | 13 | var result = [[Int]]() 14 | for (wordIndex, word) in words.enumerated() { 15 | let chars = [Character](word.characters) 16 | for rightPartStartIndex in 0 ..< chars.count { 17 | if let oddResult = findpalindromePair(chars: chars, leftStartIndex: rightPartStartIndex, rightStartIndex: rightPartStartIndex, wordDict: wordDict, wordIndex: wordIndex) { 18 | result.append(contentsOf: oddResult) 19 | } 20 | if let evenResult = findpalindromePair(chars: chars, leftStartIndex: rightPartStartIndex - 1, rightStartIndex: rightPartStartIndex, wordDict: wordDict, wordIndex: wordIndex) { 21 | result.append(contentsOf: evenResult) 22 | } 23 | } 24 | } 25 | return result 26 | } 27 | 28 | func findpalindromePair(chars:[Character], leftStartIndex : Int, rightStartIndex : Int, wordDict:[String : Int], wordIndex : Int) -> [[Int]]? { 29 | // is valid part 30 | var leftIndex = leftStartIndex, rightIndex = rightStartIndex 31 | while leftIndex >= 0 && rightIndex < chars.count && chars[leftIndex] == chars[rightIndex] { 32 | leftIndex -= 1 33 | rightIndex += 1 34 | } 35 | if leftIndex >= 0 && rightIndex < chars.count { 36 | return nil 37 | } 38 | 39 | // create pair 40 | var pair = "", direction = 0 // left -> 1 right -> -1 both -> 0 41 | if rightIndex < chars.count { 42 | direction = -1 43 | while rightIndex < chars.count { 44 | pair.insert(chars[rightIndex], at: pair.startIndex) 45 | rightIndex += 1 46 | } 47 | } else if leftIndex >= 0 { 48 | direction = 1 49 | while leftIndex >= 0 { 50 | pair.insert(chars[leftIndex], at: pair.endIndex) 51 | leftIndex -= 1 52 | } 53 | } else { // pair = "" 54 | direction = 0 55 | } 56 | 57 | if let pairIndex = wordDict[pair] { 58 | if pairIndex != wordIndex { 59 | switch direction { 60 | case 1: 61 | return [[wordIndex, pairIndex]] 62 | 63 | case -1: 64 | return [[pairIndex, wordIndex]] 65 | 66 | case 0: 67 | return [[wordIndex, pairIndex], [pairIndex, wordIndex]] 68 | 69 | default: 70 | return nil 71 | } 72 | } 73 | } 74 | return nil 75 | } 76 | } 77 | 78 | Solution().palindromePairs(["a",""]) -------------------------------------------------------------------------------- /solutions/336_Palindrome_Pair.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/336_Palindrome_Pair.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/336_Palindrome_Pair.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/336_Palindrome_Pair.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/33_Search_in_Rotated_Sorted_Array.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #33 Search in Rotated Sorted Array https://leetcode.com/problems/search-in-rotated-sorted-array/ 2 | // 比较简单的二分查找,就是在判界限的时候分几种情况讨论。跟 nums[0] 比可知要找的数应该是在上升半区还是下降半区,这样。然后就分情况讨论吧…… 上面的代码是简化过的,下面是完整版的代码,更能看出分类的具体情况。 3 | // 时间复杂度:O(lgn) 空间复杂度:O(1) 4 | 5 | class Solution { 6 | func search(_ nums: [Int], _ target: Int) -> Int { 7 | guard nums.count > 0 else { 8 | return -1 9 | } 10 | var left = 0, right = nums.count - 1 11 | if target == nums[right] { 12 | return right 13 | } 14 | if target == nums[0] { 15 | return 0 16 | } else { 17 | // search in second half 18 | var i = (left + right) / 2 19 | while nums[i] != target { // target < nums[0] 20 | if target < nums[0] { 21 | if nums[i] > nums[0] || nums[i] < target { 22 | left = i 23 | } else { 24 | right = i 25 | } 26 | } else { 27 | if nums[i] > target || nums[i] < nums[0] { 28 | right = i 29 | } else { 30 | left = i 31 | } 32 | } 33 | 34 | if right - left <= 1 { 35 | break 36 | } 37 | i = (left + right) / 2 38 | } 39 | return nums[i] == target ? i : -1 40 | } 41 | } 42 | 43 | func search_full(_ nums: [Int], _ target: Int) -> Int { 44 | guard nums.count > 0 else { 45 | return -1 46 | } 47 | var left = 0, right = nums.count - 1 48 | if target == nums[right] { 49 | return right 50 | } 51 | if target == nums[0] { 52 | return 0 53 | } else if target < nums[0] { 54 | // search in second half 55 | var i = (left + right) / 2 56 | while nums[i] != target { 57 | if nums[i] > target { 58 | if nums[i] < nums[0] { 59 | right = i 60 | } else { 61 | left = i 62 | } 63 | } else { 64 | if nums[i] < nums[0] { 65 | left = i 66 | } else { 67 | right = i 68 | } 69 | } 70 | if right - left <= 1 { 71 | break 72 | } 73 | i = (left + right) / 2 74 | } 75 | return nums[i] == target ? i : -1 76 | } else { 77 | // search in first half 78 | var i = (left + right) / 2 79 | while nums[i] != target { 80 | if nums[i] > target { 81 | if nums[i] < nums[0] { 82 | left = i 83 | } else { 84 | right = i 85 | } 86 | } else { 87 | if nums[i] < nums[0] { 88 | right = i 89 | } else { 90 | left = i 91 | } 92 | } 93 | if right - left <= 1 { 94 | break 95 | } 96 | i = (left + right) / 2 97 | } 98 | return nums[i] == target ? i : -1 99 | } 100 | } 101 | } 102 | 103 | Solution().search([4,5,6,7,0,1,2], 1) -------------------------------------------------------------------------------- /solutions/33_Search_in_Rotated_Sorted_Array.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/34_Search_for_a_Range.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #34 Search for a Range https://leetcode.com/problems/search-for-a-range/ 2 | // 仍然是简单的二分查找,只是分别找左界和右界。代码行数略多…… 3 | // 时间复杂度:O(lgn) 空间复杂度:O(1) 4 | 5 | class Solution { 6 | func searchRange(_ nums: [Int], _ target: Int) -> [Int] { 7 | guard nums.count > 0 else { 8 | return [-1, -1] 9 | } 10 | 11 | // search for lower bound 12 | var lowerBound = -1 13 | if nums[0] == target { 14 | lowerBound = 0 15 | } else if nums.last == target && nums[nums.count - 2] < target { 16 | return [nums.count - 1, nums.count - 1] 17 | } else { 18 | var left = 0, right = nums.count - 1 19 | var index = (left + right) / 2 20 | 21 | while right - left > 1 && index >= 1 { 22 | if nums[index] == target && nums[index - 1] < target { 23 | lowerBound = index 24 | break 25 | } 26 | 27 | if nums[index] < target { 28 | left = index 29 | } else { 30 | right = index 31 | } 32 | 33 | index = (left + right) / 2 34 | } 35 | 36 | if lowerBound == -1 { 37 | return [-1, -1] 38 | } 39 | } 40 | 41 | // search for upper bound 42 | var upperBound = -1 43 | if nums.last == target { 44 | upperBound = nums.count - 1 45 | } else if nums[lowerBound + 1] > target { 46 | upperBound = lowerBound 47 | } else { 48 | var left = lowerBound, right = nums.count - 1 49 | var index = (left + right) / 2 50 | 51 | while right - left > 1 && index <= nums.count - 2 { 52 | if nums[index] == target && nums[index + 1] > target { 53 | upperBound = index 54 | break 55 | } 56 | 57 | if nums[index] > target { 58 | right = index 59 | } else { 60 | left = index 61 | } 62 | 63 | index = (left + right) / 2 64 | } 65 | } 66 | return [lowerBound, upperBound] 67 | } 68 | } 69 | 70 | Solution().searchRange([1, 4], 4) 71 | -------------------------------------------------------------------------------- /solutions/34_Search_for_a_Range.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/34_Search_for_a_Range.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/34_Search_for_a_Range.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/34_Search_for_a_Range.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/35_Search_Insert_Position.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #35 Search Insert Position https://leetcode.com/problems/search-insert-position/ 2 | // 插排最基本的一步,没什么好说的。 3 | // 时间复杂度:O(n) 空间复杂度:O(1) 4 | 5 | 6 | class Solution { 7 | func searchInsert(_ nums: [Int], _ target: Int) -> Int { 8 | for (index, num) in nums.enumerated() { 9 | if num >= target { 10 | return index 11 | } 12 | } 13 | return nums.count 14 | } 15 | } -------------------------------------------------------------------------------- /solutions/35_Search_Insert_Position.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/35_Search_Insert_Position.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/35_Search_Insert_Position.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/35_Search_Insert_Position.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/36_Valid_Sudoku.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #36 Valid Sudoku https://leetcode.com/problems/valid-sudoku/ 2 | // 简单模拟每一条规则,用一个 Set 判重即可。 3 | // 时间复杂度:O(n^2) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | func isValidSudoku(_ board: [[Character]]) -> Bool { 7 | guard board.count == 9 else { 8 | return false 9 | } 10 | 11 | // lines 12 | for line in board { 13 | if line.count != 9 { 14 | return false; 15 | } 16 | 17 | var numSet = Set() 18 | for char in line { 19 | if char == "." { 20 | continue 21 | } 22 | if numSet.contains(char) { 23 | return false 24 | } 25 | numSet.insert(char) 26 | } 27 | } 28 | 29 | // vertical 30 | for columnIndex in 0 ..< 9 { 31 | var numSet = Set() 32 | for rowIndex in 0 ..< 9 { 33 | let char = board[rowIndex][columnIndex] 34 | if char == "." { 35 | continue 36 | } 37 | if numSet.contains(char) { 38 | return false 39 | } 40 | numSet.insert(char) 41 | } 42 | } 43 | 44 | // grids 45 | for gridIndex in 0 ..< 9 { 46 | let startRow = (gridIndex / 3) * 3 47 | let startColumn = (gridIndex % 3) * 3 48 | 49 | var numSet = Set() 50 | for rowIndex in startRow...startRow + 2 { 51 | for columnIndex in startColumn...startColumn + 2 { 52 | let char = board[rowIndex][columnIndex] 53 | if char == "." { 54 | continue 55 | } 56 | if numSet.contains(char) { 57 | return false 58 | } 59 | numSet.insert(char) 60 | } 61 | } 62 | } 63 | 64 | return true 65 | } 66 | } -------------------------------------------------------------------------------- /solutions/36_Valid_Sudoku.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/36_Valid_Sudoku.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /solutions/37_Sudoku_Solver.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #37 Sudoku Solver https://leetcode.com/problems/sudoku-solver/ 2 | // 3 | 4 | class Solution { 5 | func solveSudoku(_ board: inout [[Character]]) { 6 | var possibleNums = [[[]]] 7 | } 8 | } -------------------------------------------------------------------------------- /solutions/37_Sudoku_Solver.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/37_Sudoku_Solver.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/37_Sudoku_Solver.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/37_Sudoku_Solver.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/385_Mini_Parser.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #385 Mini Parser https://leetcode.com/problems/mini-parser/?tab=Description 2 | // 这道题用栈很简单。左括号入栈、右括号出栈即可。第一个想到的其实是递归,但递归的方法由于 Swift 的字符串截取性能差,估计会比较慢。 3 | // 做的过程比较委屈,感觉就给的信心而言题意不是太明确。实际上有一个理解的关键是,出现一个数字的时候,不是把栈顶 setInteger 设一个数字,而是先 new 一个数字节点,再 add 给栈顶。提交之前先试一试以下两个 case:"[]" "[-1]" 保证你的理解正确。 4 | // 时间复杂度:O(n) 空间复杂度:O(n) 5 | 6 | 7 | // This is the interface that allows for creating nested lists. 8 | // You should not implement it, or speculate about its implementation 9 | class NestedInteger { 10 | // Return true if this NestedInteger holds a single integer, rather than a nested list. 11 | public func isInteger() -> Bool { 12 | return true 13 | } 14 | 15 | // Return the single integer that this NestedInteger holds, if it holds a single integer 16 | // The result is undefined if this NestedInteger holds a nested list 17 | public func getInteger() -> Int { 18 | return 0 19 | } 20 | 21 | // Set this NestedInteger to hold a single integer. 22 | public func setInteger(_ value: Int) {} 23 | 24 | // Set this NestedInteger to hold a nested list and adds a nested integer to it. 25 | public func add(_ elem: NestedInteger) {} 26 | 27 | // Return the nested list that this NestedInteger holds, if it holds a nested list 28 | // The result is undefined if this NestedInteger holds a single integer 29 | public func getList() -> [NestedInteger] {return []} 30 | } 31 | 32 | class Solution { 33 | func deserialize(_ s: String) -> NestedInteger { 34 | let chars = [Character](s.characters) 35 | var stack = [NestedInteger]() 36 | 37 | var sign = 1 38 | var num : Int? = nil 39 | 40 | for char in chars { 41 | switch char { 42 | case "[": 43 | let nestedInteger = NestedInteger() 44 | stack.last?.add(nestedInteger) 45 | stack.append(nestedInteger) 46 | 47 | case "-": 48 | sign = -1 49 | 50 | case ",", "]": 51 | if let numUnwrap = num { 52 | let nestedInteger = NestedInteger() 53 | nestedInteger.setInteger(numUnwrap) 54 | stack.last?.add(nestedInteger) 55 | 56 | sign = 1 57 | num = nil 58 | } 59 | if char == "]" { 60 | let last = stack.removeLast() 61 | if stack.count == 0 { 62 | return last 63 | } 64 | } 65 | 66 | case "0", "1", "2", "3", "4", "5", "6", "7", "8", "9": 67 | let digit = Int(String(char))! 68 | if num == nil { 69 | num = 0 70 | } 71 | num = num! * 10 + digit * sign 72 | 73 | default: break 74 | } 75 | } 76 | 77 | if let numUnwrap = num { 78 | let nestedInteger = stack.last! 79 | nestedInteger.setInteger(numUnwrap) 80 | return nestedInteger 81 | } 82 | 83 | return NestedInteger() 84 | } 85 | } 86 | 87 | Solution().deserialize("[]") -------------------------------------------------------------------------------- /solutions/385_Mini_Parser.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/3_Longest_Substring_Without_Repeating_Characters.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #3 Longest Substring Without Repeating Characters https://leetcode.com/problems/longest-substring-without-repeating-characters/ 2 | // 我用的方法是用一个 hash 记录每个字母出现的 index,然后把字符串扫一遍。不出现重复时就往 hash 表里填。出现重复时,从 hash 取出字母出现的 previousIndex ,把从当前串开头至 previousIndex 的字母都从 hash 中清掉。 3 | // 看到一个更好的方法,不需要存字母出现的 index,出现重复时直接从当前串开头至出现重复字母的位置清掉 hash 即可。这种情况下也不需要用 Dictionary 存 hash,只需用 Set 即可。 4 | // 本来 hash 需要的额外空间很小,但因为 swift 要遍历字符串中的字符必须把字符数组存出来一份。所以空间复杂度为 O(n)。 5 | // 时间复杂度:O(n) 空间复杂度:O(n) 6 | 7 | class Solution { 8 | func lengthOfLongestSubstring(_ s: String) -> Int { 9 | 10 | var letterAppearedDict = [Character:Int]() 11 | var maxLength = 0 12 | var currentLength = 0 13 | 14 | var chars = [Character](s.characters) 15 | 16 | for index in 0 ..< chars.count { 17 | let char = chars[index] 18 | 19 | if letterAppearedDict[char] == nil { 20 | letterAppearedDict[char] = index 21 | currentLength += 1 22 | } else { 23 | let previousIndex = letterAppearedDict[char]! 24 | 25 | for clearIndex in index - currentLength ..< previousIndex { 26 | letterAppearedDict[chars[clearIndex]] = nil 27 | } 28 | letterAppearedDict[char] = index 29 | currentLength = index - previousIndex 30 | } 31 | 32 | maxLength = max(maxLength, currentLength) 33 | } 34 | 35 | 36 | return maxLength 37 | } 38 | 39 | func lengthOfLongestSubstring2(_ s: String) -> Int { 40 | 41 | var maxLength = 0 42 | var currentLength = 0 43 | 44 | var chars = [Character](s.characters) 45 | 46 | guard chars.count > 1 else { 47 | return chars.count 48 | } 49 | 50 | for index in 0 ..< chars.count - 1 { 51 | var letterAppearedSet = Set() 52 | var length = 1 53 | while length <= chars.count - index { 54 | let char = chars[index + length - 1] 55 | if letterAppearedSet.contains(char) { // 已经出现重复,后面不可能再有解了 56 | break 57 | } 58 | letterAppearedSet.insert(char) 59 | 60 | maxLength = max(maxLength, length) 61 | length += 1 62 | } 63 | } 64 | 65 | return maxLength 66 | } 67 | } 68 | 69 | Solution().lengthOfLongestSubstring2("abcabcbb") 70 | Solution().lengthOfLongestSubstring("bbbbb") 71 | Solution().lengthOfLongestSubstring("pwwkew") 72 | Solution().lengthOfLongestSubstring("") 73 | -------------------------------------------------------------------------------- /solutions/3_Longest_Substring_Without_Repeating_Characters.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/3_Longest_Substring_Without_Repeating_Characters.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/3_Longest_Substring_Without_Repeating_Characters.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/3_Longest_Substring_Without_Repeating_Characters.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/415_Add_Strings.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #415 Add Strings https://leetcode.com/problems/add-strings/?tab=Description 2 | // 看这 swift 的类型转换恶心的。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | func addStrings(_ num1: String, _ num2: String) -> String { 7 | let chars1 = [Character](num1.characters) 8 | let chars2 = [Character](num2.characters) 9 | var index1 = chars1.count - 1, index2 = chars2.count - 1 10 | var carry = 0 11 | var result : String = "" 12 | 13 | while index1 >= 0 && index2 >= 0 { 14 | let digit = Int(String(chars1[index1]))! + Int(String(chars2[index2]))! + carry 15 | result.insert(String(digit % 10).characters.first!, at: result.startIndex) 16 | carry = digit / 10 17 | 18 | index1 -= 1 19 | index2 -= 1 20 | } 21 | 22 | while index1 >= 0 { 23 | let digit = (Int(String(chars1[index1])) ?? 0) + carry 24 | result.insert(String(digit % 10).characters.first!, at: result.startIndex) 25 | carry = digit / 10 26 | 27 | index1 -= 1 28 | } 29 | 30 | while index2 >= 0 { 31 | let digit = (Int(String(chars2[index2])) ?? 0) + carry 32 | result.insert(String(digit % 10).characters.first!, at: result.startIndex) 33 | carry = digit / 10 34 | 35 | index2 -= 1 36 | } 37 | 38 | if carry > 0 { 39 | result.insert(String(carry).characters.first!, at: result.startIndex) 40 | } 41 | 42 | return result 43 | } 44 | } 45 | 46 | Solution().addStrings("9", "0") -------------------------------------------------------------------------------- /solutions/415_Add_Strings.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/415_Add_Strings.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/415_Add_Strings.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/415_Add_Strings.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/4_Median_of_two_sorted_arrays.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #4 Median of Two Sorted Arrays https://leetcode.com/problems/median-of-two-sorted-arrays/ 2 | // 下面列出了两个解法,其中 Solution2 是自己想出来的,也过了全部测试数据,但方法非常不简洁。思路是从两边逼近中位数,取两个数列的中点,可证明总有一个不能满足第 k 大的条件。然后就调整这个数列。问题在于,有些情况可能会调整过头。另外,还有这个数列已经到头、调整不了的情况,此时就需要去调另一个数列。总的来说仍然是 log(m + n) 的,但代码非常长,原理也不够清晰。 3 | // Solution1 参考了别人的题解,每次两个数列各取 k/2 处,小者在这个位置之前全都截断。 4 | // 为啥 Solution1 就非常简洁呢?最主要的问题在于,Solution1 是从一侧逼近问题的,每次迭代都更靠近答案。Solution2 是从两侧往中间逼近,然而两个数列并没有二分查找那么好的特性,有可能两个指针都在答案的同侧,还要回头找。 5 | // 另外,Solution1 利用了一个技巧,保证每次迭代时 nums1 都更短,不然交换。可以避免很多对称的重复代码。 6 | // 在语言方面,可以看出 swift 里 if(...) {return ...} 这种基本都用 guard 代替。 7 | // 时间复杂度:log(m+n) 空间复杂度:O(m+n) 8 | 9 | 10 | class Solution { 11 | 12 | func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { 13 | if (nums1.count + nums2.count) % 2 == 0 { 14 | let lowerMedian = findKthInSortedArrays(k: (nums1.count + nums2.count) / 2, nums1: nums1, nums2: nums2) 15 | let higherMedian = findKthInSortedArrays(k: (nums1.count + nums2.count) / 2 + 1, nums1: nums1, nums2: nums2) 16 | return (Double(lowerMedian) + Double(higherMedian)) / 2; 17 | } else { 18 | return Double(findKthInSortedArrays(k: (nums1.count + nums2.count + 1) / 2, nums1: nums1, nums2: nums2)) 19 | } 20 | } 21 | 22 | func findKthInSortedArrays(k: Int, nums1: [Int], nums2: [Int]) -> Int { 23 | 24 | guard nums1.count <= nums2.count else { 25 | return findKthInSortedArrays(k: k, nums1: nums2, nums2: nums1) 26 | } 27 | 28 | guard nums1.count > 0 else { 29 | return nums2[k - 1] 30 | } 31 | 32 | guard k > 1 else { 33 | return min(nums1[0], nums2[0]) 34 | } 35 | 36 | let num1Index = min(k / 2 - 1, nums1.count - 1) 37 | let num2Index = min(k / 2 - 1, nums2.count - 1) 38 | 39 | if nums1[num1Index] < nums2[num2Index] { 40 | return findKthInSortedArrays(k: k - (num1Index + 1), nums1: Array(nums1[num1Index + 1 ..< nums1.count]), nums2: nums2) 41 | } else { 42 | return findKthInSortedArrays(k: k - (num2Index + 1), nums1: nums1, nums2: Array(nums2[num2Index + 1 ..< nums2.count])) 43 | } 44 | } 45 | } 46 | 47 | class Solution2 { 48 | func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { 49 | 50 | if nums1.count == 0 { 51 | return findMedianInSortedArray(nums2) 52 | } 53 | 54 | if nums2.count == 0 { 55 | return findMedianInSortedArray(nums1) 56 | } 57 | 58 | if (nums1.count + nums2.count) % 2 == 0 { 59 | let lowerMedian = findKthInSortedArrays(k: (nums1.count + nums2.count) / 2, nums1: nums1, range1: 0 ... nums1.count - 1, nums2: nums2, range2: 0 ... nums2.count - 1) 60 | let higherMedian = findKthInSortedArrays(k: (nums1.count + nums2.count) / 2 + 1, nums1: nums1, range1: 0 ... nums1.count - 1, nums2: nums2, range2: 0 ... nums2.count - 1) 61 | return (Double(lowerMedian) + Double(higherMedian)) / 2; 62 | } else { 63 | return Double(findKthInSortedArrays(k: (nums1.count + nums2.count + 1) / 2, nums1: nums1, range1: 0 ... nums1.count - 1, nums2: nums2, range2: 0 ... nums2.count - 1)) 64 | } 65 | } 66 | 67 | func findMedianInSortedArray(_ nums: [Int]) -> Double { 68 | if nums.count % 2 == 0 { 69 | let lowerMedian = nums[nums.count / 2 - 1] 70 | let higherMedian = nums[nums.count / 2] 71 | return (Double(lowerMedian) + Double(higherMedian)) / 2 72 | } else { 73 | return Double(nums[nums.count / 2]) 74 | } 75 | } 76 | 77 | func findKthInSortedArrays(k: Int, nums1: [Int], range1: CountableClosedRange, nums2: [Int], range2: CountableClosedRange) -> Int { 78 | 79 | 80 | 81 | let index1 = (range1.lowerBound + range1.upperBound) / 2 82 | let index2 = (range2.lowerBound + range2.upperBound) / 2 83 | 84 | let num1 = nums1[index1] 85 | let num2 = nums2[index2] 86 | 87 | if num1 < num2 { 88 | return findKthInSortedArrays(k: k, lowerNums: nums1, lowerRange: range1, higherNums: nums2, higherRange: range2) 89 | } else { 90 | return findKthInSortedArrays(k: k, lowerNums: nums2, lowerRange: range2, higherNums: nums1, higherRange: range1) 91 | } 92 | } 93 | 94 | func findKthInSortedArrays(k: Int, lowerNums: [Int], lowerRange: CountableClosedRange, higherNums: [Int], higherRange: CountableClosedRange) -> Int { 95 | let lowerIndex = (lowerRange.lowerBound + lowerRange.upperBound) / 2 96 | let higherIndex = (higherRange.lowerBound + higherRange.upperBound) / 2 97 | 98 | let lowerMaxSortedIndex = lowerIndex + higherIndex + 1 99 | let higherMinSortedIndex = lowerIndex + 1 + higherIndex + 1 100 | 101 | if lowerMaxSortedIndex == k && higherIndex == higherRange.lowerBound { 102 | return lowerNums[lowerIndex] 103 | } 104 | 105 | if higherMinSortedIndex == k && lowerIndex == lowerRange.upperBound { 106 | return higherNums[higherIndex] 107 | } 108 | 109 | 110 | 111 | if lowerMaxSortedIndex < k { 112 | if lowerIndex < lowerRange.upperBound { 113 | let nextRange = lowerIndex + 1...lowerRange.upperBound 114 | return findKthInSortedArrays(k: k, nums1: lowerNums, range1: nextRange, nums2: higherNums, range2: higherRange) 115 | } else { 116 | let nextRange = higherIndex + 1...higherRange.upperBound 117 | return findKthInSortedArrays(k: k, nums1: lowerNums, range1: lowerRange, nums2: higherNums, range2: nextRange) 118 | } 119 | } else { // must have num2MinSortedIndex > k 120 | if higherIndex > higherRange.lowerBound { 121 | let nextRange = higherRange.lowerBound...higherIndex - 1 122 | return findKthInSortedArrays(k: k, nums1: lowerNums, range1: lowerRange, nums2: higherNums, range2: nextRange) 123 | } else { 124 | let nextRange = lowerRange.lowerBound...lowerIndex - 1 125 | return findKthInSortedArrays(k: k, nums1: lowerNums, range1: nextRange, nums2: higherNums, range2: higherRange) 126 | } 127 | } 128 | } 129 | } 130 | 131 | Solution().findMedianSortedArrays([1,3], [2]) 132 | -------------------------------------------------------------------------------- /solutions/4_Median_of_two_sorted_arrays.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/4_Median_of_two_sorted_arrays.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/4_Median_of_two_sorted_arrays.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/4_Median_of_two_sorted_arrays.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/5_Longest_Palindromic_Substring.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #5 Longest palindromic Substring https://leetcode.com/problems/longest-palindromic-substring/ 2 | // 这个解法是 O(n^2) 的。DP,先搜长度为 1、为 2…… 至 n。之所以写法很不简洁,多出了许多临时变量,完全是 swift 的锅。谨记 swift 字符串的特性,由于每一位字符长度不一定相等,它是不能随机访问的。也就是说,如果不存临时变量,取某一位的字符、取字符串的长度、截取子串,全部都是 n 级别的…… 所以一再超时。 3 | // 最坑的是,我之前写作 isPalidromeMatrix[startIndex][endIndex] = ... 这样就会超时,而 4 | // if (...) {isPalidromeMatrix[startIndex][endIndex] = true} 这样就不会。只不过多赋值了一些 false…… 5 | // 而且把 if isPalidrome 改成 if isPalidromeMatrix[startIndex][endIndex] ,时间会长一倍。感觉数据量稍微一大,swift 性能问题真的挺严重。 6 | // 时间复杂度:O(n^2) 空间复杂度:O(n^2) 7 | // 这个题是有一个 O(n) 的算法的。首先有暴搜的思路,就是以任何一位为中心往外扩展。O(n) 的算法是在这个基础上,利用回文串的特性,存在一个子串那么中心点两侧对称,在此基础上再往外搜即可。具体可见:https://www.felix021.com/blog/read.php?2040 8 | 9 | class Solution { 10 | func longestPalindrome(_ s: String) -> String { 11 | 12 | let chars = [Character](s.characters) 13 | let length = chars.count 14 | guard length > 0 else { 15 | return "" 16 | } 17 | 18 | var isPalidromeMatrix = Array(repeating: Array(repeating: false, count : length), count : length) 19 | 20 | var maxLength = 0 21 | var maxStartIndex = 0 22 | 23 | for palidromeLength in 1 ... length { 24 | for startIndex in 0 ... length - palidromeLength { 25 | let endIndex = startIndex + palidromeLength - 1 26 | var isPalidrome = false 27 | 28 | if palidromeLength == 1 { 29 | isPalidrome = true 30 | } else if palidromeLength == 2 { 31 | isPalidrome = chars[startIndex] == chars[endIndex] 32 | } else { 33 | isPalidrome = chars[startIndex] == chars[endIndex] && isPalidromeMatrix[startIndex + 1][endIndex - 1] 34 | } 35 | 36 | if isPalidrome { 37 | isPalidromeMatrix[startIndex][endIndex] = true 38 | 39 | if palidromeLength > maxLength { 40 | maxStartIndex = startIndex 41 | maxLength = palidromeLength 42 | } 43 | } 44 | } 45 | } 46 | 47 | return String(chars[maxStartIndex...maxStartIndex + maxLength - 1]) 48 | } 49 | } 50 | 51 | Solution().longestPalindrome("000") 52 | -------------------------------------------------------------------------------- /solutions/5_Longest_Palindromic_Substring.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/5_Longest_Palindromic_Substring.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/5_Longest_Palindromic_Substring.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/5_Longest_Palindromic_Substring.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/68_Text_Justification.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #68 Text Justification https://leetcode.com/problems/text-justification/?tab=Description 2 | // 这道题写起来真是太长了,太麻烦了…… >w< 再重复一遍,太麻烦了!还好不涉及什么复杂算法,就是一个 buffer,满了之后往结果里吐就行了。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | 7 | func fullJustify(_ words: [String], _ maxWidth: Int) -> [String] { 8 | 9 | var result = [String]() 10 | var buffer = [String]() 11 | var bufferLength = 0 12 | var wordIndex = 0 13 | while wordIndex < words.count { 14 | let word = words[wordIndex] 15 | let wordLength = word.characters.count 16 | 17 | if bufferLength + wordLength + 1 < maxWidth { 18 | bufferLength += wordLength + 1 19 | buffer.append(word) 20 | wordIndex += 1 21 | 22 | } else if bufferLength + wordLength <= maxWidth { 23 | buffer.append(word) 24 | 25 | if wordIndex == words.count - 1 { 26 | break // last line 27 | } else { 28 | result.append(lineFromBuffer(buffer, maxWidth:maxWidth)) 29 | } 30 | 31 | buffer = [] 32 | bufferLength = 0 33 | wordIndex += 1 34 | 35 | } else { 36 | result.append(lineFromBuffer(buffer, maxWidth:maxWidth)) 37 | 38 | buffer = [] 39 | bufferLength = 0 40 | } 41 | } 42 | if buffer.count > 0 { 43 | result.append(lastLineFromBuffer(buffer, maxWidth:maxWidth)) 44 | } 45 | return result 46 | } 47 | 48 | func lineFromBuffer(_ buffer:[String], maxWidth:Int) -> String { 49 | guard buffer.count > 0 else { 50 | return "" 51 | } 52 | guard buffer.count > 1 else { 53 | var result = buffer[0] 54 | if result.characters.count < maxWidth { 55 | for _ in (result.characters.count + 1)...maxWidth { 56 | result.append(" ") 57 | } 58 | } 59 | return result 60 | } 61 | 62 | var wordsTotalLength = 0 63 | for word in buffer { 64 | wordsTotalLength += word.characters.count 65 | } 66 | let totalWhiteSpace = maxWidth - wordsTotalLength 67 | let whitespacesForEachWord = totalWhiteSpace / (buffer.count - 1) 68 | var redundantWhitespaces = totalWhiteSpace % (buffer.count - 1) 69 | 70 | var result = "" 71 | for (index, word) in buffer.enumerated() { 72 | result.append(word) 73 | if index == buffer.count - 1 { 74 | break // last 75 | } 76 | for _ in 1...whitespacesForEachWord { 77 | result.append(" ") 78 | } 79 | if redundantWhitespaces > 0 { 80 | result.append(" ") 81 | redundantWhitespaces -= 1 82 | } 83 | } 84 | 85 | return result 86 | } 87 | 88 | func lastLineFromBuffer(_ buffer:[String], maxWidth:Int) -> String { 89 | var result = "" 90 | for (index, word) in buffer.enumerated() { 91 | result.append(word) 92 | if index < buffer.count - 1 { 93 | result.append(" ") 94 | } 95 | } 96 | let trailingWhiteSpaces = maxWidth - result.characters.count 97 | if trailingWhiteSpaces > 0 { 98 | for _ in 1...trailingWhiteSpaces { 99 | result.append(" ") 100 | } 101 | } 102 | return result 103 | } 104 | } 105 | 106 | Solution().fullJustify(["",""], 0) -------------------------------------------------------------------------------- /solutions/68_Text_Justification.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/68_Text_Justification.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/68_Text_Justification.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/68_Text_Justification.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/6_ZigZag_conversion.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #6 ZigZag Conversion https://leetcode.com/problems/zigzag-conversion/ 2 | // 非常简单的题,唯一的难点就是题目本身描述得不太清楚了。需要自己考虑 row = 1、2 的边界情况。 3 | // swift 有个 stride 函数用来处理 for step 的情况。 4 | // 时间复杂度:O(n) 空间复杂度:O(n) 5 | 6 | class Solution { 7 | func convert(_ s: String, _ numRows: Int) -> String { 8 | guard numRows >= 2 else { 9 | return s 10 | } 11 | 12 | let chars = [Character](s.characters) 13 | 14 | let loop = numRows + (numRows - 2) 15 | var result = "" 16 | for rowIndex in 0 ..< numRows { 17 | var row = "" 18 | for num in stride(from:rowIndex, to:chars.count, by: loop) { 19 | row.append(chars[num]) 20 | 21 | if rowIndex > 0 && rowIndex < numRows - 1 { // not first row, not last row 22 | let next = num + (numRows - rowIndex - 1) * 2 23 | 24 | if next < chars.count { 25 | row.append(chars[next]) 26 | } 27 | } 28 | } 29 | 30 | result.append(row) 31 | } 32 | 33 | return result 34 | } 35 | } 36 | 37 | Solution().convert("PAYPALISHIRING", 3) 38 | -------------------------------------------------------------------------------- /solutions/6_ZigZag_conversion.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/6_ZigZag_conversion.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/6_ZigZag_conversion.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/6_ZigZag_conversion.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/7_Reverse_Integer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #7 Reverse Integer https://leetcode.com/problems/reverse-integer/ 2 | // 这题本身很简单,但感觉是道不错的面试题。可以测试面试者是否考虑各种边界情况,对溢出有没有概念。 3 | // 测试用例对 swift 给的不对,只能用 Int32.max。我是把负数统一归成正数来计算,这样判断溢出的语句可以简单点。 4 | // 时间复杂度:O(lgn) 空间复杂度:O(1) 5 | 6 | class Solution { 7 | func reverse(_ x: Int) -> Int { 8 | var isBelowZero = 1 9 | var num = x 10 | if x < 0 { 11 | isBelowZero = -1 12 | num = -x 13 | } 14 | 15 | var result = 0 16 | while num > 0 { 17 | if result > (Int(Int32.max) - num % 10) / 10 { 18 | return 0 19 | } 20 | result = result * 10 + num % 10 21 | num = num / 10 22 | } 23 | 24 | return result * isBelowZero 25 | } 26 | } 27 | 28 | Solution().reverse(1534236469) 29 | -------------------------------------------------------------------------------- /solutions/7_Reverse_Integer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/7_Reverse_Integer.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/7_Reverse_Integer.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/7_Reverse_Integer.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/8_String_to_Integer.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #8 String to Integer https://leetcode.com/problems/string-to-integer-atoi/ 2 | // 这道题与其说是写代码不如说是写 case…… 一堆 case,真是一点懒都不能偷呀。 3 | // 时间复杂度:O(n) 空间复杂度:O(n) 4 | 5 | class Solution { 6 | func myAtoi(_ str: String) -> Int { 7 | let chars = [Character](str.characters) 8 | 9 | var result = 0 10 | var sign = 0 11 | var isPrefix = true 12 | for char in chars { 13 | if (char == " " || char == " ") && isPrefix { 14 | continue 15 | } 16 | 17 | isPrefix = false 18 | 19 | if char == "+" || char == "-" { 20 | if sign != 0 { 21 | break 22 | } 23 | sign = char == "+" ? 1 : -1 24 | continue 25 | } 26 | 27 | if char >= "0" && char <= "9" { 28 | let charValue = Int(String(char))! 29 | 30 | if sign >= 0 && result > (Int(Int32.max) - charValue) / 10 { 31 | result = Int(Int32.max) 32 | break 33 | } 34 | 35 | if sign == -1 && result > (-Int(Int32.min) - charValue) / 10 { 36 | result = -Int(Int32.min) 37 | break 38 | } 39 | 40 | result = result * 10 + charValue 41 | 42 | } else { 43 | break 44 | } 45 | } 46 | 47 | if sign == 0 { 48 | sign = 1 49 | } 50 | return result * sign 51 | } 52 | } 53 | 54 | Solution().myAtoi("9223372036854775809") 55 | -------------------------------------------------------------------------------- /solutions/8_String_to_Integer.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/8_String_to_Integer.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/8_String_to_Integer.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/8_String_to_Integer.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/9_Palindrome_Number.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | // #9 Palindrome Number https://leetcode.com/problems/palindrome-number/ 2 | // 很简单的题,没给出的条件是负数不算回文数。有个 case 1000021 一开始做错了。另外一开始写了个递归,后来发现没必要…… 3 | // 时间复杂度:O(n) 空间复杂度:O(1) 4 | 5 | class Solution { 6 | func isPalindrome(_ x: Int) -> Bool { 7 | guard x >= 0 else { 8 | return false 9 | } 10 | 11 | var divider = 1 12 | while divider * 10 <= x { 13 | divider *= 10 14 | } 15 | 16 | var target = x 17 | while divider >= 10 { 18 | if target / divider != target % 10 { 19 | return false 20 | } 21 | 22 | target = (target % divider) / 10 23 | divider = divider / 100 24 | } 25 | 26 | return true 27 | } 28 | } 29 | 30 | Solution().isPalindrome(11) 31 | -------------------------------------------------------------------------------- /solutions/9_Palindrome_Number.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /solutions/9_Palindrome_Number.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /solutions/9_Palindrome_Number.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DaiYue/HAMLeetcodeSwiftSolutions/dbe646626166692c555ac130108161e0433d3996/solutions/9_Palindrome_Number.playground/playground.xcworkspace/xcuserdata/daiyuesmacbook.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /solutions/9_Palindrome_Number.playground/timeline.xctimeline: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 9 | 10 | 15 | 16 | 17 | 18 | --------------------------------------------------------------------------------