├── 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 |
--------------------------------------------------------------------------------