├── .gitignore ├── 008_StringToInteger.swift ├── 151_ReverseWordsInString.swift ├── 202_HappyNumber.swift ├── 274_H-Index.swift ├── 80_RemoveDuplicatesFromSortedArray_II.swift ├── 880_DecodedStringAtIndex.swift ├── Array ├── 001_TwoSum.swift ├── 118_Pascal's_Triangle.swift ├── 11_ContainerWithMostWater.swift ├── 125_ValidPalindrome.swift ├── 15_ThreeSum.swift ├── 167_TwoSumII.swift ├── 209_MinimumSizeSubarraySum.swift ├── 215_FindKthLargestInAnArray.swift ├── 26_RemoveDuplicatesFromSortedArray.swift ├── 27_RemoveElement.swift ├── 283_MoveZeroes.swift ├── 345_ReverseVowelsOfAString.swift ├── 45_JumpGameII.swift ├── 498_Diagonal_Traverse.swift ├── 560_SubarraySumEqualsK.swift ├── 66_PlusOne.swift ├── 695_MaxAreaofIsland.swift ├── 724_FindPivotIndex.swift ├── 747_LargestNumberAtLeastTwiceofOthers.swift ├── 75_SortColors.swift ├── 88_MergeSortedArray.swift ├── README.md ├── anti_linear_graph.jpg └── linear_list_graph.jpg ├── BigONotes.md ├── BinarySearch ├── 33_ SearchinRotatedSortedArray.swift ├── 4_MedianofTwoSortedArrays.swift └── BinarySearch.swift ├── DP ├── 152_MaximumProductSubarray.swift ├── 221_MaximalSquare.swift ├── 53_MaximumSubarray.swift ├── 983_MinimumCostForTickets.swift └── README.md ├── LICENSE ├── LeetCodePlayground.playground ├── Pages │ ├── 024_SwapNodesInPairs.xcplaygroundpage │ │ └── Contents.swift │ ├── 1003_CheckIfWordIsValidAfterSubstitutions.xcplaygroundpage │ │ └── Contents.swift │ ├── 1014_BestSightseeingPair.xcplaygroundpage │ │ └── Contents.swift │ ├── 101_SymmetricTree.xcplaygroundpage │ │ └── Contents.swift │ ├── 1025_DivisorGame.xcplaygroundpage │ │ └── Contents.swift │ ├── 1028_RecoveraTreeFromPreorderTraversal.xcplaygroundpage │ │ └── Contents.swift │ ├── 102_BinaryTreeLevelOrderTraversal.xcplaygroundpage │ │ └── Contents.swift │ ├── 104_MaximumDepthofBinaryTree.xcplaygroundpage │ │ └── Contents.swift │ ├── 105_ConstructBinaryTreefromPreorderandInorderTraversal.xcplaygroundpage │ │ └── Contents.swift │ ├── 108_ConvertSortedArraytoBinarySearchTree.xcplaygroundpage │ │ └── Contents.swift │ ├── 10_RegularExpressionMatching.xcplaygroundpage │ │ └── Contents.swift │ ├── 112_PathSum.xcplaygroundpage │ │ └── Contents.swift │ ├── 118_Pascal'sTriangle.xcplaygroundpage │ │ └── Contents.swift │ ├── 11_ContainerWithMostWater.xcplaygroundpage │ │ └── Contents.swift │ ├── 120_Triangle.xcplaygroundpage │ │ └── Contents.swift │ ├── 121_BestTimetoBuyandSellStock.xcplaygroundpage │ │ └── Contents.swift │ ├── 122_BestTimetoBuyandSellStockII.xcplaygroundpage │ │ └── Contents.swift │ ├── 124_BinaryTreeMaximumPathSum.xcplaygroundpage │ │ └── Contents.swift │ ├── 125_ValidPalindrome.xcplaygroundpage │ │ └── Contents.swift │ ├── 126_WordLadderII.xcplaygroundpage │ │ └── Contents.swift │ ├── 128_LongestConsecutiveSequence.xcplaygroundpage │ │ └── Contents.swift │ ├── 1300_SumofMutatedArrayClosesttoTarget.xcplaygroundpage │ │ └── Contents.swift │ ├── 1371_FindtheLongestSubstringContainingVowelsinEvenCounts.xcplaygroundpage │ │ └── Contents.swift │ ├── 139_WordBreak.xcplaygroundpage │ │ └── Contents.swift │ ├── 1431_KidsWiththeGreatestNumberofCandies.xcplaygroundpage │ │ └── Contents.swift │ ├── 146_LRUCache.xcplaygroundpage │ │ └── Contents.swift │ ├── 14_LongestCommonPrefix.xcplaygroundpage │ │ └── Contents.swift │ ├── 150_EvaluateReversePolishNotation.xcplaygroundpage │ │ └── Contents.swift │ ├── 151_ReverseWordsInString.xcplaygroundpage │ │ └── Contents.swift │ ├── 152_MaximumProductSubarray.xcplaygroundpage │ │ └── Contents.swift │ ├── 155_MinStack.xcplaygroundpage │ │ └── Contents.swift │ ├── 15_ThreeSum.xcplaygroundpage │ │ └── Contents.swift │ ├── 167_TwoSumII.xcplaygroundpage │ │ └── Contents.swift │ ├── 16_3SumClosest.xcplaygroundpage │ │ └── Contents.swift │ ├── 1744_CanYouEatYourFavoriteCandyonYourFavoriteDay.xcplaygroundpage │ │ └── Contents.swift │ ├── 174_DungeonGame .xcplaygroundpage │ │ └── Contents.swift │ ├── 198_HouseRobber.xcplaygroundpage │ │ └── Contents.swift │ ├── 19_RemoveNthNodeFromEndOfList.xcplaygroundpage │ │ └── Contents.swift │ ├── 1_TwoSum.xcplaygroundpage │ │ └── Contents.swift │ ├── 202_HappyNumber.xcplaygroundpage │ │ └── Contents.swift │ ├── 203_RemoveLinkedListElements.xcplaygroundpage │ │ └── Contents.swift │ ├── 206_ReverseList.xcplaygroundpage │ │ └── Contents.swift │ ├── 209_MinimumSizeSubarraySum.xcplaygroundpage │ │ └── Contents.swift │ ├── 20_ValidParentheses.xcplaygroundpage │ │ └── Contents.swift │ ├── 210.xcplaygroundpage │ │ └── Contents.swift │ ├── 215_FindKthLargestInAnArray.xcplaygroundpage │ │ └── Contents.swift │ ├── 21_mergeTwoSortedLists.xcplaygroundpage │ │ └── Contents.swift │ ├── 221_MaximalSquare.xcplaygroundpage │ │ └── Contents.swift │ ├── 234_PalindromeLinkedList.xcplaygroundpage │ │ └── Contents.swift │ ├── 236_LowestCommonAncestorofaBinaryTree.xcplaygroundpage │ │ └── Contents.swift │ ├── 238_ProductofArrayExceptSelf.xcplaygroundpage │ │ └── Contents.swift │ ├── 25_ReverseNodesink-Group .xcplaygroundpage │ │ └── Contents.swift │ ├── 26_RemoveDuplicatesFromSortedArray.xcplaygroundpage │ │ └── Contents.swift │ ├── 274_H-Index.xcplaygroundpage │ │ └── Contents.swift │ ├── 27_RemoveElement.xcplaygroundpage │ │ └── Contents.swift │ ├── 283_MoveZeroes.xcplaygroundpage │ │ └── Contents.swift │ ├── 287_FindtheDuplicateNumber.xcplaygroundpage │ │ └── Contents.swift │ ├── 297_SerializeandDeserializeBinaryTree.xcplaygroundpage │ │ └── Contents.swift │ ├── 2_AddTwoNumbers.xcplaygroundpage │ │ └── Contents.swift │ ├── 309_BestTimetoBuyandSellStockwithCooldown.xcplaygroundpage │ │ └── Contents.swift │ ├── 312_BurstBalloons.xcplaygroundpage │ │ └── Contents.swift │ ├── 315_CountofSmallerNumbersAfterSelf.xcplaygroundpage │ │ └── Contents.swift │ ├── 328_OddEvenLinkedList.xcplaygroundpage │ │ └── Contents.swift │ ├── 33_SearchinRotatedSortedArray.xcplaygroundpage │ │ └── Contents.swift │ ├── 341_FlattenNestedListIterator.xcplaygroundpage │ │ └── Contents.swift │ ├── 343_IntegerBreak.xcplaygroundpage │ │ └── Contents.swift │ ├── 345_ReverseVowelsOfAString.xcplaygroundpage │ │ └── Contents.swift │ ├── 350_IntersectionofTwoArraysII .xcplaygroundpage │ │ └── Contents.swift │ ├── 35_SearchInsertPosition.xcplaygroundpage │ │ └── Contents.swift │ ├── 378_KthSmallestElementinaSortedMatrix.xcplaygroundpage │ │ └── Contents.swift │ ├── 392_IsSubsequence.xcplaygroundpage │ │ └── Contents.swift │ ├── 394_DecodeString.xcplaygroundpage │ │ └── Contents.swift │ ├── 3_LongestSubstringWithoutRepeatingCharacters.xcplaygroundpage │ │ └── Contents.swift │ ├── 41_FirstMissingPositive.xcplaygroundpage │ │ └── Contents.swift │ ├── 44_WildcardMatching.xcplaygroundpage │ │ └── Contents.swift │ ├── 45_JumpGameII.xcplaygroundpage │ │ └── Contents.swift │ ├── 498_DiagonalTraverse.xcplaygroundpage │ │ └── Contents.swift │ ├── 4_MedianofTwoSortedArrays.xcplaygroundpage │ │ └── Contents.swift │ ├── 50_Pow(x, n).xcplaygroundpage │ │ └── Contents.swift │ ├── 53_MaximumSubarray.xcplaygroundpage │ │ └── Contents.swift │ ├── 54_Spiral_Matrix.xcplaygroundpage │ │ └── Contents.swift │ ├── 560_SubarraySumEqualsK.xcplaygroundpage │ │ └── Contents.swift │ ├── 5_LongestPalindromicSubstring.xcplaygroundpage │ │ └── Contents.swift │ ├── 61_RotateList.xcplaygroundpage │ │ └── Contents.swift │ ├── 622_DesignCircularQueue.xcplaygroundpage │ │ └── Contents.swift │ ├── 63_UniquePathsII.xcplaygroundpage │ │ └── Contents.swift │ ├── 64_MinimumPathSum.xcplaygroundpage │ │ └── Contents.swift │ ├── 66_PlusOne.xcplaygroundpage │ │ └── Contents.swift │ ├── 67_AddBinary.xcplaygroundpage │ │ └── Contents.swift │ ├── 680_Valid_Palindrome_II.xcplaygroundpage │ │ └── Contents.swift │ ├── 695_MaxAreaofIsland.xcplaygroundpage │ │ └── Contents.swift │ ├── 707_DesignLinkedList.xcplaygroundpage │ │ └── Contents.swift │ ├── 70_ClimbingStairs.xcplaygroundpage │ │ └── Contents.swift │ ├── 718_MaximumLengthofRepeatedSubarray.xcplaygroundpage │ │ └── Contents.swift │ ├── 71_SimplifyPath.xcplaygroundpage │ │ └── Contents.swift │ ├── 724_FindPivotIndex.xcplaygroundpage │ │ └── Contents.swift │ ├── 739_DailyTemperatures.xcplaygroundpage │ │ └── Contents.swift │ ├── 747_LargestNumberAtLeastTwiceofOthers.xcplaygroundpage │ │ └── Contents.swift │ ├── 75_SortColors.xcplaygroundpage │ │ └── Contents.swift │ ├── 76_MinimumWindowSubstring.xcplaygroundpage │ │ └── Contents.swift │ ├── 785_IsGraphBipartite?.xcplaygroundpage │ │ └── Contents.swift │ ├── 80_RemoveDuplicatesFromSortedArray_II.xcplaygroundpage │ │ └── Contents.swift │ ├── 837_New21Game.xcplaygroundpage │ │ └── Contents.swift │ ├── 84_LargestRectangleinHistogram.xcplaygroundpage │ │ └── Contents.swift │ ├── 880_DecodedStringAtIndex.xcplaygroundpage │ │ └── Contents.swift │ ├── 88_MergeSortedArray.xcplaygroundpage │ │ └── Contents.swift │ ├── 8_StringToInteger.xcplaygroundpage │ │ └── Contents.swift │ ├── 912_SortAnArray.xcplaygroundpage │ │ └── Contents.swift │ ├── 93_RestoreIPAddresses.xcplaygroundpage │ │ └── Contents.swift │ ├── 95_UniqueBinarySearchTreesII.xcplaygroundpage │ │ └── Contents.swift │ ├── 96_UniqueBinarySearchTrees .xcplaygroundpage │ │ └── Contents.swift │ ├── 974_SubarraySumsDivisiblebyK .xcplaygroundpage │ │ └── Contents.swift │ ├── 983_MinimumCostForTickets.xcplaygroundpage │ │ └── Contents.swift │ ├── 98_ValidateBinarySearchTree.xcplaygroundpage │ │ └── Contents.swift │ ├── 990_SatisfiabilityofEqualityEquations.xcplaygroundpage │ │ └── Contents.swift │ ├── 9_PalindromeNumber.xcplaygroundpage │ │ └── Contents.swift │ ├── 其他 - 合并K个排序数组.xcplaygroundpage │ │ └── Contents.swift │ ├── 剑指 Offer - 面试题29. 顺时针打印矩阵.xcplaygroundpage │ │ └── Contents.swift │ ├── 剑指 Offer - 面试题46. 把数字翻译成字符串.xcplaygroundpage │ │ └── Contents.swift │ ├── 剑指 Offer - 面试题64. 求1+2+…+n.xcplaygroundpage │ │ └── Contents.swift │ ├── 剑指 Offer 09. 用两个栈实现队列.xcplaygroundpage │ │ └── Contents.swift │ ├── 剑指 Offer 11. 旋转数组的最小数字.xcplaygroundpage │ │ └── Contents.swift │ ├── 程序员面试金典 - 面试题 02.01. 移除重复节点.xcplaygroundpage │ │ └── Contents.swift │ ├── 程序员面试金典 - 面试题 10.01. 合并排序的数组.xcplaygroundpage │ │ └── Contents.swift │ ├── 程序员面试金典 - 面试题 16.11. 跳水板.xcplaygroundpage │ │ └── Contents.swift │ └── 程序员面试金典 - 面试题 17.13. 恢复空格.xcplaygroundpage │ │ └── Contents.swift └── contents.xcplayground ├── LinkedList ├── 024_SwapNodesInPairs.swift ├── 19_RemoveNthNodeFromEndOfList.swift ├── 203_RemoveLinkedListElements.swift ├── 21_MergeTwoSortedLists.swift ├── 234_PalindromeLinkedList.swift ├── 25_ReverseNodesink-Group.swift ├── 2_AddTwoNumbers.swift ├── 328_OddEvenLinkedList.swift ├── 61_RotateList.swift ├── 707_DesignLinkedList.swift └── README.md ├── Queue └── 622_DesignCircularQueue.swift ├── README.md ├── Sort ├── 912_SortAnArray.swift └── SortingAlgorithms.swift ├── Stack ├── .assets │ └── stack_intro.jpg ├── 1003_CheckIfWordIsValidAfterSubstitutions.swift ├── 150_EvaluateReversePolishNotation.swift ├── 155_MinStack.swift ├── 20_ValidParentheses.swift ├── 71_SimplifyPath.swift ├── 739_DailyTemperatures.swift └── README.md ├── String ├── 14_LongestCommonPrefix.swift ├── 3_LongestSubstringWithoutRepeatingCharacters.swift ├── 67_AddBinary.swift └── 93_RestoreIPAddresses.swift ├── THANKS.md └── Tree ├── 102_BinaryTreeLevelOrderTraversal.swift ├── 236_LowestCommonAncestorofaBinaryTree.swift └── 98_ValidateBinarySearchTree.swift /.gitignore: -------------------------------------------------------------------------------- 1 | ## Playgrounds 2 | timeline.xctimeline 3 | playground.xcworkspace 4 | LeetCodePlayground.playground/xcuserdata 5 | .DS_Store -------------------------------------------------------------------------------- /008_StringToInteger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 8. 字符串转换整数 (atoi) 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/string-to-integer-atoi/ 5 | // 标签:数学、字符串 6 | // 要点:遍历、去除(跳过)空白字符、判断正负、整数越界、判断字符是否为数字、每多一(个)位原结果值*10 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(1) 9 | 10 | private let intMax: Int = Int(Int32.max) 11 | private let intMin: Int = Int(Int32.min) 12 | class Solution { 13 | func myAtoi(_ str: String) -> Int { 14 | if str.isEmpty { return 0 } 15 | 16 | var res = 0 17 | var sign = 1 18 | var i = 0 19 | 20 | let chars = [Character](str) 21 | 22 | // 去除(跳过)空白字符 23 | while i < chars.count { 24 | guard chars[i] == " " else { break } 25 | i += 1 26 | } 27 | 28 | // 确保空字符串不越界 29 | guard i < chars.count else { return res } 30 | 31 | // 判断正负 32 | if chars[i] == "+" { 33 | i += 1 34 | } else if chars[i] == "-" { 35 | sign = -1 36 | i += 1 37 | } 38 | 39 | while i < chars.count { 40 | // 判断字符是否为数字 41 | guard chars[i] >= "0" && chars[i] <= "9" else { break } 42 | guard let digit = Int(String(chars[i])) else { break } 43 | 44 | // 每多一(个)位原结果值*10 45 | res = res * 10 + digit 46 | 47 | // 整数越界判断 48 | if sign == 1 && res >= intMax { 49 | return intMax 50 | } else if sign == -1 && res * -1 <= intMin { 51 | return intMin 52 | } 53 | 54 | i += 1 55 | } 56 | 57 | return res * sign 58 | } 59 | } 60 | 61 | // Tests 62 | let s = Solution() 63 | 64 | assert(s.myAtoi(" ") == 0) 65 | assert(s.myAtoi("42") == 42) 66 | assert(s.myAtoi("-42") == -42) 67 | assert(s.myAtoi("4193 with words") == 4193) 68 | assert(s.myAtoi("-91283472332") == -2147483648) 69 | assert(s.myAtoi("20000000000000000000") == 2147483647) -------------------------------------------------------------------------------- /151_ReverseWordsInString.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 151. 翻转字符串里的单词 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/reverse-words-in-a-string/ 5 | // 标签:字符串 6 | // 要点:以空字符进行拆分成数组->翻转->拼接 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(1) 9 | // 10 | 11 | import Foundation 12 | 13 | class Solution { 14 | func reverseWords(_ s: String) -> String { 15 | return s.split(separator: " ") 16 | .reversed() 17 | .joined(separator: " ") 18 | } 19 | } 20 | 21 | // Tests 22 | let s = Solution() 23 | assert(s.reverseWords("the sky is blue") == "blue is sky the") 24 | assert(s.reverseWords(" hello world! ") == "world! hello") 25 | assert(s.reverseWords("a good example") == "example good a") 26 | -------------------------------------------------------------------------------- /202_HappyNumber.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 202. 快乐数 3 | // 4 | // 编写一个算法来判断一个数 n 是不是快乐数。 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/happy-number/ 7 | // 标签:哈希表、快慢指针、数学 8 | // 要点:哈希表检测循环、数学规律 9 | // 时间复杂度:O(log(N)) 10 | // 空间复杂度: 11 | // * 哈希表:O(log(N)) 12 | // * 快慢指针: O(1) 13 | // * 数学: O(1) 14 | // 15 | 16 | class Solution { 17 | var numSet: Set = [] 18 | func isHappy(_ n: Int) -> Bool { 19 | var num = n 20 | var next = 0 21 | while num >= 1 { 22 | next += Int(pow(Double(num % 10), 2)) 23 | num /= 10 24 | } 25 | if next == 1 { return true } 26 | if numSet.contains(next) { return false } 27 | numSet.insert(next) 28 | return isHappy(next) 29 | } 30 | } 31 | 32 | class SolutionBy2Points { 33 | func isHappy(_ n: Int) -> Bool { 34 | var slow = n 35 | var fast = _getNext(n) 36 | while fast != 1 && slow != fast { 37 | slow = _getNext(slow) 38 | fast = _getNext(_getNext(fast)) 39 | } 40 | return fast == 1 41 | } 42 | 43 | private func _getNext(_ n: Int) -> Int { 44 | var num = n 45 | var next = 0 46 | while num >= 1 { 47 | next += Int(pow(Double(num % 10), 2)) 48 | num /= 10 49 | } 50 | return next 51 | } 52 | } 53 | 54 | class SolutionByMath { 55 | func isHappy(_ n: Int) -> Bool { 56 | var num = n 57 | var next = 0 58 | while num >= 1 { 59 | next += Int(pow(Double(num % 10), 2)) 60 | num /= 10 61 | } 62 | if next == 1 { return true } 63 | return next == 4 ? false : isHappy(next) 64 | } 65 | } 66 | 67 | // Tests 68 | 69 | let s = Solution() 70 | s.isHappy(19) == true 71 | 72 | let s2 = SolutionBy2Points() 73 | s2.isHappy(19) == true 74 | 75 | let s3 = SolutionByMath() 76 | s3.isHappy(19) == true -------------------------------------------------------------------------------- /274_H-Index.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 274. H指数 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/h-index/ 5 | // 标签:排序、哈希 6 | // 要点:逆序排序后遍历 7 | // 时间复杂度:O(nlog(n)) 8 | // 空间复杂度:O(1) 9 | 10 | import Foundation 11 | 12 | class Solution { 13 | func hIndex(_ citations: [Int]) -> Int { 14 | let sorted = citations.sorted(by: >) 15 | 16 | var i = 0 17 | while i < sorted.count && sorted[i] > i { 18 | i += 1 19 | } 20 | return i 21 | } 22 | } 23 | 24 | // Tests 25 | let s = Solution() 26 | assert(s.hIndex([3,0,6,1,5]) == 3) 27 | -------------------------------------------------------------------------------- /80_RemoveDuplicatesFromSortedArray_II.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 80. 删除排序数组中的重复项 II 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/ 5 | // 标签:数组、双指针 6 | // 要点:与 26 题类似,考察「数组变换」,使用双指针,一个遍历数组元素,一个在记录最后非重复项,移除后续(index+1)的原有项 7 | // 变化点在于双指针之间的「距离」,因此额外定义最多可出现次数,就可以直接拓展解决更多出现次数的类似问题 8 | // 时间复杂度:O(n) 9 | // 空间复杂度:O(1) 10 | // 11 | 12 | import Foundation 13 | 14 | private let duplicatesLimit = 2 15 | class Solution { 16 | func removeDuplicates(_ nums: inout [Int]) -> Int { 17 | if nums.count <= duplicatesLimit { return nums.count } 18 | 19 | var index = duplicatesLimit - 1 20 | for i in duplicatesLimit ..< nums.count { 21 | if nums[i] != nums[index - 1] { 22 | index += 1 23 | nums[index] = nums[i] 24 | } 25 | } 26 | 27 | nums.removeSubrange((index + 1 ) ..< nums.count) 28 | 29 | return nums.count 30 | } 31 | } 32 | 33 | // Tests 34 | let s = Solution() 35 | var input = [1,1,1,2,2,3] 36 | s.removeDuplicates(&input) == 6 37 | input == [1,1,2,2,3] 38 | -------------------------------------------------------------------------------- /880_DecodedStringAtIndex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 880. 索引处的解码字符串 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/decoded-string-at-index/ 5 | // 标签:字符串、余数 6 | // 要点:TBD 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(1) 9 | // 10 | 11 | import Foundation 12 | 13 | class Solution { 14 | func decodeAtIndex(_ S: String, _ K: Int) -> String { 15 | var size = 0 16 | 17 | for char in S { 18 | if char.isNumber { 19 | guard let digit = Int(String(char)) else { fatalError() } 20 | size *= digit 21 | } else if char.isLetter { 22 | size += 1 23 | } else { 24 | return "" 25 | } 26 | } 27 | 28 | var magicK = K 29 | for char in S.reversed() { 30 | magicK %= size 31 | if magicK == 0 && char.isLetter { 32 | return String(char) 33 | } 34 | if char.isNumber { 35 | guard let digit = Int(String(char)) else { fatalError() } 36 | size /= digit 37 | } else { 38 | size -= 1 39 | } 40 | } 41 | 42 | return "" 43 | } 44 | } 45 | 46 | // Tests 47 | let s = Solution() 48 | assert(s.decodeAtIndex("leet2code3", 10) == "o") 49 | assert(s.decodeAtIndex("ha22", 5) == "h") 50 | assert(s.decodeAtIndex("a2345678999999999999999", 1) == "a") -------------------------------------------------------------------------------- /Array/001_TwoSum.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 1.两数之和 4 | // 5 | // 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 6 | // 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/two-sum/ 9 | // 标签:数组、哈希表 10 | // 要点:顺序遍历目标数组,利用哈希表(Dictionary)查找元素时间复杂度O(1)的特性, 11 | // 以『元素值』为Key,『元素索引』为Value暂存,暂存字典中若存在target - num的键值对,即命中返回 12 | // 时间复杂度:O(n) 13 | // 空间复杂度:O(n) 14 | // 15 | 16 | import Foundation 17 | 18 | class Solution { 19 | typealias Index = Int 20 | func twoSum(_ nums: [Int], _ target: Int) -> [Int] { 21 | // 利用哈希表(Dictionary)查找元素时间复杂度O(1)的特性 22 | var indexesDictionary = [Int: Index]() 23 | 24 | for (index, num) in nums.enumerated() { 25 | // 暂存字典中若存在target - num的键值对,即命中返回 26 | if let pairIndex = indexesDictionary[target - num] { 27 | return [pairIndex, index] 28 | } 29 | // 以『元素值』为Key,『元素索引』为Value暂存 30 | indexesDictionary[num] = index 31 | } 32 | 33 | return [] 34 | } 35 | } 36 | 37 | // Tests 38 | let s = Solution() 39 | assert(s.twoSum([2,7,11,15], 9) == [0, 1]) 40 | -------------------------------------------------------------------------------- /Array/118_Pascal's_Triangle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 118. 杨辉三角 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/pascals-triangle/ 5 | // 标签:数组 6 | // 要点:根据杨辉三角规律迭代生成 7 | // 时间复杂度:O(n^2) 8 | // 空间复杂度:O(n^2) 9 | 10 | import Foundation 11 | 12 | class Solution { 13 | func generate(_ numRows: Int) -> [[Int]] { 14 | guard numRows > 0 else { return [] } 15 | 16 | var triangle = [[Int]]() 17 | 18 | triangle.append([1]) // 首行始终为 [1] 19 | 20 | for rowIndex in 1.. Int { 18 | var left = 0, right = height.count - 1, res = 0 19 | while left < right { 20 | let heightLeft = height[left], heightRight = height[right] 21 | res = max(res, (right - left) * min(heightLeft, heightRight)) 22 | heightLeft < heightRight ? (left += 1) : (right -= 1) 23 | } 24 | return res 25 | } 26 | } 27 | 28 | // Tests 29 | let s = Solution() 30 | s.maxArea([1,8,6,2,5,4,8,3,7]) == 49 31 | -------------------------------------------------------------------------------- /Array/125_ValidPalindrome.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 125. 验证回文串 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/valid-palindrome/ 5 | // 标签:数组、双指针、对撞指针 6 | // 要点:指针碰撞,由于数组有序,采用一头一尾双指针,相向遍历数组,跳过非比较字符 7 | // 若相等则继续,不相等则返回 false,直到指针碰撞(l Bool { 16 | let chars = Array(s.lowercased()) 17 | var l = 0, r = chars.count - 1 18 | 19 | while l < r { 20 | while !chars[l].isLetter && !chars[l].isNumber && l < r { 21 | l += 1 22 | } 23 | 24 | while !chars[r].isLetter && !chars[r].isNumber && l < r { 25 | r -= 1 26 | } 27 | 28 | if chars[l] == chars[r] { 29 | l += 1; r -= 1 30 | } else { 31 | return false 32 | } 33 | } 34 | 35 | return true 36 | } 37 | } 38 | 39 | // Tests 40 | let s = Solution() 41 | s.isPalindrome("A man, a plan, a canal: Panama") 42 | s.isPalindrome("race a car") 43 | -------------------------------------------------------------------------------- /Array/15_ThreeSum.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 15. 三数之和 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/longest-common-prefix/ 6 | // 题目描述: 7 | // - 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。 8 | // - 注意:答案中不可以包含重复的三元组。 9 | 10 | // 标签:数组、双指针 11 | // 要点:枚举数组并额外采用双指针进行判断 12 | // 时间复杂度:O(N^2) 13 | // 空间复杂度:O(logN) 14 | // 15 | 16 | class Solution { 17 | func threeSum(_ nums: [Int]) -> [[Int]] { 18 | 19 | if nums.count < 3 { return [] } 20 | 21 | let nums = nums.sorted(by: <) 22 | var res = [[Int]]() 23 | 24 | for i in 0.. 0 && nums[i] == nums[i - 1] { continue } 27 | 28 | var left = i + 1 29 | var right = nums.count - 1 30 | 31 | while left < right { 32 | let sum = nums[i] + nums[left] + nums[right] 33 | if sum < 0 { 34 | left += 1 35 | } else if sum > 0 { 36 | right -= 1 37 | } else { 38 | res.append([nums[i], nums[left], nums[right]]) 39 | while (left < right && nums[left] == nums[left + 1]) { 40 | left += 1 41 | } 42 | while (left < right && nums[right] == nums[right - 1]) { 43 | right -= 1 44 | } 45 | left += 1 46 | right -= 1 47 | } 48 | } 49 | } 50 | 51 | return res 52 | } 53 | } 54 | 55 | // Tests 56 | 57 | let s = Solution() 58 | s.threeSum([-1, 0, 1, 2, -1, -4]) == [[-1, -1, 2], [-1, 0, 1]] 59 | s.threeSum([0,0,0,0]) == [[0, 0, 0]] 60 | s.threeSum([-2,0,1,1,2]) == [[-2,0,2],[-2,1,1]] 61 | -------------------------------------------------------------------------------- /Array/167_TwoSumII.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 167. 两数之和 II - 输入有序数组 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ 5 | // 标签:数组、双指针、二分查找 6 | // 要点:指针碰撞,由于数组有序,采用一头一尾双指针,通过判断两数之和与目标值的关系,相向遍历数组 7 | // 时间复杂度:O(N) 8 | // 空间复杂度:O(1) 9 | // 10 | 11 | import Foundation 12 | 13 | class Solution { 14 | func twoSum(_ numbers: [Int], _ target: Int) -> [Int] { 15 | var i = 0, j = numbers.count - 1 16 | 17 | while i < j { 18 | switch numbers[i] + numbers[j] { 19 | case target: return [i + 1, j + 1] 20 | case target...: j = j - 1 21 | default: i = i + 1 22 | } 23 | } 24 | return [] 25 | } 26 | } 27 | 28 | // Tests 29 | let s = Solution() 30 | s.twoSum([2, 7, 11, 15], 9) == [1, 2] 31 | -------------------------------------------------------------------------------- /Array/209_MinimumSizeSubarraySum.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 209. 长度最小的子数组 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ 6 | // 标签:数组、双指针、二分查找 7 | // 要点:定义一个 left 指针,另外定义一个 i 指针向前遍历,与此同时求和, 8 | // 当和大于目标值时,更新 res, 并将和减去 left 指针的值,left 指针前进一步 9 | // 时间复杂度:O(N) 10 | // 空间复杂度:O(1) 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func minSubArrayLen(_ s: Int, _ nums: [Int]) -> Int { 17 | guard !nums.isEmpty else { return 0 } 18 | var left = 0, sum = 0, res = Int.max 19 | for i in 0..= s { 22 | res = min(res, i + 1 - left) 23 | sum -= nums[left] 24 | left += 1 25 | } 26 | } 27 | return res != Int.max ? res : 0 28 | } 29 | } 30 | 31 | // Tests 32 | let s = Solution() 33 | s.minSubArrayLen(7, [2,3,1,2,4,3]) == 2 34 | s.minSubArrayLen(4, [1, 4, 4]) == 1 35 | s.minSubArrayLen(11, [1, 2, 3, 4, 5]) == 3 36 | s.minSubArrayLen(15, [1, 2, 3, 4, 5]) == 5 37 | s.minSubArrayLen(6, [10,2,3]) == 1 38 | -------------------------------------------------------------------------------- /Array/215_FindKthLargestInAnArray.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 215. 数组中的第K个最大元素 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/ 5 | // 标签:数组、多指针、快速排序 6 | // 要点:考察快速排序,基于怎么写效率都不如直接标准库sort一遍来得快,暂时先采用这个「笨」办法了 7 | // 另外,原地排序sort(by:)要比赋值排序sorted(by:)效率更快 8 | // 时间复杂度:O(NlogN),sort快排的复杂度 9 | // 空间复杂度:O(N) 10 | // 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func findKthLargest(_ nums: [Int], _ k: Int) -> Int { 16 | precondition(!nums.isEmpty && k > 0 && k <= nums.count) 17 | // return nums.sorted(by: >)[k - 1] 18 | var array = nums 19 | array.sort(by: >) 20 | return array[k - 1] 21 | } 22 | } 23 | 24 | // Tests 25 | let s = Solution() 26 | s.findKthLargest([3,2,1,5,6,4], 2) 27 | s.findKthLargest([3,2,3,1,2,4,5,5,6], 4) 28 | -------------------------------------------------------------------------------- /Array/26_RemoveDuplicatesFromSortedArray.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 26. 删除排序数组中的重复项 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ 5 | // 标签:数组、双指针 6 | // 要点:考察「数组变换」,使用双指针,一个遍历数组元素,一个在记录最后非重复项,移除后续(index+1)的原有项 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(1) 9 | // 10 | 11 | import Foundation 12 | 13 | class Solution { 14 | func removeDuplicates(_ nums: inout [Int]) -> Int { 15 | if nums.isEmpty { return 0 } 16 | 17 | var index = 0 18 | for i in 1 ..< nums.count { 19 | if nums[i] != nums[index] { 20 | index += 1 21 | nums[index] = nums[i] 22 | } 23 | } 24 | 25 | nums.removeSubrange((index + 1 ) ..< nums.count) 26 | 27 | return nums.count 28 | } 29 | } 30 | 31 | // Tests 32 | let s = Solution() 33 | var inputs = [1,1,2] 34 | assert(s.removeDuplicates(&inputs) == 2) 35 | assert(inputs == [1, 2]) 36 | -------------------------------------------------------------------------------- /Array/27_RemoveElement.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 27. 移除元素 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/remove-element/ 5 | // 标签:数组、双指针 6 | // 要点:考察「数组变换」,使用双指针,一个遍历数组元素,一个在记录最后非指定值的位置 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(1) 9 | // 10 | 11 | import Foundation 12 | 13 | class Solution { 14 | func removeElement(_ nums: inout [Int], _ val: Int) -> Int { 15 | if nums.isEmpty { return 0 } 16 | 17 | var index = 0 18 | for i in 0 ..< nums.count { 19 | if nums[i] != val { 20 | nums[index] = nums[i] 21 | index += 1 22 | } 23 | } 24 | 25 | nums.removeLast(nums.count - index) 26 | 27 | return nums.count 28 | } 29 | } 30 | 31 | // Tests 32 | let s = Solution() 33 | do { 34 | var input = [3,2,2,3] 35 | let newLength = s.removeElement(&input, 3) 36 | assert(input == [2, 2]) 37 | assert(newLength == 2) 38 | } 39 | -------------------------------------------------------------------------------- /Array/283_MoveZeroes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 283. 移动零 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/move-zeroes/ 5 | // 标签:数组、双指针 6 | // 要点:考察「数组变换」,使用双指针,一个遍历数组元素,一个在记录最后非零元素索引位置 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(1) 9 | // 10 | 11 | import Foundation 12 | 13 | class Solution { 14 | func moveZeroes(_ nums: inout [Int]) { 15 | if nums.isEmpty || nums.count == 1 { return } 16 | 17 | var index = 0 18 | for i in 0 ..< nums.count { 19 | if nums[i] != 0 { 20 | nums.swapAt(index, i) 21 | index += 1 22 | } 23 | } 24 | 25 | for i in (index.. String { 16 | var chars = Array(s) 17 | var left = 0, right = chars.count - 1 18 | while left < right { 19 | while !chars[left].isVowel && left < right { 20 | left += 1 21 | } 22 | while !chars[right].isVowel && left < right { 23 | right -= 1 24 | } 25 | chars.swapAt(left, right) 26 | left += 1; right -= 1 27 | } 28 | return String(chars) 29 | } 30 | } 31 | 32 | extension Character { 33 | // Discussion: `["a", "e", "i", "o", "u"].contains(lowercased())`? 34 | // 写法更简洁但运行更慢: 180ms vs 88ms 35 | var isVowel: Bool { 36 | let lower = lowercased() 37 | return "a" == lower || "e" == lower || "i" == lower || "o" == lower || "u" == lower 38 | } 39 | } 40 | 41 | // Tests 42 | let s = Solution() 43 | s.reverseVowels("hello") == "holle" 44 | s.reverseVowels("leetcode") == "leotcede" 45 | -------------------------------------------------------------------------------- /Array/45_JumpGameII.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 45. 跳跃游戏 II 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/jump-game-ii/ 6 | // 标签:数组、贪心算法 7 | // 要点:每次找可以到达的最远位置,不要访问最后一个元素避免不必要的一次跳跃 8 | // 时间复杂度: O(N) 9 | // 空间复杂度: O(1) 10 | // 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func jump(_ nums: [Int]) -> Int { 16 | var maxPosition = 0 17 | var step = 0 18 | var stop = 0 19 | for i in 0.. [Int] { 14 | let m = matrix.count 15 | guard m > 0 else { return [] } 16 | let n = matrix[0].count 17 | guard n > 0 else { return [] } 18 | 19 | var res = [Int]() 20 | var x = 0 21 | var y = 0 22 | for _ in 0 ..< (m * n) { 23 | res.append(matrix[x][y]) 24 | if (x+y) % 2 == 0 { 25 | if y == n - 1 { 26 | x += 1 27 | } else if x == 0 { 28 | y += 1 29 | } else { 30 | x -= 1 31 | y += 1 32 | } 33 | } else { 34 | if x == m - 1 { 35 | y += 1 36 | } else if y == 0 { 37 | x += 1 38 | } else { 39 | x += 1 40 | y -= 1 41 | } 42 | } 43 | } 44 | 45 | return res 46 | } 47 | } 48 | 49 | // Tests 50 | let s = Solution() 51 | let matrix = [[ 1, 2, 3 ],[ 4, 5, 6 ],[ 7, 8, 9 ]] 52 | assert(s.findDiagonalOrder(matrix) == [1,2,4,7,5,3,6,8,9]) 53 | -------------------------------------------------------------------------------- /Array/560_SubarraySumEqualsK.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 560. 和为K的子数组 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/subarray-sum-equals-k/ 6 | // 标签:数组、哈希表 7 | // 要点:从暴力解法着手启发思路,借助哈希表缓存前缀和进行优化 8 | // 时间复杂度: O(N) 9 | // 空间复杂度: O(N) 10 | // 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func subarraySum(_ nums: [Int], _ k: Int) -> Int { 16 | var count = 0 17 | var pre = 0 18 | var dict = [0: 1] 19 | for num in nums { 20 | pre += num 21 | if let value = dict[pre - k] { 22 | count += value 23 | } 24 | dict[pre] = (dict[pre] ?? 0) + 1 25 | } 26 | return count 27 | } 28 | } 29 | 30 | // Tests 31 | let s = Solution() 32 | s.subarraySum([1, 1, 1], 2) 33 | s.subarraySum([0,0,0,0,0,0,0,0,0,0], 0) 34 | -------------------------------------------------------------------------------- /Array/66_PlusOne.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 66. 加一 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/plus-one/ 5 | // 标签:数组 6 | // 要点:逆序遍历,加一后判断10求余是否为0,不为0则为结果,为0则继续进位,遍历结束仍未返回则添加一位最高位 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(1) 9 | 10 | import Foundation 11 | 12 | class Solution { 13 | func plusOne(_ digits: [Int]) -> [Int] { 14 | var _digits = digits 15 | for index in stride(from: _digits.count - 1, through: 0, by: -1) { 16 | _digits[index] += 1 17 | _digits[index] = _digits[index] % 10 18 | if _digits[index] != 0 { return _digits } 19 | } 20 | _digits = Array(repeating: 0, count: digits.count + 1) 21 | _digits[0] = 1 22 | return _digits 23 | } 24 | } 25 | 26 | // Tests 27 | let s = Solution() 28 | assert(s.plusOne([1, 2, 3]) == [1, 2, 4]) 29 | assert(s.plusOne([4,3,2,1]) == [4,3,2,2]) -------------------------------------------------------------------------------- /Array/695_MaxAreaofIsland.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 695. 岛屿的最大面积 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/max-area-of-island/ 6 | // 标签:数组、深度优先搜索 7 | // 要点:贪心 8 | // 时间复杂度: O(M * N) 9 | // 空间复杂度: O(M * N) 10 | // 11 | 12 | class Solution { 13 | func maxAreaOfIsland(_ grid: [[Int]]) -> Int { 14 | var maxArea = 0 15 | var grid = grid 16 | for (i, row) in grid.enumerated() { 17 | for j in 0.. Int { 25 | 26 | if row < 0 || column < 0 27 | || row == grid.count || column == grid[0].count 28 | || grid[row][column] != 1 { 29 | return 0 30 | } 31 | // 为了确保每个土地访问不超过一次,我们每次经过一块土地时,将这块土地的值置为 0。这样我们就不会多次访问同一土地。 32 | grid[row][column] = 0 33 | var area = 1 34 | for (i, j) in [(0, 1), (0, -1), (1, 0), (-1, 0)] { 35 | let nextRow = row + i 36 | let nextColumn = column + j 37 | area += backtrack(&grid, row: nextRow, column: nextColumn) 38 | } 39 | return area 40 | } 41 | } 42 | 43 | /// Tests 44 | let s = Solution() 45 | s.maxAreaOfIsland([ 46 | [0,0,1,0,0,0,0,1,0,0,0,0,0], 47 | [0,0,0,0,0,0,0,1,1,1,0,0,0], 48 | [0,1,1,0,1,0,0,0,0,0,0,0,0], 49 | [0,1,0,0,1,1,0,0,1,0,1,0,0], 50 | [0,1,0,0,1,1,0,0,1,1,1,0,0], 51 | [0,0,0,0,0,0,0,0,0,0,1,0,0], 52 | [0,0,0,0,0,0,0,1,1,1,0,0,0], 53 | [0,0,0,0,0,0,0,1,1,0,0,0,0] 54 | ]) == 6 55 | 56 | s.maxAreaOfIsland([[0,0,0,0,0,0,0,0]]) == 0 57 | -------------------------------------------------------------------------------- /Array/724_FindPivotIndex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 724. 寻找数组的中心索引 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/find-pivot-index/ 5 | // 标签:数组 6 | // 要点:两次遍历,一次求总和,一次渐进求和判断 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(1) 9 | 10 | import Foundation 11 | 12 | class Solution { 13 | func pivotIndex(_ nums: [Int]) -> Int { 14 | // 求总和 15 | let sum = nums.reduce(0, +) 16 | var current = 0 17 | for (index, num) in nums.enumerated() { 18 | // 渐进求和判断 19 | if (sum - current - num) == current { return index } 20 | current += num 21 | } 22 | return -1 23 | } 24 | } 25 | 26 | // Tests 27 | let s = Solution() 28 | assert(s.pivotIndex([1, 7, 3, 6, 5, 6]) == 3) 29 | assert(s.pivotIndex([1, 2, 3]) == -1) 30 | -------------------------------------------------------------------------------- /Array/747_LargestNumberAtLeastTwiceofOthers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 747. Largest Number At Least Twice of Others 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/largest-number-at-least-twice-of-others/submissions/ 5 | // 标签:数组 6 | // 要点:两次遍历,一次求总和,一次判断是否大于(除自身外)其他数两倍 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(1) 9 | 10 | import Foundation 11 | 12 | class Solution { 13 | func dominantIndex(_ nums: [Int]) -> Int { 14 | var largest = 0, indexRes = 0 15 | for (index, num) in nums.enumerated() { 16 | if num > largest { 17 | largest = num 18 | indexRes = index 19 | } 20 | } 21 | for num in nums { 22 | if num == largest { continue } 23 | if largest < num * 2 { 24 | return -1 25 | } 26 | } 27 | return indexRes 28 | } 29 | } 30 | 31 | // Tests 32 | let s = Solution() 33 | assert(s.dominantIndex([3, 6, 1, 0]) == 1) 34 | assert(s.dominantIndex([1, 2, 3, 4]) == -1) 35 | -------------------------------------------------------------------------------- /Array/75_SortColors.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 75. Sort Colors 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/sort-colors/ 5 | // 标签:数组、多指针 6 | // 要点:考察多指针的应用,一个指针指向「小端」,一个指针指向「大端」,一个指针遍历数组 7 | // 注意遍历指针交换时的动作,仅在与小端进行交换时前进,因为与大端交换过来的元素未遍历过 8 | // 时间复杂度:O(n) 9 | // 空间复杂度:O(1) 10 | // 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func sortColors(_ nums: inout [Int]) { 16 | if nums.isEmpty { return } 17 | 18 | var current = 0, little = 0, big = nums.count - 1 19 | while current <= big { 20 | if nums[current] == 0 { 21 | nums.swapAt(little, current) 22 | little += 1 23 | current += 1 24 | } else if nums[current] == 2 { 25 | nums.swapAt(big, current) 26 | big -= 1 27 | } else { 28 | current += 1 29 | } 30 | } 31 | } 32 | } 33 | 34 | // Tests 35 | let s = Solution() 36 | do { 37 | var input = [2,0,2,1,1,0] 38 | let expectOutput = [0,0,1,1,2,2] 39 | s.sortColors(&input) 40 | input 41 | assert(input == expectOutput) 42 | } 43 | 44 | do { 45 | var input = [1, 2, 0] 46 | let expectOutput = [0, 1, 2] 47 | s.sortColors(&input) 48 | input 49 | // assert(input == expectOutput) 50 | } 51 | -------------------------------------------------------------------------------- /Array/88_MergeSortedArray.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 88. 合并两个有序数组 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/merge-sorted-array/ 5 | // 标签:数组、多指针 6 | // 要点:逆序遍历,避免拷贝增加不必要的空间复杂度 7 | // 注意使用双指针即可,以及避免用到 replaceSubrange(:with:) 8 | // 时间复杂度:O(M+N) 9 | // 空间复杂度:O(1) 10 | // 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) { 16 | var p1 = m - 1, p2 = n - 1 17 | while p1 >= 0 || p2 >= 0 { 18 | if p2 < 0 || (p1 >= 0 && nums1[p1] > nums2[p2]) { 19 | nums1[p1 + p2 + 1] = nums1[p1] 20 | p1 -= 1 21 | } else { 22 | nums1[p1 + p2 + 1] = nums2[p2] 23 | p2 -= 1 24 | } 25 | } 26 | } 27 | } 28 | 29 | // Tests 30 | let s = Solution() 31 | var nums1 = [1,2,3,0,0,0] 32 | s.merge(&nums1, 3, [2,5,6], 3) 33 | nums1 34 | -------------------------------------------------------------------------------- /Array/README.md: -------------------------------------------------------------------------------- 1 | # 数组 2 | 3 | > 思考:为什么数组要从 0 开始编号,而不是从 1 开始呢? 4 | 5 | ## 如何实现随机访问 6 | 7 | 数组(Array)是一种**线性表**数据结构。它用一组**连续的内存空间**,来存储一组具有**相同类型**的数据** 8 | 9 | 1. 线性表(Linear List) 10 | 11 | 线性表就是数据排成一条线一样的结构,每个线性表上的数据最多只有前后两个方向。除了数组,链表、队列、栈也是线性表结构。 12 | 13 | ![线性表](./linear_list_graph.jpg) 14 | 15 | 对应的概念是非线性表,如二叉树、堆、图等,数据之间并不是简单的前后关系。 16 | 17 | ![非线性表](./anti_linear_graph.jpg) 18 | 19 | 2. 连续的内存空间和相同类型的数据 20 | 21 | 这两点让数组有了一个重要的特性:「随机访问」。 22 | * 优势: 下标随机访问(⚠️而非查找操作)的时间复杂度是O(1) 23 | * 劣势:删除、插入等操作,为了保证连续性而变得低效 24 | 25 | ```c 26 | a[i]_address = base_address + i * data_type_size 27 | ``` 28 | 29 | ## 低效的「插入」和「删除」 30 | 31 | 数组为了保持内存数据的连续性,会导致插入、删除的操作比较低效。 32 | 33 | * 插入操作: 34 | * 有序 35 | * **无序** 36 | * 删除操作: 37 | * 标记->需时一次批量删除 38 | 39 | ## 警惕数组的访问越界 40 | 41 | ## 容器能否完全替代数组? 42 | 43 | * 容器的优势: 44 | * 封装许多数组操作细节 45 | * 支持动态扩容 46 | 47 | > 对于业务开发,直接用容器就足够了; 48 | > 49 | > 对于底层开发,性能需要优化到极致,就要考虑优选数组了。 50 | 51 | ## 思考解答 52 | 53 | 「下标」的定义是「偏移」 54 | 55 | 以下是从 0 开始: 56 | ```c 57 | a[i]_address = base_address + i * data_type_size 58 | ``` 59 | 60 | 以下是从 1 开始: 61 | ```c 62 | a[k]_address = base_address + (k-1)*type_size 63 | ``` 64 | 65 | * 从 1 开始,每次随机访问数组元素时都多了一次减法运算。 66 | * 最主要原因可能还是历史原因 67 | 68 | ## 数组的常用操作 69 | 70 | * 初始化 71 | 72 | * 获取长度 73 | * 「随机访问」根据索引获取元素 74 | * 元素遍历 75 | * 修改元素 76 | * 排序 77 | 78 | ## 数组在算法中的应用技巧 79 | 80 | * 做好初始定义 81 | 82 | 做数组类算法问题的时候,常常需要定义一个变量,明确该变量的定义,并且在整个算法逻辑中,不停地维护住这个变量的定义,特别注意初始值和边界的问题。 83 | 84 | * 运用基础算法思想 85 | 86 | 典型的排序算法思想、二分查找思想在数组中应用非常广泛 87 | 88 | * 双索引技巧 - 对撞指针 89 | 90 | 对撞指针:指针 i 和 j 分别指向数组的第一个元素和最后一个元素,然后指针 i 不断向前,指针 j 不断递减向后,直到 i = j。 91 | 92 | * 双索引技巧 - 滑动窗口 93 | 94 | 一些题目利用「滑动窗口」方法,可以将时间复杂度控制在 O(n) 级别。定义好滑动窗口,明确表达的意思,并考虑边界与初始值。 -------------------------------------------------------------------------------- /Array/anti_linear_graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binlogo-Archive/LeetCode-Swift-Track/6636f0446d3da2fbe5fbdc9206d4907dd2ff3f46/Array/anti_linear_graph.jpg -------------------------------------------------------------------------------- /Array/linear_list_graph.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Binlogo-Archive/LeetCode-Swift-Track/6636f0446d3da2fbe5fbdc9206d4907dd2ff3f46/Array/linear_list_graph.jpg -------------------------------------------------------------------------------- /BigONotes.md: -------------------------------------------------------------------------------- 1 | # 大 O 复杂度表示法 2 | 3 | > 大 O 复杂度表示法,表示代码执行时间随数据规模增长的变化趋势,也称作渐进时间复杂度。不代表代码真正的执行时间。 4 | 5 | # 时间复杂度分析 6 | 7 | 1. 只关注循环次数最多的一段代码 8 | 2. 加法法则:总复杂度等于量级最大的那段代码的复杂度 9 | > 如果 T1(n)=O(f(n)),T2(n)=O(g(n)); 10 | > 11 | > 那么 T(n)=T1(n)+T2(n)=max(O(f(n)),O(g(n)))=O(max(f(n),g(n))) 12 | 3. 乘法法则:嵌套代码的复杂度等于嵌套内外代码复杂度的乘积 13 | 14 | * 最好、最坏情况时间复杂度 15 | * 平均情况时间复杂度 16 | * 均摊时间复杂度 17 | -------------------------------------------------------------------------------- /BinarySearch/33_ SearchinRotatedSortedArray.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 33. 搜索旋转排序数组 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ 6 | // 标签:数组、二分查找 7 | // 要点:局部有序,边界细节的把控 8 | // 时间复杂度: O(logN) 9 | // 空间复杂度: O(1) 10 | // 11 | 12 | class Solution { 13 | func search(_ nums: [Int], _ target: Int) -> Int { 14 | return binarySearch(nums, target: target, range: nums.startIndex..) -> Int { 18 | 19 | guard range.endIndex > range.startIndex else { return -1 } 20 | 21 | let middle = nums.index(range.startIndex, offsetBy: (range.endIndex - range.startIndex) / 2) 22 | 23 | if nums[middle] == target { 24 | return middle 25 | } else if nums.first! <= nums[middle] { 26 | if target >= nums.first! && target < nums[middle] { 27 | return binarySearch(nums, target: target, range: range.startIndex.. nums[middle] && target <= nums.last! { 33 | return binarySearch(nums, target: target, range: (middle + 1).. Double { 20 | let count = nums1.count + nums2.count 21 | if count % 2 != 0 { 22 | return _findKth(nums1: nums1, nums2: nums2, k: count / 2 + 1) 23 | } else { 24 | return (_findKth(nums1: nums1, nums2: nums2, k: count / 2) 25 | + _findKth(nums1: nums1, nums2: nums2, k: count / 2 + 1)) 26 | / 2.0 27 | } 28 | } 29 | 30 | private func _findKth(nums1: [Int], nums2: [Int], k: Int) -> Double { 31 | let count1 = nums1.count 32 | let count2 = nums2.count 33 | guard count1 <= count2 else { 34 | return _findKth(nums1: nums2, nums2: nums1, k: k) 35 | } 36 | if count1 == 0 { 37 | return Double(nums2[k - 1]) 38 | } 39 | if k == 1 { 40 | return Double(min(nums1[0], nums2[0])) 41 | } 42 | // 划分下一个递归迭代 43 | let i = min(k / 2, count1) 44 | let j = min(k / 2, count2) 45 | 46 | if nums1[i - 1] < nums2[j - 1] { 47 | return _findKth(nums1: Array(nums1[i.. Int { 15 | let currentPruduct = nums.first ?? Int.min 16 | var maxProduct = currentPruduct 17 | var minProduct = currentPruduct 18 | var result = currentPruduct 19 | for current in 1.. Int { 15 | 16 | guard let first = matrix.first else { return 0 } 17 | 18 | var dp = matrix.map { row in row.map { _ in 0 } } 19 | var maximalSize = 0 20 | for i in 0.. Int { 14 | var currentSum = nums.first ?? Int.min 15 | var maxSum = currentSum 16 | for current in 1.. Int { 15 | precondition(costs.count == 3) 16 | guard let last = days.last else { return 0 } 17 | var dp = [Int](repeating: 0, count: last + 1) 18 | var day = 0 19 | for i in 1.. 定义 DP 数组/函数的含义 -> 明确「选择」 -> 明确 base case 16 | ``` 17 | 18 | ## 斐波那契数列 19 | 20 | * 简单递归暴力求解 21 | 22 | ```c 23 | int fib(int N) { 24 | if (N == 1 || N == 2) return 1; 25 | return fib(N - 1) + fib(N - 2); 26 | } 27 | ``` 28 | 29 | 30 | 31 | > 递归问题的时间复杂度怎么算?子问题个数 * 子问题的时间复杂度 32 | 33 | ```c 34 | int fib(int N) { 35 | vector dp(N + 1, 0); 36 | // base case 37 | dp[1] = dp[2] = 1; 38 | for (int i = 3; i <= N; i++) 39 | dp[i] = dp[i - 1] + dp[i - 2]; 40 | return dp[N]; 41 | } 42 | ``` 43 | 44 | 动态转移方程: 45 | 46 | ![img](https://gblobscdn.gitbook.com/assets%2F-LrtQOWSnDdXhp3kYN4k%2F-M3U3aNXgGJVkKZ-TldN%2F-M0SeazMTJ4s2Y0pPdIz%2Ffib.png?generation=1585364271219618&alt=media) 47 | 48 | * 进一步优化:仅保留之前的两个状态即可 49 | 50 | ```c 51 | int fib(int n) { 52 | if (n == 2 || n == 1) 53 | return 1; 54 | int prev = 1, curr = 1; 55 | for (int i = 3; i <= n; i++) { 56 | int sum = prev + curr; 57 | prev = curr; 58 | curr = sum; 59 | } 60 | return curr; 61 | } 62 | ``` 63 | 64 | ## 凑零钱问题 65 | 66 | > 要符合「最优子结构」,子问题间必须互相独立 67 | 68 | ```c 69 | int coinChange(vector& coins, int amount) { 70 | // 数组大小为 amount + 1,初始值也为 amount + 1 71 | vector dp(amount + 1, amount + 1); 72 | // base case 73 | dp[0] = 0; 74 | for (int i = 0; i < dp.size(); i++) { 75 | // 内层 for 在求所有子问题 + 1 的最小值 76 | for (int coin : coins) { 77 | // 子问题无解,跳过 78 | if (i - coin < 0) continue; 79 | dp[i] = min(dp[i], 1 + dp[i - coin]); 80 | } 81 | } 82 | return (dp[amount] == amount + 1) ? -1 : dp[amount]; 83 | } 84 | ``` 85 | 86 | ## 总结 87 | 88 | * 先思考「如何穷举」,再追求「如何聪明地穷举」 -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 王兴彬_Binboy 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 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/024_SwapNodesInPairs.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 24. 两两交换链表中的节点 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs/ 7 | // 标签:链表 8 | // 要点:链表遍历, 递归 9 | // **** 上一次递归 -> head -> next -> 下一次递归 10 | // **** head -> 下一次递归结果,next -> head 11 | // 时间复杂度:O(n) 12 | // 空间复杂度:O(1) 13 | // 14 | 15 | import Foundation 16 | 17 | // Definition for singly-linked list. 18 | public class ListNode { 19 | public var val: Int 20 | public var next: ListNode? 21 | public init(_ val: Int) { 22 | self.val = val 23 | self.next = nil 24 | } 25 | } 26 | 27 | class Solution { 28 | func swapPairs(_ head: ListNode?) -> ListNode? { 29 | guard let wrappedHead = head, 30 | let next = wrappedHead.next else { 31 | return head 32 | } 33 | 34 | wrappedHead.next = swapPairs(next.next) 35 | next.next = wrappedHead 36 | return next 37 | } 38 | } 39 | 40 | //: [Next](@next) 41 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/1003_CheckIfWordIsValidAfterSubstitutions.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 1003. 检查替换后的词是否有效 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/check-if-word-is-valid-after-substitutions/ 7 | // 标签:字符串、栈 8 | // 要点:当前字母为c时,栈顶应为b,出栈,栈顶应为a,否则都无效;当前字母不为c时,入栈 9 | // 时间复杂度:O(n) 10 | // 空间复杂度:O(1) 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func isValid(_ S: String) -> Bool { 16 | var stack = [Character]() 17 | for char in S { 18 | if char == "c" { 19 | if stack.popLast() != "b" { 20 | return false 21 | } 22 | if stack.popLast() != "a" { 23 | return false 24 | } 25 | } else { 26 | stack.append(char) 27 | } 28 | } 29 | return stack.isEmpty 30 | } 31 | } 32 | 33 | // Tests 34 | let s = Solution() 35 | assert(s.isValid("aabcbc")) 36 | assert(s.isValid("abcabcababcc")) 37 | assert(!s.isValid("abccba")) 38 | assert(!s.isValid("cababc")) 39 | 40 | //: [Next](@next) 41 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/1014_BestSightseeingPair.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 1014. 最佳观光组合 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/best-sightseeing-pair/ 9 | // 10 | 11 | class Solution { 12 | func maxScoreSightseeingPair(_ A: [Int]) -> Int { 13 | var res = 0 14 | var maxScore = A.first ?? 0 + 0 15 | 16 | for j in 1.. Bool { 20 | return check(p: root, q: root) 21 | } 22 | 23 | private func check(p: TreeNode?, q: TreeNode?) -> Bool { 24 | if p == nil && q == nil { return true } 25 | 26 | if let p = p, let q = q { 27 | return p.val == q.val && check(p: p.left, q: q.right) && check(p: p.right, q: q.left) 28 | } else { 29 | return false 30 | } 31 | } 32 | } 33 | 34 | //: [Next](@next) 35 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/1025_DivisorGame.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func divisorGame(_ N: Int) -> Bool { 7 | return N % 2 == 0 8 | } 9 | } 10 | 11 | //: [Next](@next) 12 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/1028_RecoveraTreeFromPreorderTraversal.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | 6 | /// Definition for a binary tree node. 7 | public class TreeNode { 8 | public var val: Int 9 | public var left: TreeNode? 10 | public var right: TreeNode? 11 | public init(_ val: Int) { 12 | self.val = val 13 | self.left = nil 14 | self.right = nil 15 | } 16 | } 17 | 18 | class Solution { 19 | func recoverFromPreorder(_ S: String) -> TreeNode? { 20 | guard !S.isEmpty else { return nil } 21 | 22 | let chars = [Character](S) 23 | var nodes = [TreeNode?]() 24 | var index = 0 25 | 26 | var degree = 0 27 | while index < chars.count { 28 | if chars[index] == "-" { 29 | degree += 1 30 | } else { 31 | var temp = "\(chars[index])" 32 | while index + 1 < chars.count { 33 | if chars[index + 1] == "-" { 34 | break 35 | } 36 | temp = "\(temp)\(chars[index + 1])" 37 | index += 1 38 | } 39 | let node = TreeNode(Int(temp)!) 40 | if !nodes.isEmpty { 41 | if degree < nodes.count { 42 | nodes[degree - 1]?.right = node 43 | nodes.removeLast(nodes.count - degree) 44 | } else { 45 | nodes[degree - 1]?.left = node 46 | } 47 | } 48 | nodes.append(node) 49 | degree = 0 50 | } 51 | index += 1 52 | } 53 | return nodes.first ?? nil 54 | } 55 | } 56 | 57 | //: [Next](@next) 58 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/102_BinaryTreeLevelOrderTraversal.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 102. 二叉树的层序遍历 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/ 9 | // 标签:树 10 | // 要点:递归,理解并把握返回的终止条件 11 | // 时间复杂度: O(N) 12 | // 空间复杂度: O(N) 13 | // 14 | 15 | /// Definition for a binary tree node. 16 | public class TreeNode { 17 | public var val: Int 18 | public var left: TreeNode? 19 | public var right: TreeNode? 20 | public init(_ val: Int) { 21 | self.val = val 22 | self.left = nil 23 | self.right = nil 24 | } 25 | } 26 | 27 | class Solution { 28 | func levelOrder(_ root: TreeNode?) -> [[Int]] { 29 | guard let root = root else { return [] } 30 | 31 | var result = [[Int]]() 32 | func _helper(_ node: TreeNode, level: Int) { 33 | if result.count == level { 34 | result.append([]) 35 | } 36 | result[level].append(node.val) 37 | if let left = node.left { 38 | _helper(left, level: level + 1) 39 | } 40 | if let right = node.right { 41 | _helper(right, level: level + 1) 42 | } 43 | } 44 | 45 | _helper(root, level: 0) 46 | return result 47 | } 48 | } 49 | 50 | //: [Next](@next) 51 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/104_MaximumDepthofBinaryTree.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | 6 | /// Definition for a binary tree node. 7 | public class TreeNode { 8 | public var val: Int 9 | public var left: TreeNode? 10 | public var right: TreeNode? 11 | public init(_ val: Int) { 12 | self.val = val 13 | self.left = nil 14 | self.right = nil 15 | } 16 | } 17 | 18 | class Solution { 19 | func maxDepth(_ root: TreeNode?) -> Int { 20 | guard let node = root else { return 0 } 21 | return max(maxDepth(node.left), maxDepth(node.right)) + 1 22 | } 23 | } 24 | 25 | //: [Next](@next) 26 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/105_ConstructBinaryTreefromPreorderandInorderTraversal.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | 6 | /// Definition for a binary tree node. 7 | public class TreeNode { 8 | public var val: Int 9 | public var left: TreeNode? 10 | public var right: TreeNode? 11 | public init(_ val: Int) { 12 | self.val = val 13 | self.left = nil 14 | self.right = nil 15 | } 16 | } 17 | 18 | class Solution { 19 | func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? { 20 | guard !preorder.isEmpty else { return nil } 21 | 22 | let root = TreeNode(preorder[0]) 23 | var stack = [TreeNode]() 24 | stack.append(root) 25 | var inorderIndex = 0 26 | for i in 1.. TreeNode? { 20 | return helper(nums, left: 0, right: nums.count - 1) 21 | } 22 | 23 | func helper(_ nums: [Int], left: Int, right: Int) -> TreeNode? { 24 | if left > right { 25 | return nil 26 | } 27 | let mid = (left + right) / 2 28 | let node = TreeNode(nums[mid]) 29 | node.left = helper(nums, left: left, right: mid - 1) 30 | node.right = helper(nums, left: mid + 1, right: right) 31 | return node 32 | } 33 | } 34 | 35 | //: [Next](@next) 36 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/10_RegularExpressionMatching.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func isMatch(_ s: String, _ p: String) -> Bool { 7 | if p.isEmpty { return s.isEmpty } 8 | 9 | let signIndex = p.index(p.startIndex, offsetBy: 1) 10 | let firstCharacterMatch = s.first == p.first || p.first == "." 11 | 12 | if p.count >= 2 && p[signIndex] == "*" { 13 | return isMatch(s, String(p[p.index(p.startIndex, offsetBy: 2).. Bool { 20 | guard let root = root else { 21 | return false 22 | } 23 | if root.left == nil && root.right == nil { 24 | return root.val == sum 25 | } 26 | return hasPathSum(root.left, sum - root.val) 27 | || hasPathSum(root.right, sum - root.val) 28 | } 29 | } 30 | 31 | //: [Next](@next) 32 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/118_Pascal'sTriangle.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 118. 杨辉三角 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/pascals-triangle/ 7 | // 标签:数组 8 | // 要点:根据杨辉三角规律迭代生成 9 | // 时间复杂度:O(n^2) 10 | // 空间复杂度:O(n^2) 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func generate(_ numRows: Int) -> [[Int]] { 16 | guard numRows > 0 else { return [] } 17 | 18 | var triangle = [[Int]]() 19 | 20 | triangle.append([1]) // 首行始终为 [1] 21 | 22 | for rowIndex in 1.. Int { 19 | var left = 0, right = height.count - 1, res = 0 20 | while left < right { 21 | let heightLeft = height[left], heightRight = height[right] 22 | res = max(res, (right - left) * min(heightLeft, heightRight)) 23 | heightLeft < heightRight ? (left += 1) : (right -= 1) 24 | } 25 | return res 26 | } 27 | } 28 | 29 | // Tests 30 | let s = Solution() 31 | s.maxArea([1,8,6,2,5,4,8,3,7]) == 49 32 | 33 | //: [Next](@next) 34 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/120_Triangle.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func minimumTotal(_ triangle: [[Int]]) -> Int { 7 | var triangle = triangle 8 | for i in (0..<(triangle.count - 1)).reversed() { 9 | for j in 0.. Int { 7 | guard !prices.isEmpty else { return 0 } 8 | var minPrice = prices.first! 9 | var maxProfit = 0 10 | for current in 1.. maxProfit { 15 | maxProfit = currentPrice - minPrice 16 | } 17 | } 18 | return maxProfit 19 | } 20 | } 21 | 22 | // Tests 23 | let s = Solution() 24 | s.maxProfit([7,1,5,3,6,4]) == 5 25 | 26 | //: [Next](@next) 27 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/122_BestTimetoBuyandSellStockII.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func maxProfit(_ prices: [Int]) -> Int { 7 | guard !prices.isEmpty else { return 0 } 8 | var maxProfit = 0 9 | for current in 1.. prices[current - 1] { 11 | maxProfit += prices[current] - prices[current - 1] 12 | } 13 | } 14 | return maxProfit 15 | } 16 | } 17 | 18 | // Tests 19 | let s = Solution() 20 | s.maxProfit([7,1,5,3,6,4]) == 7 21 | 22 | //: [Next](@next) 23 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/124_BinaryTreeMaximumPathSum.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | 6 | /// Definition for a binary tree node. 7 | public class TreeNode { 8 | public var val: Int 9 | public var left: TreeNode? 10 | public var right: TreeNode? 11 | public init(_ val: Int) { 12 | self.val = val 13 | self.left = nil 14 | self.right = nil 15 | } 16 | } 17 | 18 | class Solution { 19 | func maxPathSum(_ root: TreeNode?) -> Int { 20 | return getPathSum(root).maxPath 21 | } 22 | 23 | private func getPathSum(_ root: TreeNode?) -> (singlePath: Int, maxPath: Int) { 24 | guard let root = root else { 25 | return (0, Int.min) 26 | } 27 | 28 | let left = getPathSum(root.left) 29 | let right = getPathSum(root.right) 30 | 31 | var singlePath = max(left.singlePath, right.singlePath) + root.val 32 | singlePath = max(singlePath, 0) 33 | 34 | let maxPath = max(left.maxPath, 35 | right.maxPath, 36 | left.singlePath + right.singlePath + root.val) 37 | return (singlePath, maxPath) 38 | } 39 | } 40 | 41 | //: [Next](@next) 42 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/125_ValidPalindrome.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 125. 验证回文串 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/valid-palindrome/ 7 | // 标签:数组、双指针、对撞指针 8 | // 要点:指针碰撞,由于数组有序,采用一头一尾双指针,相向遍历数组,跳过非比较字符 9 | // 若相等则继续,不相等则返回 false,直到指针碰撞(l Bool { 18 | let chars = Array(s.lowercased()) 19 | var l = 0, r = chars.count - 1 20 | 21 | while l < r { 22 | while !chars[l].isLetter && !chars[l].isNumber && l < r { 23 | l += 1 24 | } 25 | 26 | while !chars[r].isLetter && !chars[r].isNumber && l < r { 27 | r -= 1 28 | } 29 | 30 | if chars[l] == chars[r] { 31 | l += 1; r -= 1 32 | } else { 33 | return false 34 | } 35 | } 36 | 37 | return true 38 | } 39 | } 40 | 41 | // Tests 42 | let s = Solution() 43 | s.isPalindrome("A man, a plan, a canal: Panama") 44 | s.isPalindrome("race a car") 45 | 46 | //: [Next](@next) 47 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/128_LongestConsecutiveSequence.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func longestConsecutive(_ nums: [Int]) -> Int { 7 | var numSet = Set(nums) 8 | var result = 0 9 | 10 | for num in nums { 11 | if numSet.contains(num) { 12 | numSet.remove(num) 13 | result = max(1 + consecutive(&numSet, num, 1) + consecutive(&numSet, num, -1), result) 14 | } 15 | } 16 | 17 | return result 18 | } 19 | 20 | private func consecutive(_ set: inout Set, _ num: Int, _ step: Int) -> Int { 21 | var length = 0 22 | var num = num + step 23 | 24 | while set.contains(num) { 25 | set.remove(num) 26 | length += 1 27 | num = num + step 28 | } 29 | 30 | return length 31 | } 32 | } 33 | 34 | //: [Next](@next) 35 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/1300_SumofMutatedArrayClosesttoTarget.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func findBestValue(_ arr: [Int], _ target: Int) -> Int { 7 | let sortedArr = arr.sorted() 8 | let count = arr.count 9 | var sum = 0 10 | for i in 0..= average { 13 | let curAverage = Double(target - sum) / Double(count - i) 14 | if curAverage - Double(average) > 0.5 { 15 | return average + 1 16 | } else { 17 | return average 18 | } 19 | } 20 | sum += sortedArr[i] 21 | } 22 | return sortedArr[count - 1] 23 | } 24 | } 25 | 26 | /// Tests 27 | let s = Solution() 28 | s.findBestValue([4,9,3], 10) == 3 29 | 30 | //: [Next](@next) 31 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/1371_FindtheLongestSubstringContainingVowelsinEvenCounts.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func findTheLongestSubstring(_ s: String) -> Int { 7 | var res = 0 8 | var status = 0 9 | var pos = [Int](repeating: -1, count: 1 << 5) 10 | pos[0] = 0 11 | let chars = [Character](s) 12 | for i in 0..= 0 { 22 | res = max(res, i + 1 - pos[status]) 23 | } else { 24 | pos[status] = i + 1 25 | } 26 | } 27 | return res 28 | } 29 | } 30 | 31 | // Tests 32 | let s = Solution() 33 | s.findTheLongestSubstring("eleetminicoworoep") == 13 34 | s.findTheLongestSubstring("leetcodeisgreat") == 5 35 | s.findTheLongestSubstring("bcbcbc") == 6 36 | 37 | //: [Next](@next) 38 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/139_WordBreak.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func wordBreak(_ s: String, _ wordDict: [String]) -> Bool { 7 | let wordDictSet = Set(wordDict) 8 | var dp = [Bool](repeating: false, count: s.count + 1) 9 | // 任意空字符串可被分割 10 | dp[0] = true 11 | for i in 1...s.count { 12 | for j in 0.. [Bool] { 7 | guard let originMax = candies.max() else { return [] } 8 | return candies.map { $0 + extraCandies >= originMax } 9 | } 10 | } 11 | 12 | //: [Next](@next) 13 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/146_LRUCache.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Node { 6 | var key: Int 7 | var value: Int 8 | var next: Node? 9 | weak var prev: Node? 10 | 11 | init(key: Int, value: Int) { 12 | self.key = key 13 | self.value = value 14 | } 15 | } 16 | 17 | class LRUCache { 18 | var capacity: Int 19 | var dict: [Int: Node] 20 | var head: Node 21 | var tail: Node 22 | 23 | init(_ capacity: Int) { 24 | self.capacity = capacity 25 | self.dict = [Int: Node]() 26 | self.head = Node(key: 0, value: 0) 27 | self.tail = Node(key: 0, value: 0) 28 | self.head.next = self.tail 29 | self.tail.prev = self.head 30 | } 31 | 32 | func get(_ key: Int) -> Int { 33 | if let node = dict[key] { 34 | remove(node: node) 35 | add(node: node) 36 | return node.value 37 | } else { 38 | return -1 39 | } 40 | } 41 | 42 | func put(_ key: Int, _ value: Int) { 43 | if let node = dict[key] { 44 | remove(node: node) 45 | } 46 | 47 | let newNode = Node(key: key, value: value) 48 | dict[key] = newNode 49 | add(node: newNode) 50 | 51 | if dict.count > capacity { 52 | let first = head.next! 53 | remove(node: first) 54 | dict.removeValue(forKey: first.key) 55 | } 56 | } 57 | 58 | private func add(node: Node) { 59 | let last = self.tail.prev! 60 | last.next = node 61 | node.prev = last 62 | node.next = tail 63 | tail.prev = node 64 | } 65 | 66 | private func remove(node: Node) { 67 | guard let prev = node.prev, let next = node.next else { 68 | return 69 | } 70 | 71 | prev.next = next 72 | next.prev = prev 73 | } 74 | } 75 | 76 | //: [Next](@next) 77 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/14_LongestCommonPrefix.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 14. 最长公共前缀 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/longest-common-prefix/ 9 | // 标签:字符串 10 | // 要点:字符串的扫描遍历,字符串API接口应用 11 | // 时间复杂度:O(N), N = 数组中字符串左右字符数总和 12 | // 空间复杂度:O(1) 13 | // 14 | 15 | class Solution { 16 | func longestCommonPrefix(_ strs: [String]) -> String { 17 | 18 | guard !strs.isEmpty else { return "" } 19 | 20 | var prefix = strs.first! 21 | for string in strs { 22 | // Think about hasPrefix vs. starts(with:) 23 | while !string.hasPrefix(prefix) { 24 | prefix = String(prefix.dropLast()) 25 | } 26 | } 27 | 28 | return prefix 29 | } 30 | } 31 | 32 | // Tests 33 | let s = Solution() 34 | s.longestCommonPrefix(["flower","flow","flight"]) == "fl" 35 | s.longestCommonPrefix(["dog","racecar","car"]) == "" 36 | 37 | //: [Next](@next) 38 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/150_EvaluateReversePolishNotation.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 150. 逆波兰表达式求值 5 | // 6 | // 根据逆波兰表示法,求表达式的值。 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ 9 | // 标签:栈、 10 | // 要点:操作数压栈、操作符出栈 11 | // 时间复杂度:O(N) 12 | // 空间复杂度:O( Int { 19 | enum Operator: String { 20 | case add = "+" 21 | case minus = "-" 22 | case multiply = "*" 23 | case divide = "/" 24 | 25 | func exec(left: Int, right: Int) -> Int { 26 | switch self { 27 | case .add: return left + right 28 | case .minus: return left - right 29 | case .multiply: return left * right 30 | case .divide: return left / right 31 | } 32 | } 33 | } 34 | 35 | var stack = [Int]() 36 | 37 | for token in tokens { 38 | if let op = Operator(rawValue: token) { 39 | guard let right = stack.popLast(), let left = stack.popLast() else { break } 40 | stack.append(op.exec(left: left, right: right)) 41 | } else if let num = Int(token) { 42 | stack.append(num) 43 | } 44 | } 45 | 46 | return stack.first! 47 | } 48 | } 49 | 50 | /// Tests 51 | let s = Solution() 52 | s.evalRPN(["2", "1", "+", "3", "*"]) == 9 53 | s.evalRPN(["4", "13", "5", "/", "+"]) == 6 54 | s.evalRPN(["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]) == 22 55 | 56 | //: [Next](@next) 57 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/151_ReverseWordsInString.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 151. 翻转字符串里的单词 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/reverse-words-in-a-string/ 7 | // 标签:字符串 8 | // 要点:以空字符进行拆分成数组->翻转->拼接 9 | // 时间复杂度:O(n) 10 | // 空间复杂度:O(1) 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func reverseWords(_ s: String) -> String { 17 | return s.split(separator: " ") 18 | .reversed() 19 | .joined(separator: " ") 20 | } 21 | } 22 | 23 | // Tests 24 | let s = Solution() 25 | assert(s.reverseWords("the sky is blue") == "blue is sky the") 26 | assert(s.reverseWords(" hello world! ") == "world! hello") 27 | assert(s.reverseWords("a good example") == "example good a") 28 | 29 | //: [Next](@next) 30 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/152_MaximumProductSubarray.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 152. 最大子序和 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/maximum-product-subarray/ 9 | // 标签:数组、分治算法、动态规划 10 | // 要点:贪心 11 | // 时间复杂度: O(n) 12 | // 空间复杂度: O(1) 13 | // 备注:与 53 题相似,不同点是,由于乘积在负数情况下存在差异,多记录一个最小乘积进行累乘 14 | // 15 | 16 | class Solution { 17 | func maxProduct(_ nums: [Int]) -> Int { 18 | let currentPruduct = nums.first ?? Int.min 19 | var maxProduct = currentPruduct 20 | var minProduct = currentPruduct 21 | var result = currentPruduct 22 | for current in 1.. Int { 40 | guard let e = _innerArray.last else { return -1 } 41 | return e 42 | } 43 | 44 | func getMin() -> Int { 45 | guard let min = _helperArray.last else { return -1 } 46 | return min 47 | } 48 | } 49 | 50 | // Tests 51 | let obj = MinStack() 52 | obj.push(-2) 53 | obj.push(0) 54 | obj.push(-3) 55 | obj.getMin() 56 | obj.pop() 57 | let ret_3: Int = obj.top() 58 | let ret_4: Int = obj.getMin() 59 | 60 | /** 61 | * Your MinStack object will be instantiated and called as such: 62 | * let obj = MinStack() 63 | * obj.push(x) 64 | * obj.pop() 65 | * let ret_3: Int = obj.top() 66 | * let ret_4: Int = obj.getMin() 67 | */ 68 | 69 | //: [Next](@next) 70 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/15_ThreeSum.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 15. 三数之和 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/longest-common-prefix/ 9 | // 题目描述: 10 | // - 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。 11 | // - 注意:答案中不可以包含重复的三元组。 12 | 13 | // 标签:数组、双指针 14 | // 要点:枚举数组并额外采用双指针进行判断 15 | // 时间复杂度:O(N^2) 16 | // 空间复杂度:O(logN) 17 | // 18 | 19 | class Solution { 20 | func threeSum(_ nums: [Int]) -> [[Int]] { 21 | 22 | if nums.count < 3 { return [] } 23 | 24 | let nums = nums.sorted(by: <) 25 | var res = [[Int]]() 26 | 27 | for i in 0.. 0 && nums[i] == nums[i - 1] { continue } 30 | 31 | var left = i + 1 32 | var right = nums.count - 1 33 | 34 | while left < right { 35 | let sum = nums[i] + nums[left] + nums[right] 36 | if sum < 0 { 37 | left += 1 38 | } else if sum > 0 { 39 | right -= 1 40 | } else { 41 | res.append([nums[i], nums[left], nums[right]]) 42 | while (left < right && nums[left] == nums[left + 1]) { 43 | left += 1 44 | } 45 | while (left < right && nums[right] == nums[right - 1]) { 46 | right -= 1 47 | } 48 | left += 1 49 | right -= 1 50 | } 51 | } 52 | } 53 | 54 | return res 55 | } 56 | } 57 | 58 | // Tests 59 | 60 | let s = Solution() 61 | s.threeSum([-1, 0, 1, 2, -1, -4]) == [[-1, -1, 2], [-1, 0, 1]] 62 | s.threeSum([0,0,0,0]) == [[0, 0, 0]] 63 | s.threeSum([-2,0,1,1,2]) == [[-2,0,2],[-2,1,1]] 64 | 65 | //: [Next](@next) 66 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/167_TwoSumII.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 167. 两数之和 II - 输入有序数组 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/ 7 | // 标签:数组、双指针、二分查找 8 | // 要点:指针碰撞,由于数组有序,采用一头一尾双指针,通过判断两数之和与目标值的关系,相向遍历数组 9 | // 时间复杂度:O(N) 10 | // 空间复杂度:O(1) 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func twoSum(_ numbers: [Int], _ target: Int) -> [Int] { 17 | var i = 0, j = numbers.count - 1 18 | 19 | while i < j { 20 | switch numbers[i] + numbers[j] { 21 | case target: return [i + 1, j + 1] 22 | case target...: j = j - 1 23 | default: i = i + 1 24 | } 25 | } 26 | return [] 27 | } 28 | } 29 | 30 | // Tests 31 | let s = Solution() 32 | s.twoSum([2, 7, 11, 15], 9) == [1, 2] 33 | 34 | //: [Next](@next) 35 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/16_3SumClosest.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func threeSumClosest(_ nums: [Int], _ target: Int) -> Int { 7 | let nums = nums.sorted(by: <) 8 | var minDiff = Int.max 9 | var res = 0 10 | 11 | for i in 0.. 0 && nums[i] == nums[i - 1] { continue } 14 | 15 | var left = i + 1 16 | var right = nums.count - 1 17 | 18 | while left < right { 19 | let sum = nums[i] + nums[left] + nums[right] 20 | // 绝对相等,提前返回 target 21 | if sum == target { return sum } 22 | 23 | let diff = abs(sum - target) 24 | if diff < minDiff { 25 | minDiff = diff 26 | res = sum 27 | } 28 | 29 | sum < target ? (left += 1) : (right -= 1) 30 | } 31 | } 32 | 33 | return res 34 | } 35 | } 36 | 37 | // Tests 38 | let s = Solution() 39 | s.threeSumClosest([-1,2,1,-4], 1) == 2 40 | 41 | //: [Next](@next) 42 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/1744_CanYouEatYourFavoriteCandyonYourFavoriteDay.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func canEat(_ candiesCount: [Int], _ queries: [[Int]]) -> [Bool] { 7 | // 前缀和 8 | let sums = candiesCount.reduce(into: [Int]()) { result, count in 9 | guard let lastSum = result.last else { 10 | result.append(count) 11 | return 12 | } 13 | result.append(lastSum + count) 14 | } 15 | 16 | let result = queries.map { query -> Bool in 17 | let (favoriteType, favoriteDay, dailyCap) = (query[0], query[1], query[2]) 18 | let x1 = favoriteDay + 1 19 | let y1 = (favoriteDay + 1) * dailyCap 20 | let x2 = favoriteType == 0 ? 1 : sums[favoriteType - 1] + 1 21 | let y2 = sums[favoriteType] 22 | 23 | return !(x1 > y2 || y1 < x2) 24 | } 25 | 26 | return result 27 | } 28 | } 29 | 30 | // Tests 31 | let solution = Solution() 32 | solution.canEat([7,4,5,3,8], [[0,2,2],[4,2,4],[2,13,1000000000]]) 33 | 34 | //: [Next](@next) 35 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/174_DungeonGame .xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func calculateMinimumHP(_ dungeon: [[Int]]) -> Int { 7 | guard !dungeon.isEmpty else { return -1 } 8 | let n = dungeon.count, m = dungeon[0].count 9 | var dp = [[Int]].init(repeating: [Int](repeating: .max, count: m + 1), count: n + 1) 10 | dp[n][m - 1] = 1 11 | dp[n - 1][m] = 1 12 | for i in (0.. Int { 7 | if nums.isEmpty { 8 | return 0 9 | } 10 | if nums.count == 1 { 11 | return nums[0] 12 | } 13 | let count = nums.count 14 | var dp = [Int].init(repeating: 0, count: count) 15 | dp[0] = nums[0] 16 | dp[1] = max(nums[0], nums[1]) 17 | for idx in 2.. ListNode? { 25 | let dummy = ListNode(0) 26 | dummy.next = head 27 | var fast: ListNode? = dummy 28 | var slow: ListNode? = dummy 29 | 30 | for _ in 0.. [Int] { 21 | // 利用哈希表(Dictionary)查找元素时间复杂度O(1)的特性 22 | var indexesDictionary = [Int: Index]() 23 | 24 | for (index, num) in nums.enumerated() { 25 | // 暂存字典中若存在target - num的键值对,即命中返回 26 | if let pairIndex = indexesDictionary[target - num] { 27 | return [pairIndex, index] 28 | } 29 | // 以『元素值』为Key,『元素索引』为Value暂存 30 | indexesDictionary[num] = index 31 | } 32 | 33 | return [] 34 | } 35 | } 36 | 37 | // Tests 38 | let s = Solution() 39 | assert(s.twoSum([2,7,11,15], 9) == [0, 1]) 40 | 41 | //: [Next](@next) 42 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/202_HappyNumber.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 202. 快乐数 7 | // 8 | // 编写一个算法来判断一个数 n 是不是快乐数。 9 | // 10 | // 题目链接:https://leetcode-cn.com/problems/happy-number/ 11 | // 标签:哈希表、快慢指针、数学 12 | // 要点:哈希表检测循环、数学规律 13 | // 时间复杂度:O(log(N)) 14 | // 空间复杂度: 15 | // * 哈希表:O(log(N)) 16 | // * 快慢指针: O(1) 17 | // * 数学: O(1) 18 | // 19 | 20 | class Solution { 21 | var numSet: Set = [] 22 | func isHappy(_ n: Int) -> Bool { 23 | var num = n 24 | var next = 0 25 | while num >= 1 { 26 | next += Int(pow(Double(num % 10), 2)) 27 | num /= 10 28 | } 29 | if next == 1 { return true } 30 | if numSet.contains(next) { return false } 31 | numSet.insert(next) 32 | return isHappy(next) 33 | } 34 | } 35 | 36 | class SolutionBy2Points { 37 | func isHappy(_ n: Int) -> Bool { 38 | var slow = n 39 | var fast = _getNext(n) 40 | while fast != 1 && slow != fast { 41 | slow = _getNext(slow) 42 | fast = _getNext(_getNext(fast)) 43 | } 44 | return fast == 1 45 | } 46 | 47 | private func _getNext(_ n: Int) -> Int { 48 | var num = n 49 | var next = 0 50 | while num >= 1 { 51 | next += Int(pow(Double(num % 10), 2)) 52 | num /= 10 53 | } 54 | return next 55 | } 56 | } 57 | 58 | class SolutionByMath { 59 | func isHappy(_ n: Int) -> Bool { 60 | var num = n 61 | var next = 0 62 | while num >= 1 { 63 | next += Int(pow(Double(num % 10), 2)) 64 | num /= 10 65 | } 66 | if next == 1 { return true } 67 | return next == 4 ? false : isHappy(next) 68 | } 69 | } 70 | 71 | // Tests 72 | 73 | let s = Solution() 74 | s.isHappy(19) == true 75 | 76 | let s2 = SolutionBy2Points() 77 | s2.isHappy(19) == true 78 | 79 | let s3 = SolutionByMath() 80 | s3.isHappy(19) == true 81 | 82 | //: [Next](@next) 83 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/203_RemoveLinkedListElements.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 203. 移除链表元素 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/remove-linked-list-elements 9 | // 标签:链表 10 | // 要点:设立哨兵节点,避免复杂的头尾判空处理 11 | // 时间复杂度:O(N) 12 | // 空间复杂度:O(1) 13 | // 14 | 15 | /// Definition for singly-linked list. 16 | public class ListNode { 17 | public var val: Int 18 | public var next: ListNode? 19 | public init(_ val: Int) { 20 | self.val = val 21 | self.next = nil 22 | } 23 | } 24 | 25 | class Solution { 26 | func removeElements(_ head: ListNode?, _ val: Int) -> ListNode? { 27 | let dummy = ListNode(0) 28 | dummy.next = head 29 | var (pre, cur) = (dummy, head) 30 | while cur != nil { 31 | if cur!.val == val { 32 | pre.next = cur!.next 33 | } else { 34 | pre = cur! 35 | } 36 | cur = cur?.next 37 | } 38 | return dummy.next 39 | } 40 | } 41 | 42 | //: [Next](@next) 43 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/206_ReverseList.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | /// Definition for singly-linked list. 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 reverseList(_ head: ListNode?) -> ListNode? { 17 | var pre: ListNode? 18 | var cur = head 19 | 20 | while cur != nil { 21 | let next = cur!.next 22 | cur!.next = pre 23 | pre = cur 24 | cur = next 25 | } 26 | 27 | return pre 28 | } 29 | } 30 | 31 | 32 | //: [Next](@next) 33 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/209_MinimumSizeSubarraySum.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 209. 长度最小的子数组 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum/ 7 | // 标签:数组、双指针、二分查找 8 | // 要点:定义一个 left 指针,另外定义一个 i 指针向前遍历,与此同时求和, 9 | // 当和大于目标值时,更新 res, 并将和减去 left 指针的值,left 指针前进一步 10 | // 时间复杂度:O(N) 11 | // 空间复杂度:O(1) 12 | // 13 | 14 | import Foundation 15 | 16 | class Solution { 17 | func minSubArrayLen(_ s: Int, _ nums: [Int]) -> Int { 18 | guard !nums.isEmpty else { return 0 } 19 | var left = 0, sum = 0, res = Int.max 20 | for i in 0..= s { 23 | res = min(res, i + 1 - left) 24 | sum -= nums[left] 25 | left += 1 26 | } 27 | } 28 | return res != Int.max ? res : 0 29 | } 30 | } 31 | 32 | // Tests 33 | let s = Solution() 34 | s.minSubArrayLen(7, [2,3,1,2,4,3]) == 2 35 | s.minSubArrayLen(4, [1, 4, 4]) == 1 36 | s.minSubArrayLen(11, [1, 2, 3, 4, 5]) == 3 37 | s.minSubArrayLen(15, [1, 2, 3, 4, 5]) == 5 38 | s.minSubArrayLen(6, [10,2,3]) == 1 39 | 40 | //: [Next](@next) 41 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/20_ValidParentheses.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 20. 有效的括号 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/valid-parentheses/ 7 | // 标签:栈、字符串 8 | // 要点:栈的特点,考虑入栈、出栈条件,以及最终有效性条件 9 | // 时间复杂度:O(N) 10 | // 空间复杂度:O(N) 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func isValid(_ s: String) -> Bool { 17 | var stack: [String] = [] 18 | let paren_pairs = [ 19 | ")":"(", 20 | "]": "[", 21 | "}": "{" 22 | ] 23 | for c in s { 24 | if !paren_pairs.keys.contains("\(c)") { 25 | stack.append("\(c)") 26 | } else if stack.isEmpty || paren_pairs["\(c)"] != stack.removeLast() { 27 | return false 28 | } 29 | } 30 | return stack.isEmpty 31 | } 32 | } 33 | 34 | //: [Next](@next) 35 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/210.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func findOrder(_ numCourses: Int, _ prerequisites: [[Int]]) -> [Int] { 7 | var edges = [[Int]](repeating: [], count: numCourses) 8 | var inDegree = [Int](repeating: 0, count: numCourses) 9 | var result = [Int]() 10 | 11 | 12 | for info in prerequisites { 13 | edges[info[1]].append(info[0]) 14 | inDegree[info[0]] += 1 15 | } 16 | 17 | var queue = [Int]() 18 | for (index, degree) in inDegree.enumerated() { 19 | if degree == 0 { 20 | queue.append(index) 21 | } 22 | } 23 | 24 | while !queue.isEmpty { 25 | let u = queue.removeFirst() 26 | result.append(u) 27 | for v in edges[u] { 28 | inDegree[v] -= 1 29 | if inDegree[v] == 0 { 30 | queue.append(v) 31 | } 32 | } 33 | } 34 | 35 | return result.count == numCourses ? result : [] 36 | } 37 | 38 | } 39 | 40 | // Test 41 | let s = Solution() 42 | s.findOrder(2, [[1, 0]]) == [0, 1] 43 | 44 | //: [Next](@next) 45 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/215_FindKthLargestInAnArray.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 215. 数组中的第K个最大元素 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/ 7 | // 标签:数组、多指针、快速排序 8 | // 要点:考察快速排序,基于怎么调效率都不如直接标准库sort一遍来得快,暂时先采用这个「笨」办法了 9 | // 另外,原地排序sort(by:)要比赋值排序sorted(by:)效率更快 10 | // 时间复杂度:O(NlogN),sort快排的复杂度 11 | // 空间复杂度:O(N) 12 | // 13 | 14 | import Foundation 15 | 16 | class Solution { 17 | func findKthLargest(_ nums: [Int], _ k: Int) -> Int { 18 | precondition(!nums.isEmpty && k > 0 && k <= nums.count) 19 | // return nums.sorted(by: >)[k - 1] 20 | var array = nums 21 | array.sort(by: >) 22 | return array[k - 1] 23 | } 24 | } 25 | 26 | // Tests 27 | let s = Solution() 28 | s.findKthLargest([3,2,1,5,6,4], 2) 29 | s.findKthLargest([3,2,3,1,2,4,5,5,6], 4) 30 | 31 | //: [Next](@next) 32 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/21_mergeTwoSortedLists.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 21. 合并两个有序链表 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/ 7 | // 标签:链表 8 | // 要点:递归 9 | // 时间复杂度:O(N+M) 10 | // 空间复杂度:O(N+M) 11 | // 12 | 13 | import Foundation 14 | 15 | /// Definition for singly-linked list. 16 | public class ListNode { 17 | public var val: Int 18 | public var next: ListNode? 19 | public init(_ val: Int) { 20 | self.val = val 21 | self.next = nil 22 | } 23 | } 24 | 25 | class Solution { 26 | func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { 27 | guard let l1 = l1 else { return l2 } 28 | guard let l2 = l2 else { return l1 } 29 | 30 | if l1.val < l2.val { 31 | l1.next = mergeTwoLists(l1.next, l2) 32 | return l1 33 | } else { 34 | l2.next = mergeTwoLists(l1, l2.next) 35 | return l2 36 | } 37 | } 38 | } 39 | 40 | //: [Next](@next) 41 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/221_MaximalSquare.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 221. 最大正方形 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/maximal-square/ 9 | // 标签:动态规划 10 | // 要点:明确状态转移方程,数组储存状态转移 11 | // dp(i,j)=min(dp(i−1,j),dp(i−1,j−1),dp(i,j−1))+1 12 | // 时间复杂度: O(M * N) 13 | // 空间复杂度: O(M * N) 14 | // 15 | 16 | class Solution { 17 | func maximalSquare(_ matrix: [[Character]]) -> Int { 18 | 19 | guard let first = matrix.first else { return 0 } 20 | 21 | var dp = matrix.map { row in row.map { _ in 0 } } 22 | var maximalSize = 0 23 | for i in 0.. Bool { 27 | if head == nil || head?.next == nil { 28 | return true 29 | } 30 | 31 | var slow = head 32 | var fast = head?.next 33 | 34 | var reHead: ListNode? // 用于翻转前半部分链表 35 | 36 | while fast != nil && fast?.next != nil { 37 | let temp = slow 38 | 39 | slow = slow?.next 40 | fast = fast?.next?.next 41 | 42 | temp?.next = reHead 43 | reHead = temp 44 | } 45 | 46 | if fast != nil { // 偶数 47 | fast = slow?.next 48 | slow?.next = reHead 49 | } else { 50 | fast = slow?.next 51 | slow = reHead 52 | } 53 | 54 | while fast != nil && slow != nil { 55 | if fast?.val != slow?.val { 56 | return false 57 | } 58 | fast = fast?.next 59 | slow = slow?.next 60 | } 61 | return true 62 | } 63 | } 64 | 65 | //: [Next](@next) 66 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/236_LowestCommonAncestorofaBinaryTree.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 236. 二叉树的最近公共祖先 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ 9 | // 标签:树 10 | // 要点:递归,理解并把握返回的终止条件 11 | // 时间复杂度: O(N) 12 | // 空间复杂度: O(N) 13 | // 14 | 15 | /// Definition for a binary tree node. 16 | public class TreeNode { 17 | public var val: Int 18 | public var left: TreeNode? 19 | public var right: TreeNode? 20 | public init(_ val: Int) { 21 | self.val = val 22 | self.left = nil 23 | self.right = nil 24 | } 25 | } 26 | 27 | 28 | class Solution { 29 | func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? { 30 | guard let root = root else { return nil } 31 | if root.val == p?.val || root.val == q?.val { return root } 32 | 33 | let left = lowestCommonAncestor(root.left, p, q) 34 | let right = lowestCommonAncestor(root.right, p, q) 35 | 36 | return left == nil ? right : (right == nil ? left : root) 37 | } 38 | } 39 | 40 | //: [Next](@next) 41 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/238_ProductofArrayExceptSelf.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func productExceptSelf(_ nums: [Int]) -> [Int] { 7 | var left = [Int](repeating: 1, count: nums.count) 8 | var right = [Int](repeating: 1, count: nums.count) 9 | 10 | for i in 1.. ListNode? { 27 | let dummy = ListNode(0) 28 | dummy.next = head 29 | var pre: ListNode? = dummy 30 | 31 | var head = head 32 | 33 | while head != nil { 34 | var tail = pre 35 | for _ in 0.. (head: ListNode?, tail: ListNode?) { 55 | var pre = tail?.next 56 | var cur = head 57 | 58 | while pre !== tail { 59 | let next = cur!.next 60 | cur?.next = pre 61 | pre = cur 62 | cur = next 63 | } 64 | 65 | return (tail, head) 66 | } 67 | } 68 | 69 | //: [Next](@next) 70 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/26_RemoveDuplicatesFromSortedArray.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 26. 删除排序数组中的重复项 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/ 7 | // 标签:数组、双指针 8 | // 要点:考察「数组变换」,使用双指针,一个遍历数组元素,一个在记录最后非重复项,移除后续(index+1)的原有项 9 | // 时间复杂度:O(n) 10 | // 空间复杂度:O(1) 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func removeDuplicates(_ nums: inout [Int]) -> Int { 17 | if nums.isEmpty { return 0 } 18 | 19 | var index = 0 20 | for i in 1 ..< nums.count { 21 | if nums[i] != nums[index] { 22 | index += 1 23 | nums[index] = nums[i] 24 | } 25 | } 26 | 27 | nums.removeSubrange((index + 1 ) ..< nums.count) 28 | 29 | return nums.count 30 | } 31 | } 32 | 33 | // Tests 34 | let s = Solution() 35 | var inputs = [1,1,2] 36 | assert(s.removeDuplicates(&inputs) == 2) 37 | assert(inputs == [1, 2]) 38 | 39 | //: [Next](@next) 40 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/274_H-Index.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 274. H指数 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/h-index/ 7 | // 标签:排序、哈希 8 | // 要点:逆序排序后遍历 9 | // 时间复杂度:O(nlog(n)) 10 | // 空间复杂度:O(1) 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func hIndex(_ citations: [Int]) -> Int { 16 | let sorted = citations.sorted(by: >) 17 | 18 | var i = 0 19 | while i < sorted.count && sorted[i] > i { 20 | i += 1 21 | } 22 | return i 23 | } 24 | } 25 | 26 | // Tests 27 | let s = Solution() 28 | assert(s.hIndex([3,0,6,1,5]) == 3) 29 | 30 | //: [Next](@next) 31 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/27_RemoveElement.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 27. 移除元素 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/remove-element/ 7 | // 标签:数组、双指针 8 | // 要点:考察「数组变换」,使用双指针,一个遍历数组元素,一个在记录最后非指定值的位置 9 | // 时间复杂度:O(n) 10 | // 空间复杂度:O(1) 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func removeElement(_ nums: inout [Int], _ val: Int) -> Int { 17 | if nums.isEmpty { return 0 } 18 | 19 | var index = 0 20 | for i in 0 ..< nums.count { 21 | if nums[i] != val { 22 | nums[index] = nums[i] 23 | index += 1 24 | } 25 | } 26 | 27 | nums.removeLast(nums.count - index) 28 | 29 | return nums.count 30 | } 31 | } 32 | 33 | // Tests 34 | let s = Solution() 35 | do { 36 | var input = [3,2,2,3] 37 | let newLength = s.removeElement(&input, 3) 38 | assert(input == [2, 2]) 39 | assert(newLength == 2) 40 | } 41 | 42 | //: [Next](@next) 43 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/283_MoveZeroes.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 283. 移动零 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/move-zeroes/ 7 | // 标签:数组、双指针 8 | // 要点:考察「数组变换」,使用双指针,一个遍历数组元素,一个在记录最后非零元素索引位置 9 | // 时间复杂度:O(n) 10 | // 空间复杂度:O(1) 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func moveZeroes(_ nums: inout [Int]) { 17 | if nums.isEmpty || nums.count == 1 { return } 18 | 19 | var index = 0 20 | for i in 0 ..< nums.count { 21 | if nums[i] != 0 { 22 | nums.swapAt(index, i) 23 | index += 1 24 | } 25 | } 26 | 27 | for i in (index.. Int { 7 | var slow = 0, fast = 0 8 | repeat { 9 | slow = nums[slow] 10 | fast = nums[nums[fast]] 11 | } while (slow != fast) 12 | slow = 0 13 | while slow != fast { 14 | slow = nums[slow] 15 | fast = nums[fast] 16 | } 17 | return slow 18 | } 19 | } 20 | 21 | // Tests 22 | let s = Solution() 23 | s.findDuplicate([1,3,4,2,2]) == 2 24 | s.findDuplicate([3,1,3,4,2]) == 3 25 | 26 | //: [Next](@next) 27 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/2_AddTwoNumbers.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 2. 两数相加 7 | // 给出两个非空的链表用来表示两个非负的整数。 8 | // 其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字。 9 | // 10 | // 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 11 | // 12 | // 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 13 | // 14 | // 题目链接:https://leetcode-cn.com/problems/add-two-numbers/ 15 | // 标签:链表 数学 16 | // 要点:加法数学在链表中的体现 17 | // 时间复杂度:O(max(M,N)) 18 | // 空间复杂度:O(max(M,N)) 19 | // 20 | 21 | /// Definition for singly-linked list. 22 | public class ListNode { 23 | public var val: Int 24 | public var next: ListNode? 25 | public init(_ val: Int) { 26 | self.val = val 27 | self.next = nil 28 | } 29 | } 30 | 31 | class Solution { 32 | func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { 33 | // 保存进位 34 | var carry = 0 35 | // 哨兵节点 36 | let dummy = ListNode(0) 37 | var node = dummy 38 | var l1 = l1 39 | var l2 = l2 40 | 41 | while l1 != nil || l2 != nil { 42 | let v1 = l1?.val ?? 0 43 | let v2 = l2?.val ?? 0 44 | // 两位相加再加进位 45 | let sum = v1 + v2 + carry 46 | carry = sum / 10 47 | node.next = ListNode(sum % 10) 48 | 49 | if l1 != nil { l1 = l1?.next } 50 | if l2 != nil { l2 = l2?.next } 51 | node = node.next! 52 | } 53 | // 最后一位加上必要的进位 54 | if carry > 0 { 55 | node.next = ListNode(carry) 56 | } 57 | return dummy.next 58 | } 59 | } 60 | 61 | //: [Next](@next) 62 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/309_BestTimetoBuyandSellStockwithCooldown.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func maxProfit(_ prices: [Int]) -> Int { 7 | guard !prices.isEmpty else { return 0 } 8 | var rest = 0 9 | var sold = 0 10 | var hold = Int.min 11 | for current in 0.. Int { 7 | guard !nums.isEmpty else { 8 | return 0 9 | } 10 | let nums = [1] + nums + [1] 11 | var table = [[Int]](repeating: [Int](repeating: 0, count: nums.count), count: nums.count) 12 | for len in 1...(nums.count - 2) { 13 | for i in 1...(nums.count - 1 - len) { 14 | let j = i + len - 1 15 | for k in i...j { 16 | table[i][j] = max( 17 | table[i][j], 18 | table[i][k - 1] + nums[i - 1] * nums[k] * nums[j + 1] + table[k + 1][j] 19 | ); 20 | } 21 | } 22 | } 23 | return table[1][nums.count - 2] 24 | } 25 | } 26 | 27 | //: [Next](@next) 28 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/315_CountofSmallerNumbersAfterSelf.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func countSmaller(_ nums: [Int]) -> [Int] { 7 | var counts: [Int] = [] 8 | for i in 0.. ListNode? { 27 | guard let head = head else { return nil } 28 | 29 | let evenHead = head.next 30 | var odd: ListNode? = head, even = evenHead 31 | 32 | while even != nil && even?.next != nil { 33 | odd?.next = even?.next 34 | odd = odd?.next 35 | even?.next = odd?.next 36 | even = even?.next 37 | } 38 | odd?.next = evenHead 39 | return head 40 | } 41 | } 42 | 43 | //: [Next](@next) 44 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/33_SearchinRotatedSortedArray.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 33. 搜索旋转排序数组 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/ 9 | // 标签:数组、二分查找 10 | // 要点:局部有序,边界细节的把控 11 | // 时间复杂度: O(logN) 12 | // 空间复杂度: O(1) 13 | // 14 | 15 | class Solution { 16 | func search(_ nums: [Int], _ target: Int) -> Int { 17 | return binarySearch(nums, target: target, range: nums.startIndex..) -> Int { 21 | 22 | guard range.endIndex > range.startIndex else { return -1 } 23 | 24 | let middle = nums.index(range.startIndex, offsetBy: (range.endIndex - range.startIndex) / 2) 25 | 26 | if nums[middle] == target { 27 | return middle 28 | } else if nums.first! <= nums[middle] { 29 | if target >= nums.first! && target < nums[middle] { 30 | return binarySearch(nums, target: target, range: range.startIndex.. nums[middle] && target <= nums.last! { 36 | return binarySearch(nums, target: target, range: (middle + 1).. Bool 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 | func getInteger() -> Int 18 | 19 | // Set this NestedInteger to hold a single integer. 20 | func setInteger(value: Int) 21 | 22 | // Set this NestedInteger to hold a nested list and adds a nested integer to it. 23 | func add(elem: NestedInteger) 24 | 25 | // Return the nested list that this NestedInteger holds, if it holds a nested list 26 | // The result is undefined if this NestedInteger holds a single integer 27 | func getList() -> [NestedInteger] 28 | } 29 | 30 | class NestedIterator { 31 | private var vals: [Int] = [] 32 | private var current: Int? 33 | 34 | init(_ nestedList: [NestedInteger]) { 35 | dfs(nestedList) 36 | current = vals.first 37 | } 38 | 39 | func next() -> Int { 40 | return vals.removeFirst() 41 | } 42 | 43 | func hasNext() -> Bool { 44 | return !vals.isEmpty 45 | } 46 | 47 | private func dfs(_ nestedList: [NestedInteger]) { 48 | for nest in nestedList { 49 | if nest.isInteger() { 50 | vals.append(nest.getInteger()) 51 | } else { 52 | dfs(nest.getList()) 53 | } 54 | } 55 | } 56 | } 57 | 58 | /** 59 | * Your NestedIterator object will be instantiated and called as such: 60 | * let obj = NestedIterator(nestedList) 61 | * let ret_1: Int = obj.next() 62 | * let ret_2: Bool = obj.hasNext() 63 | */ 64 | 65 | //: [Next](@next) 66 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/343_IntegerBreak.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func integerBreak(_ n: Int) -> Int { 7 | if n <= 3 { 8 | return n - 1 9 | } 10 | 11 | let numCount = n / 3 12 | let num = n % 3 13 | 14 | if num == 0 { 15 | return Int(pow(3.0, Double(numCount))) 16 | } else if num == 1 { 17 | return Int(pow(3.0, Double(numCount - 1))) * 4 18 | } else { 19 | return Int(pow(3.0, Double(numCount))) * 2 20 | } 21 | 22 | } 23 | } 24 | 25 | // Tests 26 | let s = Solution() 27 | s.integerBreak(2) == 1 28 | s.integerBreak(10) == 36 29 | 30 | //: [Next](@next) 31 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/345_ReverseVowelsOfAString.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 345. 翻转字符串中的元音字母 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/reverse-vowels-of-a-string/ 7 | // 标签:数组、双指针、对撞指针 8 | // 要点:指针碰撞,若不为元音则移动指针,每次迭代交换元音 9 | // 备注:isVowel的写法与效率 10 | // 时间复杂度:O(N) 11 | // 空间复杂度:O(1) 12 | // 13 | 14 | import Foundation 15 | 16 | class Solution { 17 | func reverseVowels(_ s: String) -> String { 18 | var chars = Array(s) 19 | var left = 0, right = chars.count - 1 20 | while left < right { 21 | while !chars[left].isVowel && left < right { 22 | left += 1 23 | } 24 | while !chars[right].isVowel && left < right { 25 | right -= 1 26 | } 27 | chars.swapAt(left, right) 28 | left += 1; right -= 1 29 | } 30 | return String(chars) 31 | } 32 | } 33 | 34 | extension Character { 35 | // Discussion: `["a", "e", "i", "o", "u"].contains(lowercased())`? 36 | // 写法更简洁但运行更慢: 180ms vs 88ms 37 | var isVowel: Bool { 38 | let lower = lowercased() 39 | return "a" == lower || "e" == lower || "i" == lower || "o" == lower || "u" == lower 40 | } 41 | } 42 | 43 | // Tests 44 | let s = Solution() 45 | s.reverseVowels("hello") == "holle" 46 | s.reverseVowels("leetcode") == "leotcede" 47 | 48 | //: [Next](@next) 49 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/350_IntersectionofTwoArraysII .xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func intersect(_ nums1: [Int], _ nums2: [Int]) -> [Int] { 7 | if nums1.count > nums2.count { 8 | return intersect(nums2, nums1) 9 | } 10 | var frenquencyMap = nums1.reduce([:]) { (res, num) -> [Int: Int] in 11 | var res = res 12 | if let count = res[num] { 13 | res[num] = count + 1 14 | } else { 15 | res[num] = 1 16 | } 17 | return res 18 | } 19 | var res = [Int]() 20 | for num in nums2 { 21 | if let count = frenquencyMap[num], count > 0 { 22 | res.append(num) 23 | frenquencyMap[num] = count - 1 24 | } 25 | } 26 | return res 27 | } 28 | } 29 | 30 | // Tests 31 | let s = Solution() 32 | s.intersect([1,2,2,1], [2,2]) == [2,2] 33 | s.intersect([4,9,5], [9,4,9,8,4]) == [4,9] 34 | 35 | //: [Next](@next) 36 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/35_SearchInsertPosition.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func searchInsert(_ nums: [Int], _ target: Int) -> Int { 7 | var left = 0, right = nums.count - 1 8 | var index = nums.count 9 | while left <= right { 10 | let mid = (right - left) >> 1 + left 11 | if target <= nums[mid] { 12 | index = mid 13 | right = mid - 1 14 | } else { 15 | left = mid + 1 16 | } 17 | } 18 | return index 19 | } 20 | } 21 | 22 | /// Tests 23 | let s = Solution() 24 | s.searchInsert([1,3,5,6], 5) == 2 25 | s.searchInsert([1,3,5,6], 2) == 1 26 | s.searchInsert([1,3,5,6], 7) == 4 27 | s.searchInsert([1,3,5,6], 0) == 0 28 | 29 | //: [Next](@next) 30 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/378_KthSmallestElementinaSortedMatrix.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func kthSmallest(_ matrix: [[Int]], _ k: Int) -> Int { 7 | return matrix.flatMap { $0 }.sorted()[k-1] 8 | } 9 | } 10 | 11 | //: [Next](@next) 12 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/392_IsSubsequence.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func isSubsequence(_ s: String, _ t: String) -> Bool { 7 | let sChars = [Character](s), tChars = [Character](t) 8 | let n = sChars.count, m = tChars.count 9 | var i = 0, j = 0 10 | while i < n && j < m { 11 | if sChars[i] == tChars[j] { 12 | i += 1 13 | } 14 | j += 1 15 | } 16 | return i == n 17 | } 18 | } 19 | 20 | // Tests 21 | let s = Solution() 22 | s.isSubsequence("abc", "ahbgdc") == true 23 | s.isSubsequence("axc", "ahbgdc") == false 24 | 25 | //: [Next](@next) 26 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/394_DecodeString.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func decodeString(_ s: String) -> String { 7 | if s.isEmpty { return s } 8 | 9 | var nums = [Int]() 10 | var decodedComponents = [String]() 11 | var decodingString = "" 12 | 13 | let charactors = [Character](s) 14 | var i = 0 15 | while i < charactors.count { 16 | if charactors[i].isNumber { 17 | var count = 0 18 | while charactors[i].isNumber { 19 | count = 10 * count + Int(String(charactors[i]))! 20 | i += 1 21 | } 22 | nums.append(count) 23 | } else if charactors[i] == "[" { 24 | decodedComponents.append(decodingString) 25 | decodingString = "" 26 | i += 1 27 | } else if charactors[i] == "]" { 28 | if var decodedComponent = decodedComponents.popLast(), let count = nums.popLast() { 29 | for _ in 0.. Int { 7 | var ns = nums 8 | let len = ns.count 9 | for i in 0.. 0 && num <= len && ns[num-1] > 0 { 18 | ns[num-1] *= -1 19 | } 20 | } 21 | 22 | for i in 0.. 0 { 24 | return i + 1 25 | } 26 | } 27 | return len + 1 28 | } 29 | } 30 | 31 | // Tests 32 | let s = Solution() 33 | s.firstMissingPositive([1, 2, 0]) == 3 34 | s.firstMissingPositive([3, 4, -1, 1]) == 2 35 | s.firstMissingPositive([7, 8, 9, 11, 12]) == 1 36 | 37 | //: [Next](@next) 38 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/44_WildcardMatching.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func isMatch(_ s: String, _ p: String) -> Bool { 7 | let sChars = [Character](s), pChars = [Character](p) 8 | var dp = [[Bool]](repeating: [Bool](repeating: false, count: p.count + 1), count: s.count + 1) 9 | 10 | dp[0][0] = true 11 | for i in 0...s.count { 12 | for j in 0...p.count { 13 | guard j > 0 else { continue } 14 | 15 | let pCur = pChars[j - 1] 16 | if pCur != "*" { 17 | dp[i][j] = i > 0 && dp[i - 1][j - 1] && (pCur == sChars[i - 1] || pCur == "?") 18 | } else { 19 | var flag = false 20 | for k in 0...i { 21 | if dp[k][j - 1] { 22 | flag = true 23 | break 24 | } 25 | } 26 | dp[i][j] = flag || j == 1 27 | } 28 | } 29 | } 30 | return dp[s.count][p.count] 31 | } 32 | } 33 | 34 | // Tests 35 | let s = Solution() 36 | s.isMatch("aa", "a") == false 37 | s.isMatch("aa", "*") == true 38 | 39 | //: [Next](@next) 40 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/45_JumpGameII.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 45. 跳跃游戏 II 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/jump-game-ii/ 7 | // 标签:数组、贪心算法 8 | // 要点:每次找可以到达的最远位置,不要访问最后一个元素避免不必要的一次跳跃 9 | // 时间复杂度: O(N) 10 | // 空间复杂度: O(1) 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func jump(_ nums: [Int]) -> Int { 17 | var maxPosition = 0 18 | var step = 0 19 | var stop = 0 20 | for i in 0.. [Int] { 16 | let m = matrix.count 17 | guard m > 0 else { return [] } 18 | let n = matrix[0].count 19 | guard n > 0 else { return [] } 20 | 21 | var res = [Int]() 22 | var x = 0 23 | var y = 0 24 | for _ in 0 ..< (m * n) { 25 | res.append(matrix[x][y]) 26 | if (x+y) % 2 == 0 { 27 | if y == n - 1 { 28 | x += 1 29 | } else if x == 0 { 30 | y += 1 31 | } else { 32 | x -= 1 33 | y += 1 34 | } 35 | } else { 36 | if x == m - 1 { 37 | y += 1 38 | } else if y == 0 { 39 | x += 1 40 | } else { 41 | x += 1 42 | y -= 1 43 | } 44 | } 45 | } 46 | 47 | return res 48 | } 49 | } 50 | 51 | // Tests 52 | let s = Solution() 53 | let matrix = [[ 1, 2, 3 ],[ 4, 5, 6 ],[ 7, 8, 9 ]] 54 | assert(s.findDiagonalOrder(matrix) == [1,2,4,7,5,3,6,8,9]) 55 | 56 | //: [Next](@next) 57 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/4_MedianofTwoSortedArrays.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 4. 寻找两个正序数组的中位数 7 | // 8 | // 给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。 9 | // 10 | // 请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。 11 | // 12 | // 你可以假设 nums1 和 nums2 不会同时为空。 13 | // 14 | // 题目链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/ 15 | // 标签:数组 二分查找 分治算法 16 | // 要点:递归二分查找,按奇偶区分中位数计算方式 17 | // 时间复杂度:O(log(m+n)) 18 | // 空间复杂度:O(1) 19 | // 20 | 21 | class Solution { 22 | func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { 23 | let count = nums1.count + nums2.count 24 | if count % 2 != 0 { 25 | return _findKth(nums1: nums1, nums2: nums2, k: count / 2 + 1) 26 | } else { 27 | return (_findKth(nums1: nums1, nums2: nums2, k: count / 2) 28 | + _findKth(nums1: nums1, nums2: nums2, k: count / 2 + 1)) 29 | / 2.0 30 | } 31 | } 32 | 33 | private func _findKth(nums1: [Int], nums2: [Int], k: Int) -> Double { 34 | let count1 = nums1.count 35 | let count2 = nums2.count 36 | guard count1 <= count2 else { 37 | return _findKth(nums1: nums2, nums2: nums1, k: k) 38 | } 39 | if count1 == 0 { 40 | return Double(nums2[k - 1]) 41 | } 42 | if k == 1 { 43 | return Double(min(nums1[0], nums2[0])) 44 | } 45 | // 划分下一个递归迭代 46 | let i = min(k / 2, count1) 47 | let j = min(k / 2, count2) 48 | 49 | if nums1[i - 1] < nums2[j - 1] { 50 | return _findKth(nums1: Array(nums1[i.. Double { 7 | return n >= 0 ? _helper(x, n: UInt64(n)) : 1.0 / _helper(x, n: UInt64(-n)) 8 | } 9 | 10 | private func _helper(_ x: Double, n: UInt64) -> Double { 11 | var res = 1.0 12 | var xContribute = x 13 | var n = n 14 | while n > 0 { 15 | if n % 2 == 1 { 16 | res = res * xContribute 17 | } 18 | xContribute *= xContribute 19 | n /= 2 20 | } 21 | return res 22 | } 23 | } 24 | 25 | //: [Next](@next) 26 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/53_MaximumSubarray.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 53. 最大子序和 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/maximum-subarray/ 9 | // 标签:数组、分治算法、动态规划 10 | // 要点:贪心 11 | // 时间复杂度: O(n) 12 | // 空间复杂度: O(1) 13 | // 备注:与 152 题相似 14 | // 15 | 16 | class Solution { 17 | func maxSubArray(_ nums: [Int]) -> Int { 18 | var currentSum = nums.first ?? Int.min 19 | var maxSum = currentSum 20 | for current in 1.. [Int] { 7 | if matrix.isEmpty { return [] } 8 | 9 | var res = [Int]() 10 | 11 | var startX = 0 12 | var endX = matrix.count - 1 13 | var startY = 0 14 | var endY = matrix[0].count - 1 15 | 16 | while true { 17 | // top 18 | for i in startY...endY { 19 | res.append(matrix[startX][i]) 20 | } 21 | startX += 1 22 | if startX > endX { 23 | break 24 | } 25 | 26 | // right 27 | for i in startX...endX { 28 | res.append(matrix[i][endY]) 29 | } 30 | endY -= 1 31 | if startY > endY { 32 | break 33 | } 34 | 35 | // bottom 36 | for i in stride(from: endY, through: startY, by: -1) { 37 | res.append(matrix[endX][i]) 38 | } 39 | endX -= 1 40 | if startX > endX { 41 | break 42 | } 43 | 44 | // left 45 | for i in stride(from: endX, through: startX, by: -1) { 46 | res.append(matrix[i][startY]) 47 | } 48 | startY += 1 49 | if startY > endY { 50 | break 51 | } 52 | } 53 | 54 | return res 55 | } 56 | } 57 | 58 | // Tests 59 | let s = Solution() 60 | let input1 = [ 61 | [ 1, 2, 3 ], 62 | [ 4, 5, 6 ], 63 | [ 7, 8, 9 ] 64 | ] 65 | assert(s.spiralOrder(input1) == [1,2,3,6,9,8,7,4,5]) 66 | 67 | //: [Next](@next) 68 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/560_SubarraySumEqualsK.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 560. 和为K的子数组 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/subarray-sum-equals-k/ 7 | // 标签:数组、哈希表 8 | // 要点:从暴力解法着手启发思路,借助哈希表缓存前缀和进行优化 9 | // 时间复杂度: O(N) 10 | // 空间复杂度: O(N) 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func subarraySum(_ nums: [Int], _ k: Int) -> Int { 17 | var count = 0 18 | var pre = 0 19 | var dict = [0: 1] 20 | for num in nums { 21 | pre += num 22 | if let value = dict[pre - k] { 23 | count += value 24 | } 25 | dict[pre] = (dict[pre] ?? 0) + 1 26 | } 27 | return count 28 | } 29 | } 30 | 31 | // Tests 32 | let s = Solution() 33 | s.subarraySum([1, 1, 1], 2) 34 | s.subarraySum([0,0,0,0,0,0,0,0,0,0], 0) 35 | 36 | //: [Next](@next) 37 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/5_LongestPalindromicSubstring.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // TODO: 没太掌握,待梳理 6 | class Solution { 7 | func longestPalindrome(_ s: String) -> String { 8 | guard s.count > 1 else { 9 | return s 10 | } 11 | 12 | let sChars = Array(s) 13 | var maxLen = 0, start = 0 14 | 15 | for i in 0..= 0 && r < chars.count && chars[l] == chars[r] { 27 | l -= 1 28 | r += 1 29 | } 30 | 31 | if maxLen < r - l - 1 { 32 | start = l + 1 33 | maxLen = r - l - 1 34 | } 35 | } 36 | } 37 | 38 | // Tests 39 | let s = Solution() 40 | s.longestPalindrome("babad") == "bab" 41 | s.longestPalindrome("cbbd") == "bb" 42 | 43 | //: [Next](@next) 44 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/61_RotateList.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 61. 旋转链表 5 | // 6 | // 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/rotate-list/ 9 | // 标签:链表、双指针 10 | // 要点:链表成环,区分判断好`head`与`tail` 11 | // 时间复杂度:O(N) 12 | // 空间复杂度:O(1) 13 | // 14 | 15 | import Foundation 16 | 17 | /// Definition for singly-linked list. 18 | public class ListNode { 19 | public var val: Int 20 | public var next: ListNode? 21 | public init(_ val: Int) { 22 | self.val = val 23 | self.next = nil 24 | } 25 | } 26 | 27 | class Solution { 28 | func rotateRight(_ head: ListNode?, _ k: Int) -> ListNode? { 29 | guard let head = head else { return nil } 30 | guard head.next != nil else { return head } 31 | 32 | var node = head 33 | var n = 1 34 | while node.next != nil { 35 | node = node.next! 36 | n += 1 37 | } 38 | node.next = head 39 | 40 | var newTail = head 41 | for _ in 0..<(n - k % n - 1) { 42 | newTail = newTail.next! 43 | } 44 | let newHead = newTail.next 45 | newTail.next = nil 46 | 47 | return newHead 48 | } 49 | } 50 | 51 | /** 52 | 示例1: 53 | ``` 54 | 输入: 1->2->3->4->5->NULL, k = 2 55 | 输出: 4->5->1->2->3->NULL 56 | 解释: 57 | 向右旋转 1 步: 5->1->2->3->4->NULL 58 | 向右旋转 2 步: 4->5->1->2->3->NULL 59 | ``` 60 | 示例 2: 61 | ``` 62 | 输入: 0->1->2->NULL, k = 4 63 | 输出: 2->0->1->NULL 64 | 解释: 65 | 向右旋转 1 步: 2->0->1->NULL 66 | 向右旋转 2 步: 1->2->0->NULL 67 | 向右旋转 3 步: 0->1->2->NULL 68 | 向右旋转 4 步: 2->0->1->NULL 69 | ``` 70 | */ 71 | 72 | //: [Next](@next) 73 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/63_UniquePathsII.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func uniquePathsWithObstacles(_ obstacleGrid: [[Int]]) -> Int { 7 | if obstacleGrid.isEmpty { 8 | return 0 9 | } 10 | 11 | let m = obstacleGrid.count, n = obstacleGrid.first!.count 12 | var dp = [[Int]](repeating: [Int](repeating: 0, count: n), count: m) 13 | for i in 0.. Int { 7 | precondition(!grid.isEmpty) 8 | let m = grid.count, n = grid[0].count 9 | var dp = [[Int]](repeating: [Int](repeating: Int.max, count: n + 1), count: m + 1) 10 | dp[m][n - 1] = 0; dp[m - 1][n - 1] = 0 11 | for i in (0.. [Int] { 16 | var _digits = digits 17 | for index in stride(from: _digits.count - 1, through: 0, by: -1) { 18 | _digits[index] += 1 19 | _digits[index] = _digits[index] % 10 20 | if _digits[index] != 0 { return _digits } 21 | } 22 | _digits = Array(repeating: 0, count: digits.count + 1) 23 | _digits[0] = 1 24 | return _digits 25 | } 26 | } 27 | 28 | // Tests 29 | let s = Solution() 30 | assert(s.plusOne([1, 2, 3]) == [1, 2, 4]) 31 | assert(s.plusOne([4,3,2,1]) == [4,3,2,2]) 32 | 33 | //: [Next](@next) 34 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/67_AddBinary.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 67. 二进制求和 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/add-binary/ 7 | // 标签:字符串 8 | // 要点:按位逆序遍历,异或相加,重点思考进位(carry)🤔 9 | // 时间复杂度:O(n) 10 | // 空间复杂度:O(n) 11 | // 注意:1. 转整数【Int(a, radix:2)】再相加的方案,无法处理溢出的情况 12 | // 2. Swift 中 String 不支持直接下标随机访问,需要先转为数组 13 | 14 | import Foundation 15 | 16 | class Solution { 17 | func addBinary(_ a: String, _ b: String) -> String { 18 | let aChars = Array(a), bChars = Array(b) 19 | var sum = 0, carry = 0, res = "" 20 | var i = aChars.count - 1, j = bChars.count - 1 21 | 22 | while i >= 0 || j >= 0 || carry > 0 { 23 | let bitA: Int = { 24 | if i < 0 { return 0 } 25 | defer { i -= 1 } 26 | return Int(String(aChars[i]))! 27 | }() 28 | let bitB: Int = { 29 | if j < 0 { return 0 } 30 | defer { j -= 1 } 31 | return Int(String(bChars[j]))! 32 | }() 33 | 34 | sum = bitA ^ bitB ^ carry 35 | carry = (bitA & bitB) | (carry & (bitA | bitB)) 36 | 37 | res = String(sum) + res 38 | } 39 | return res 40 | } 41 | } 42 | 43 | // Tests 44 | let s = Solution() 45 | assert(s.addBinary("11", "1") == "100") 46 | assert(s.addBinary("1010", "1011") == "10101") 47 | 48 | let bigA = "10100000100100110110010000010101111011011001101110111111111101000000101111001110001111100001101" 49 | let bigB = "110101001011101110001111100110001010100001101011101010000011011011001011101111001100000011011110011" 50 | let bigExpectation = "110111101100010011000101110110100000011101000101011001000011011000001100011110011010010011000000000" 51 | assert(s.addBinary(bigA, bigB) == bigExpectation) 52 | 53 | //: [Next](@next) 54 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/680_Valid_Palindrome_II.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func validPalindrome(_ s: String) -> Bool { 7 | if s.isEmpty { return true } 8 | if s.count < 3 { return true } 9 | 10 | let chars = [Character](s) 11 | var left = 0 12 | var right = s.count - 1 13 | 14 | while left < right { 15 | if chars[left] == chars[right] { 16 | left += 1 17 | right -= 1 18 | } else { 19 | func _valid(low: Int, high: Int) -> Bool { 20 | let mid = low + (high - low) / 2 21 | for i in low...mid { 22 | if chars[i] != chars[high - (i - low)] { 23 | return false 24 | } 25 | } 26 | return true 27 | } 28 | return _valid(low: left + 1, high: right) || _valid(low: left, high: right - 1) 29 | } 30 | } 31 | 32 | return true 33 | } 34 | } 35 | 36 | // Tests 37 | let s = Solution() 38 | s.validPalindrome("aba") == true 39 | s.validPalindrome("abca") == true 40 | s.validPalindrome("abc") == false 41 | s.validPalindrome("eeccccbebaeeabebccceea") == false 42 | s.validPalindrome("aguokepatgbnvfqmgmlcupuufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuupuculmgmqfvnbgtapekouga") == true 43 | 44 | //: [Next](@next) 45 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/695_MaxAreaofIsland.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 695. 岛屿的最大面积 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/max-area-of-island/ 9 | // 标签:数组、深度优先搜索 10 | // 要点:贪心 11 | // 时间复杂度: O(M * N) 12 | // 空间复杂度: O(M * N) 13 | // 14 | 15 | class Solution { 16 | func maxAreaOfIsland(_ grid: [[Int]]) -> Int { 17 | var maxArea = 0 18 | var grid = grid 19 | for (i, row) in grid.enumerated() { 20 | for j in 0.. Int { 28 | 29 | if row < 0 || column < 0 30 | || row == grid.count || column == grid[0].count 31 | || grid[row][column] != 1 { 32 | return 0 33 | } 34 | // 为了确保每个土地访问不超过一次,我们每次经过一块土地时,将这块土地的值置为 0。这样我们就不会多次访问同一土地。 35 | grid[row][column] = 0 36 | var area = 1 37 | for (i, j) in [(0, 1), (0, -1), (1, 0), (-1, 0)] { 38 | let nextRow = row + i 39 | let nextColumn = column + j 40 | area += backtrack(&grid, row: nextRow, column: nextColumn) 41 | } 42 | return area 43 | } 44 | } 45 | 46 | /// Tests 47 | let s = Solution() 48 | s.maxAreaOfIsland([ 49 | [0,0,1,0,0,0,0,1,0,0,0,0,0], 50 | [0,0,0,0,0,0,0,1,1,1,0,0,0], 51 | [0,1,1,0,1,0,0,0,0,0,0,0,0], 52 | [0,1,0,0,1,1,0,0,1,0,1,0,0], 53 | [0,1,0,0,1,1,0,0,1,1,1,0,0], 54 | [0,0,0,0,0,0,0,0,0,0,1,0,0], 55 | [0,0,0,0,0,0,0,1,1,1,0,0,0], 56 | [0,0,0,0,0,0,0,1,1,0,0,0,0] 57 | ]) == 6 58 | 59 | s.maxAreaOfIsland([[0,0,0,0,0,0,0,0]]) == 0 60 | 61 | //: [Next](@next) 62 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/70_ClimbingStairs.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func climbStairs(_ n: Int) -> Int { 7 | var p = 0, q = 0, r = 1 8 | for _ in 1...n { 9 | p = q 10 | q = r 11 | r = p + q 12 | } 13 | return r 14 | } 15 | 16 | } 17 | 18 | /// Tests 19 | let s = Solution() 20 | s.climbStairs(2) == 2 21 | s.climbStairs(3) == 3 22 | 23 | //: [Next](@next) 24 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/718_MaximumLengthofRepeatedSubarray.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func findLength(_ A: [Int], _ B: [Int]) -> Int { 7 | var res = 0 8 | var dp = [[Int]](repeating: [Int](repeating: 0, count: B.count + 1), count: A.count + 1) 9 | for i in (0.. String { 17 | /* Think about split implementation 18 | * link: https://github.com/apple/swift/blob/c1ab69e2db6922814111ff0bc3855f7bee0e18a6/stdlib/public/core/Collection.swift#L1527 19 | **/ 20 | let paths = path.split(separator: "/") 21 | 22 | var pathStack = [String]() 23 | 24 | for path in paths { 25 | guard path != ".", !path.isEmpty else { continue } 26 | 27 | if path == ".." { 28 | pathStack.popLast() 29 | } else { 30 | pathStack.append(String(path)) 31 | } 32 | } 33 | 34 | return "/" + pathStack.joined(separator: "/") 35 | } 36 | } 37 | 38 | // Tests 39 | let s = Solution() 40 | s.simplifyPath("/home/") == "/home" 41 | s.simplifyPath("/../") == "/" 42 | s.simplifyPath("/home//foo/") == "/home/foo" 43 | s.simplifyPath("/a/./b/../../c/") == "/c" 44 | s.simplifyPath("/a/../../b/../c//.//") == "/c" 45 | s.simplifyPath("/a//b////c/d//././/..") == "/a/b/c" 46 | 47 | //: [Next](@next) 48 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/724_FindPivotIndex.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 724. 寻找数组的中心索引 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/find-pivot-index/ 7 | // 标签:数组 8 | // 要点:两次遍历,一次求总和,一次渐进求和判断 9 | // 时间复杂度:O(n) 10 | // 空间复杂度:O(1) 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func pivotIndex(_ nums: [Int]) -> Int { 16 | // 求总和 17 | let sum = nums.reduce(0, +) 18 | var current = 0 19 | for (index, num) in nums.enumerated() { 20 | // 渐进求和判断 21 | if (sum - current - num) == current { return index } 22 | current += num 23 | } 24 | return -1 25 | } 26 | } 27 | 28 | // Tests 29 | let s = Solution() 30 | assert(s.pivotIndex([1, 7, 3, 6, 5, 6]) == 3) 31 | assert(s.pivotIndex([1, 2, 3]) == -1) 32 | 33 | //: [Next](@next) 34 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/739_DailyTemperatures.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 739. 每日温度 5 | // 6 | // 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/daily-temperatures/ 9 | // 标签:栈、哈希表 10 | // 要点:递减栈 11 | // 时间复杂度:O(N) 12 | // 空间复杂度:O(W),W 是 T[i] 的可取值数 13 | // 14 | 15 | import Foundation 16 | 17 | class Solution { 18 | func dailyTemperatures(_ T: [Int]) -> [Int] { 19 | var res = [Int](repeating: 0, count: T.count) 20 | var stack = [Int]() 21 | 22 | for i in 0.. T[stack.last!] { 24 | res[stack.last!] = i - stack.last! 25 | stack.popLast() 26 | } 27 | stack.append(i) 28 | } 29 | 30 | return res 31 | } 32 | } 33 | 34 | //: [Next](@next) 35 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/747_LargestNumberAtLeastTwiceofOthers.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 747. Largest Number At Least Twice of Others 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/largest-number-at-least-twice-of-others/submissions/ 7 | // 标签:数组 8 | // 要点:两次遍历,一次求总和,一次判断是否大于(除自身外)其他数两倍 9 | // 时间复杂度:O(n) 10 | // 空间复杂度:O(1) 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func dominantIndex(_ nums: [Int]) -> Int { 16 | var largest = 0, indexRes = 0 17 | for (index, num) in nums.enumerated() { 18 | if num > largest { 19 | largest = num 20 | indexRes = index 21 | } 22 | } 23 | for num in nums { 24 | if num == largest { continue } 25 | if largest < num * 2 { 26 | return -1 27 | } 28 | } 29 | return indexRes 30 | } 31 | } 32 | 33 | // Tests 34 | let s = Solution() 35 | assert(s.dominantIndex([3, 6, 1, 0]) == 1) 36 | assert(s.dominantIndex([1, 2, 3, 4]) == -1) 37 | 38 | //: [Next](@next) 39 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/75_SortColors.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 75. Sort Colors 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/sort-colors/ 7 | // 标签:数组、多指针 8 | // 要点:考察多指针的应用,一个指针指向「小端」,一个指针指向「大端」,一个指针遍历数组 9 | // 注意遍历指针交换时的动作,仅在与小端进行交换时前进,因为与大端交换过来的元素未遍历过 10 | // 时间复杂度:O(n) 11 | // 空间复杂度:O(1) 12 | // 13 | 14 | import Foundation 15 | 16 | class Solution { 17 | func sortColors(_ nums: inout [Int]) { 18 | if nums.isEmpty { return } 19 | 20 | var current = 0, little = 0, big = nums.count - 1 21 | while current <= big { 22 | if nums[current] == 0 { 23 | nums.swapAt(little, current) 24 | little += 1 25 | current += 1 26 | } else if nums[current] == 2 { 27 | nums.swapAt(big, current) 28 | big -= 1 29 | } else { 30 | current += 1 31 | } 32 | } 33 | } 34 | } 35 | 36 | // Tests 37 | let s = Solution() 38 | do { 39 | var input = [2,0,2,1,1,0] 40 | let expectOutput = [0,0,1,1,2,2] 41 | s.sortColors(&input) 42 | input 43 | assert(input == expectOutput) 44 | } 45 | 46 | do { 47 | var input = [1, 2, 0] 48 | let expectOutput = [0, 1, 2] 49 | s.sortColors(&input) 50 | input 51 | // assert(input == expectOutput) 52 | } 53 | 54 | 55 | //: [Next](@next) 56 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/76_MinimumWindowSubstring.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // TODO: 理解滑动窗口的思路 6 | class Solution { 7 | func minWindow(_ s: String, _ t: String) -> String { 8 | let sChars = Array(s), tChars = Array(t) 9 | var tFreq = Dictionary(tChars.map { ($0, 1) }, uniquingKeysWith: +) 10 | var left = 0, shortestLen = Int.max, start = 0, matters = 0 11 | 12 | for (i, sChar) in sChars.enumerated() { 13 | guard let sCharFreq = tFreq[sChar] else { 14 | continue 15 | } 16 | 17 | tFreq[sChar] = sCharFreq - 1 18 | 19 | if sCharFreq > 0 { 20 | matters += 1 21 | } 22 | 23 | while matters == tChars.count { 24 | guard let leftFreq = tFreq[sChars[left]] else { 25 | left += 1 26 | continue 27 | } 28 | 29 | if leftFreq == 0 { 30 | matters -= 1 31 | 32 | if i - left + 1 < shortestLen { 33 | shortestLen = i - left + 1 34 | start = left 35 | } 36 | 37 | } 38 | 39 | tFreq[sChars[left]] = leftFreq + 1 40 | left += 1 41 | } 42 | } 43 | 44 | return shortestLen == Int.max ? "" : String(sChars[start.. Bool { 7 | /// 图?啥?(并查集 8 | var friends = [Int](repeating: 0, count: graph.count) 9 | for i in 0 ..< friends.count { 10 | friends[i] = i 11 | } 12 | 13 | func find(_ x: Int) -> Int { 14 | return friends[x] == x ? x : find(friends[x]) 15 | } 16 | 17 | func merge(_ x: Int, _ y: Int) { 18 | let fx = find(x), fy = find(y) 19 | friends[fy] = friends[fx] 20 | } 21 | 22 | for table in graph { 23 | var pre = -1 24 | for neighbor in table { 25 | if pre != -1 { merge(pre, neighbor) } 26 | pre = neighbor 27 | } 28 | } 29 | 30 | for master in 0 ..< graph.count { 31 | for neighbor in graph[master] { 32 | if find(master) == find(neighbor) { return false } 33 | } 34 | } 35 | return true 36 | } 37 | } 38 | 39 | //: [Next](@next) 40 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/80_RemoveDuplicatesFromSortedArray_II.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 80. 删除排序数组中的重复项 II 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array-ii/ 7 | // 标签:数组、双指针 8 | // 要点:与 26 题类似,考察「数组变换」,使用双指针,一个遍历数组元素,一个在记录最后非重复项,移除后续(index+1)的原有项 9 | // 变化点在于双指针之间的「距离」,因此额外定义最多可出现次数,就可以直接拓展解决更多出现次数的类似问题 10 | // 时间复杂度:O(n) 11 | // 空间复杂度:O(1) 12 | // 13 | 14 | import Foundation 15 | 16 | private let duplicatesLimit = 2 17 | class Solution { 18 | func removeDuplicates(_ nums: inout [Int]) -> Int { 19 | if nums.count <= duplicatesLimit { return nums.count } 20 | 21 | var index = duplicatesLimit - 1 22 | for i in duplicatesLimit ..< nums.count { 23 | if nums[i] != nums[index - 1] { 24 | index += 1 25 | nums[index] = nums[i] 26 | } 27 | } 28 | 29 | nums.removeSubrange((index + 1 ) ..< nums.count) 30 | 31 | return nums.count 32 | } 33 | } 34 | 35 | // Tests 36 | let s = Solution() 37 | var input = [1,1,1,2,2,3] 38 | s.removeDuplicates(&input) == 6 39 | input == [1,1,2,2,3] 40 | 41 | //: [Next](@next) 42 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/837_New21Game.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func new21Game(_ N: Int, _ K: Int, _ W: Int) -> Double { 7 | // Warning: 没太搞懂,直接上题解先打卡吧 8 | guard N > 0 else { return 1.0 } 9 | guard W >= N - K else { return 1.0 } 10 | var dp = Array(repeating: 0.0, count: N + 1) 11 | dp[0] = 1 12 | let w = Double(W) 13 | var temp = 0.0 14 | for i in 1...N { 15 | if i <= K { 16 | temp += dp[i-1] / w 17 | } 18 | if i > W { 19 | temp -= dp[i-W-1] / w 20 | } 21 | dp[i] = temp 22 | } 23 | return dp[K...].reduce(0.0, +) 24 | } 25 | } 26 | 27 | // Tests 28 | let s = Solution() 29 | s.new21Game(10, 1, 10) == 1.0 30 | 31 | //: [Next](@next) 32 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/84_LargestRectangleinHistogram.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func largestRectangleArea(_ heights: [Int]) -> Int { 7 | if heights.isEmpty { 8 | return 0 9 | } 10 | let count = heights.count 11 | var left = [Int](repeating: 0, count: count) 12 | var right = [Int](repeating: count, count: count) 13 | var stack = [Int]() 14 | for i in 0..= heights[i] { 16 | right[top] = i 17 | stack.popLast() 18 | } 19 | left[i] = stack.last ?? -1 20 | stack.append(i) 21 | } 22 | 23 | var res = 0 24 | for i in 0.. String { 17 | var size = 0 18 | 19 | for char in S { 20 | if char.isNumber { 21 | guard let digit = Int(String(char)) else { fatalError() } 22 | size *= digit 23 | } else if char.isLetter { 24 | size += 1 25 | } else { 26 | return "" 27 | } 28 | } 29 | 30 | var magicK = K 31 | for char in S.reversed() { 32 | magicK %= size 33 | if magicK == 0 && char.isLetter { 34 | return String(char) 35 | } 36 | if char.isNumber { 37 | guard let digit = Int(String(char)) else { fatalError() } 38 | size /= digit 39 | } else { 40 | size -= 1 41 | } 42 | } 43 | 44 | return "" 45 | } 46 | } 47 | 48 | // Tests 49 | let s = Solution() 50 | assert(s.decodeAtIndex("leet2code3", 10) == "o") 51 | assert(s.decodeAtIndex("ha22", 5) == "h") 52 | assert(s.decodeAtIndex("a2345678999999999999999", 1) == "a") 53 | 54 | //: [Next](@next) 55 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/88_MergeSortedArray.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | // 4 | // 88. 合并两个有序数组 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/merge-sorted-array/ 7 | // 标签:数组、多指针 8 | // 要点:逆序遍历,避免拷贝增加不必要的空间复杂度 9 | // 注意使用双指针即可,以及避免用到 replaceSubrange(:with:) 10 | // 时间复杂度:O(M+N) 11 | // 空间复杂度:O(1) 12 | // 13 | 14 | import Foundation 15 | 16 | class Solution { 17 | func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) { 18 | var p1 = m - 1, p2 = n - 1 19 | while p1 >= 0 || p2 >= 0 { 20 | if p2 < 0 || (p1 >= 0 && nums1[p1] > nums2[p2]) { 21 | nums1[p1 + p2 + 1] = nums1[p1] 22 | p1 -= 1 23 | } else { 24 | nums1[p1 + p2 + 1] = nums2[p2] 25 | p2 -= 1 26 | } 27 | } 28 | } 29 | } 30 | 31 | // Tests 32 | let s = Solution() 33 | var nums1 = [1,2,3,0,0,0] 34 | s.merge(&nums1, 3, [2,5,6], 3) 35 | nums1 36 | 37 | //: [Next](@next) 38 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/93_RestoreIPAddresses.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 93. 复原IP地址 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/restore-ip-addresses/ 9 | // 标签:字符串 10 | // 要点:字符串的扫描遍历,回溯算法 11 | // 时间复杂度: 12 | // 空间复杂度: 13 | // 14 | 15 | class Solution { 16 | 17 | func restoreIpAddresses(_ s: String) -> [String] { 18 | guard s.count >= 4, s.count <= 12 else { return [] } 19 | var result = [String]() 20 | _backtrack(s, index: 0, segments: [], result: &result) 21 | return result 22 | } 23 | 24 | private func _backtrack(_ s: String, index: Int, segments: [String], result: inout [String]) { 25 | if index == s.count && segments.count == 4 { 26 | result.append(segments.joined(separator: ".")) 27 | return 28 | } 29 | 30 | let chars = [Character](s) 31 | for i in 1...3 { 32 | if index + i > s.count { continue } 33 | if i != 1 && chars[index] == "0" { continue } 34 | let segment = String(chars[index.. [TreeNode?] { 22 | let res = [TreeNode?]() 23 | if n == 0 { 24 | return res 25 | } 26 | return _generateTrees(start: 1, end: n) 27 | 28 | } 29 | 30 | private func _generateTrees(start:Int, end:Int) -> [TreeNode?]{ 31 | var res = [TreeNode?]() 32 | if start > end { 33 | res.append(nil) 34 | return res 35 | } 36 | if start == end { 37 | let tmp = TreeNode(start) 38 | res.append(tmp) 39 | return res 40 | } 41 | for i in start...end { 42 | let leftTrees = _generateTrees(start: start, end: i - 1) 43 | let rightTrees = _generateTrees(start: i + 1, end: end) 44 | for tmpLeft in leftTrees { 45 | for tmpRight in rightTrees { 46 | let root = TreeNode(i) 47 | root.left = tmpLeft 48 | root.right = tmpRight 49 | res.append(root) 50 | } 51 | } 52 | } 53 | return res 54 | } 55 | } 56 | 57 | //: [Next](@next) 58 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/96_UniqueBinarySearchTrees .xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | //return int(math.factorial(2*n)/math.factorial(n+1)/math.factorial(n)) 5 | //var str = "Hello, playground" 6 | 7 | class Solution { 8 | func numTrees(_ n: Int) -> Int { 9 | (0.. Int { 7 | var record = [0: 1] 8 | var sum = 0, res = 0 9 | for element in A { 10 | sum += element 11 | let m = (sum % K + K) % K 12 | if let count = record[m] { 13 | res += count 14 | } else { 15 | record[m] = 0 16 | } 17 | record[m]! += 1 18 | } 19 | return res 20 | } 21 | 22 | } 23 | 24 | // Tests 25 | let s = Solution() 26 | s.subarraysDivByK([4,5,0,-2,-3,1], 5) == 7 27 | 28 | //: [Next](@next) 29 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/983_MinimumCostForTickets.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 6 | // 983. 最低票价 7 | // 8 | // 题目链接:https://leetcode-cn.com/problems/minimum-cost-for-tickets/ 9 | // 标签:动态规划 10 | // 要点:明确状态转移方程,数组储存状态转移 11 | // dp(i)=min{cost(j)+dp(i+j)},j∈{1,7,30} 12 | // 时间复杂度: O(W), W 为最大旅行天数 13 | // 空间复杂度: O(W), W 为最大旅行天数 14 | // 15 | 16 | class Solution { 17 | func mincostTickets(_ days: [Int], _ costs: [Int]) -> Int { 18 | precondition(costs.count == 3) 19 | guard let last = days.last else { return 0 } 20 | var dp = [Int](repeating: 0, count: last + 1) 21 | var day = 0 22 | for i in 1.. Bool { 29 | return _validate(root) 30 | } 31 | 32 | private func _validate(_ node: TreeNode?, min: Int? = nil, max: Int? = nil) -> Bool { 33 | 34 | guard let node = node else { return true } 35 | 36 | if let min = min, node.val <= min { 37 | return false 38 | } 39 | if let max = max, node.val >= max { 40 | return false 41 | } 42 | return _validate(node.left, min: min, max: node.val) 43 | && _validate(node.right, min: node.val, max: max) 44 | } 45 | } 46 | 47 | //: [Next](@next) 48 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/990_SatisfiabilityofEqualityEquations.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func equationsPossible(_ equations: [String]) -> Bool { 7 | var parent = Array(repeating: 0, count: 26) 8 | for i in 0..<26 { 9 | parent[i] = i 10 | } 11 | for e in equations { 12 | let eArray = Array(e) 13 | if eArray[1] == "=" { 14 | _union(&parent, Int(eArray[0].asciiValue! - 97), Int(eArray[3].asciiValue! - 97)) 15 | } 16 | } 17 | 18 | for e in equations { 19 | let eArray = Array(e) 20 | if eArray[1] == "!" { 21 | let p1 = _find(parent, Int(eArray[0].asciiValue! - 97)) 22 | let p2 = _find(parent, Int(eArray[3].asciiValue! - 97)) 23 | if p1 == p2 { 24 | return false 25 | } 26 | } 27 | } 28 | 29 | return true 30 | } 31 | 32 | private func _union(_ parent: inout [Int], _ index1: Int, _ index2: Int) { 33 | let p1 = _find(parent, index1) 34 | let p2 = _find(parent, index2) 35 | parent[p1] = p2 36 | } 37 | 38 | private func _find(_ parent: [Int], _ index: Int) -> Int { 39 | var pIndex = index 40 | var p = parent 41 | while p[pIndex] != pIndex { 42 | let current = parent[pIndex] 43 | p[pIndex] = p[current] 44 | pIndex = current 45 | } 46 | return pIndex 47 | } 48 | } 49 | 50 | //: [Next](@next) 51 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/9_PalindromeNumber.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func isPalindrome(_ x: Int) -> Bool { 7 | guard x >= 0 else { return false } 8 | var nums = [Int]() 9 | var _x = x 10 | while _x != 0 { 11 | let num = _x % 10 12 | _x = _x / 10 13 | nums.append(num) 14 | } 15 | return _isPalindrome(nums: nums) 16 | } 17 | 18 | func _isPalindrome(nums: [Int]) -> Bool { 19 | guard !nums.isEmpty else { return true } 20 | var left = 0, right = nums.count - 1 21 | while left < right { 22 | if nums[left] != nums[right] { 23 | return false 24 | } 25 | left += 1 26 | right -= 1 27 | } 28 | return true 29 | } 30 | } 31 | 32 | /// Tests 33 | let s = Solution() 34 | s._isPalindrome(nums: [1, 2, 1]) == true 35 | s.isPalindrome(121) == true 36 | s.isPalindrome(-121) == false 37 | s.isPalindrome(10) == false 38 | 39 | //: [Next](@next) 40 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/剑指 Offer - 面试题29. 顺时针打印矩阵.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | // 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。 6 | // 注意:本题与主站 54 题相同:https://leetcode-cn.com/problems/spiral-matrix/ 7 | 8 | class Solution { 9 | func spiralOrder(_ matrix: [[Int]]) -> [Int] { 10 | if matrix.isEmpty { return [] } 11 | 12 | var res = [Int]() 13 | 14 | var startX = 0 15 | var endX = matrix.count - 1 16 | var startY = 0 17 | var endY = matrix[0].count - 1 18 | 19 | while true { 20 | // top 21 | for i in startY...endY { 22 | res.append(matrix[startX][i]) 23 | } 24 | startX += 1 25 | if startX > endX { 26 | break 27 | } 28 | 29 | // right 30 | for i in startX...endX { 31 | res.append(matrix[i][endY]) 32 | } 33 | endY -= 1 34 | if startY > endY { 35 | break 36 | } 37 | 38 | // bottom 39 | for i in stride(from: endY, through: startY, by: -1) { 40 | res.append(matrix[endX][i]) 41 | } 42 | endX -= 1 43 | if startX > endX { 44 | break 45 | } 46 | 47 | // left 48 | for i in stride(from: endX, through: startX, by: -1) { 49 | res.append(matrix[i][startY]) 50 | } 51 | startY += 1 52 | if startY > endY { 53 | break 54 | } 55 | } 56 | 57 | return res 58 | } 59 | } 60 | 61 | //: [Next](@next) 62 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/剑指 Offer - 面试题46. 把数字翻译成字符串.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | /// 与 93_RestoreIPAddresses 要解决的方式非常类似 6 | class Solution { 7 | func translateNum(_ num: Int) -> Int { 8 | var result = 0 9 | _backtrace(String(num), index: 0, segments: [], result: &result) 10 | return result 11 | } 12 | 13 | private func _backtrace(_ s: String, index: Int, segments: [String], result: inout Int) { 14 | if index == s.count { 15 | result += 1 16 | return 17 | } 18 | 19 | let chars = [Character](s) 20 | for i in 1...2 { 21 | if index + i > s.count { continue } 22 | if i != 1 && chars[index] == "0" { continue } 23 | let segment = String(chars[index.. Int { 11 | return (1...n).reduce(0, +) 12 | } 13 | } 14 | 15 | // Tests 16 | let s = Solution() 17 | s.sumNums(3) == 6 18 | s.sumNums(9) == 45 19 | 20 | //: [Next](@next) 21 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/剑指 Offer 09. 用两个栈实现队列.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class CQueue { 6 | 7 | var stack1: [Int] = [] 8 | var stack2: [Int] = [] 9 | 10 | init() { 11 | 12 | } 13 | 14 | func appendTail(_ value: Int) { 15 | stack1.append(value) 16 | } 17 | 18 | func deleteHead() -> Int { 19 | if stack2.isEmpty { 20 | while let head = stack1.popLast() { 21 | stack2.append(head) 22 | } 23 | } 24 | return stack2.popLast() ?? -1 25 | } 26 | } 27 | 28 | //: [Next](@next) 29 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/剑指 Offer 11. 旋转数组的最小数字.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func minArray(_ numbers: [Int]) -> Int { 7 | assert(!numbers.isEmpty) 8 | var left = 0, right = numbers.count - 1 9 | while left < right { 10 | let mid = left + (right - left) / 2 11 | if numbers[mid] < numbers[right] { 12 | right = mid 13 | } else if numbers[mid] > numbers[right] { 14 | left = mid + 1 15 | } else { 16 | right -= 1 17 | } 18 | } 19 | return numbers[left] 20 | } 21 | } 22 | 23 | /// Tests 24 | let s = Solution() 25 | s.minArray([3,4,5,1,2]) == 1 26 | s.minArray([2,2,2,0,1]) == 0 27 | s.minArray([1,3,3]) == 1 28 | s.minArray([1,3,3,1]) == 1 29 | s.minArray([3,3,1,3]) == 1 30 | 31 | //: [Next](@next) 32 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/程序员面试金典 - 面试题 02.01. 移除重复节点.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | 6 | /// Definition for singly-linked list. 7 | public class ListNode { 8 | public var val: Int 9 | public var next: ListNode? 10 | public init(_ val: Int) { 11 | self.val = val 12 | self.next = nil 13 | } 14 | } 15 | 16 | class Solution { 17 | func removeDuplicateNodes(_ head: ListNode?) -> ListNode? { 18 | guard let head = head else { return nil } 19 | 20 | var valSet: Set = [head.val] 21 | var node: ListNode? = head 22 | while node?.next != nil { 23 | if valSet.contains(node!.next!.val) { 24 | node?.next = node?.next?.next 25 | } else { 26 | valSet.insert(node!.next!.val) 27 | node = node?.next 28 | } 29 | } 30 | return head 31 | } 32 | } 33 | 34 | //: [Next](@next) 35 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/程序员面试金典 - 面试题 10.01. 合并排序的数组.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func merge(_ A: inout [Int], _ m: Int, _ B: [Int], _ n: Int) { 7 | guard m != 0 else { 8 | A = B 9 | return 10 | } 11 | guard n != 0 else { 12 | return 13 | } 14 | 15 | var a = m - 1 16 | var b = n - 1 17 | var cur = m + n - 1 18 | while b >= 0 { 19 | if a < 0 { 20 | A[cur] = B[b] 21 | b -= 1 22 | cur -= 1 23 | } else if A[a] >= B[b] { 24 | A[cur] = A[a]; 25 | a -= 1 26 | cur -= 1 27 | } else { 28 | A[cur] = B[b]; 29 | b -= 1 30 | cur -= 1 31 | } 32 | } 33 | } 34 | } 35 | 36 | // Tests 37 | let solution = Solution() 38 | var A = [1,2,3,0,0,0] 39 | solution.merge(&A, 3, [2,5,6], 3) 40 | A == [1,2,2,3,5,6] 41 | 42 | A = [0] 43 | solution.merge(&A, 0, [1], 1) 44 | A == [1] 45 | 46 | //: [Next](@next) 47 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/Pages/程序员面试金典 - 面试题 16.11. 跳水板.xcplaygroundpage/Contents.swift: -------------------------------------------------------------------------------- 1 | //: [Previous](@previous) 2 | 3 | import Foundation 4 | 5 | class Solution { 6 | func divingBoard(_ shorter: Int, _ longer: Int, _ k: Int) -> [Int] { 7 | if k == 0 { 8 | return [] 9 | } 10 | if shorter == longer { 11 | return [shorter * k] 12 | } 13 | /// 220ms & 26.1MB 14 | var lengths = [Int]() 15 | for i in 0...k { 16 | lengths.append(shorter * (k - i) + longer * i) 17 | } 18 | return lengths 19 | /// 376ms & 24.7MB 20 | // return (0...k).map { i in shorter * (k - i) + longer * i } 21 | } 22 | } 23 | 24 | // Tests 25 | let s = Solution() 26 | s.divingBoard(1, 2, 3) == [3, 4, 5, 6] 27 | 28 | //: [Next](@next) 29 | -------------------------------------------------------------------------------- /LeetCodePlayground.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LinkedList/024_SwapNodesInPairs.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 24. 两两交换链表中的节点 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs/ 5 | // 标签:链表 6 | // 要点:链表遍历, 递归 7 | // **** 上一次递归 -> head -> next -> 下一次递归 8 | // **** head -> 下一次递归结果,next -> head 9 | // 时间复杂度:O(n) 10 | // 空间复杂度:O(1) 11 | // 12 | 13 | import Foundation 14 | 15 | // Definition for singly-linked list. 16 | public class ListNode { 17 | public var val: Int 18 | public var next: ListNode? 19 | public init(_ val: Int) { 20 | self.val = val 21 | self.next = nil 22 | } 23 | } 24 | 25 | class Solution { 26 | func swapPairs(_ head: ListNode?) -> ListNode? { 27 | guard let wrappedHead = head, 28 | let next = wrappedHead.next else { 29 | return head 30 | } 31 | 32 | wrappedHead.next = swapPairs(next.next) 33 | next.next = wrappedHead 34 | return next 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LinkedList/19_RemoveNthNodeFromEndOfList.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 19. 删除链表的倒数第N个节点 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/ 6 | // 标签:链表、双指针 7 | // 要点:双指针,前一个指针快N个节点,借助dummy节点可有效避免判空 8 | // 时间复杂度:O(N) 9 | // 空间复杂度:O(1) 10 | // 11 | 12 | import Foundation 13 | 14 | class ListNode { 15 | var val: Int 16 | var next: ListNode? 17 | init(_ val: Int) { 18 | self.val = val 19 | } 20 | } 21 | 22 | class Solution { 23 | func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { 24 | let dummy = ListNode(0) 25 | dummy.next = head 26 | var fast: ListNode? = dummy 27 | var slow: ListNode? = dummy 28 | 29 | for _ in 0.. ListNode? { 23 | let dummy = ListNode(0) 24 | dummy.next = head 25 | var (pre, cur) = (dummy, head) 26 | while cur != nil { 27 | if cur!.val == val { 28 | pre.next = cur!.next 29 | } else { 30 | pre = cur! 31 | } 32 | cur = cur?.next 33 | } 34 | return dummy.next 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LinkedList/21_MergeTwoSortedLists.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 21. 合并两个有序链表 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/ 6 | // 标签:链表 7 | // 要点:递归 8 | // 时间复杂度:O(N+M) 9 | // 空间复杂度:O(N+M) 10 | // 11 | 12 | import Foundation 13 | 14 | /// Definition for singly-linked list. 15 | public class ListNode { 16 | public var val: Int 17 | public var next: ListNode? 18 | public init(_ val: Int) { 19 | self.val = val 20 | self.next = nil 21 | } 22 | } 23 | 24 | class Solution { 25 | func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { 26 | guard let l1 = l1 else { return l2 } 27 | guard let l2 = l2 else { return l1 } 28 | 29 | if l1.val < l2.val { 30 | l1.next = mergeTwoLists(l1.next, l2) 31 | return l1 32 | } else { 33 | l2.next = mergeTwoLists(l1, l2.next) 34 | return l2 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LinkedList/234_PalindromeLinkedList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 234. 回文链表 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/palindrome-linked-list/ 5 | // 标签:链表、双指针 6 | // 要点:快慢指针找到链表中间节点的同时,翻转前半部分链表 7 | // 时间复杂度:O(N) 8 | // 空间复杂度:O(1) 9 | // 10 | 11 | import Foundation 12 | 13 | /// Definition for singly-linked list. 14 | public class ListNode { 15 | public var val: Int 16 | public var next: ListNode? 17 | public init(_ val: Int) { 18 | self.val = val 19 | self.next = nil 20 | } 21 | } 22 | 23 | class Solution { 24 | func isPalindrome(_ head: ListNode?) -> Bool { 25 | if head == nil || head?.next == nil { 26 | return true 27 | } 28 | 29 | var slow = head 30 | var fast = head?.next 31 | 32 | var reHead: ListNode? // 用于翻转前半部分链表 33 | 34 | while fast != nil && fast?.next != nil { 35 | let temp = slow 36 | 37 | slow = slow?.next 38 | fast = fast?.next?.next 39 | 40 | temp?.next = reHead 41 | reHead = temp 42 | } 43 | 44 | if fast != nil { // 偶数 45 | fast = slow?.next 46 | slow?.next = reHead 47 | } else { 48 | fast = slow?.next 49 | slow = reHead 50 | } 51 | 52 | while fast != nil && slow != nil { 53 | if fast?.val != slow?.val { 54 | return false 55 | } 56 | fast = fast?.next 57 | slow = slow?.next 58 | } 59 | return true 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /LinkedList/25_ReverseNodesink-Group.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 25. K 个一组翻转链表 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/ 6 | // 标签:链表 7 | // 要点:与翻转链表类似,考虑清楚细节,注重细节处理的设计,善用哨兵节点 8 | // 时间复杂度:O(N) 9 | // 空间复杂度:O(1) 10 | // 11 | 12 | /// Definition for singly-linked list. 13 | public class ListNode { 14 | public var val: Int 15 | public var next: ListNode? 16 | public init(_ val: Int) { 17 | self.val = val 18 | self.next = nil 19 | } 20 | } 21 | 22 | class Solution { 23 | func reverseKGroup(_ head: ListNode?, _ k: Int) -> ListNode? { 24 | let dummy = ListNode(0) 25 | dummy.next = head 26 | var pre: ListNode? = dummy 27 | 28 | var head = head 29 | 30 | while head != nil { 31 | var tail = pre 32 | for _ in 0.. (head: ListNode?, tail: ListNode?) { 52 | var pre = tail?.next 53 | var cur = head 54 | 55 | while pre !== tail { 56 | let next = cur!.next 57 | cur?.next = pre 58 | pre = cur 59 | cur = next 60 | } 61 | 62 | return (tail, head) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /LinkedList/2_AddTwoNumbers.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 2. 两数相加 4 | // 给出两个非空的链表用来表示两个非负的整数。 5 | // 其中,它们各自的位数是按照逆序的方式存储的,并且它们的每个节点只能存储一位数字。 6 | // 7 | // 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 8 | // 9 | // 您可以假设除了数字 0 之外,这两个数都不会以 0 开头。 10 | // 11 | // 题目链接:https://leetcode-cn.com/problems/add-two-numbers/ 12 | // 标签:链表 数学 13 | // 要点:加法数学在链表中的体现 14 | // 时间复杂度:O(max(M,N)) 15 | // 空间复杂度:O(max(M,N)) 16 | // 17 | 18 | /// Definition for singly-linked list. 19 | public class ListNode { 20 | public var val: Int 21 | public var next: ListNode? 22 | public init(_ val: Int) { 23 | self.val = val 24 | self.next = nil 25 | } 26 | } 27 | 28 | class Solution { 29 | func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { 30 | // 保存进位 31 | var carry = 0 32 | // 哨兵节点 33 | let dummy = ListNode(0) 34 | var node = dummy 35 | var l1 = l1 36 | var l2 = l2 37 | 38 | while l1 != nil || l2 != nil { 39 | let v1 = l1?.val ?? 0 40 | let v2 = l2?.val ?? 0 41 | // 两位相加再加进位 42 | let sum = v1 + v2 + carry 43 | carry = sum / 10 44 | node.next = ListNode(sum % 10) 45 | 46 | if l1 != nil { l1 = l1?.next } 47 | if l2 != nil { l2 = l2?.next } 48 | node = node.next! 49 | } 50 | // 最后一位加上必要的进位 51 | if carry > 0 { 52 | node.next = ListNode(carry) 53 | } 54 | return dummy.next 55 | } 56 | } -------------------------------------------------------------------------------- /LinkedList/328_OddEvenLinkedList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 328. 奇偶链表 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/odd-even-linked-list/ 5 | // 标签:链表 6 | // 要点:多指针,遍历原链表,将其奇偶节点分别放入两个链表,并将偶链表链接在奇链表尾部 7 | // 时间复杂度:O(N) 8 | // 空间复杂度:O(1) 9 | // 10 | 11 | import Foundation 12 | 13 | /// Definition for singly-linked list. 14 | public class ListNode { 15 | public var val: Int 16 | public var next: ListNode? 17 | public init(_ val: Int) { 18 | self.val = val 19 | self.next = nil 20 | } 21 | } 22 | 23 | class Solution { 24 | func oddEvenList(_ head: ListNode?) -> ListNode? { 25 | guard let head = head else { return nil } 26 | 27 | let evenHead = head.next 28 | var odd: ListNode? = head, even = evenHead 29 | 30 | while even != nil && even?.next != nil { 31 | odd?.next = even?.next 32 | odd = odd?.next 33 | even?.next = odd?.next 34 | even = even?.next 35 | } 36 | odd?.next = evenHead 37 | return head 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LinkedList/61_RotateList.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 61. 旋转链表 4 | // 5 | // 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。 6 | // 7 | // 题目链接:https://leetcode-cn.com/problems/rotate-list/ 8 | // 标签:链表、双指针 9 | // 要点:链表成环,区分判断好`head`与`tail` 10 | // 时间复杂度:O(N) 11 | // 空间复杂度:O(1) 12 | // 13 | 14 | import Foundation 15 | 16 | /// Definition for singly-linked list. 17 | public class ListNode { 18 | public var val: Int 19 | public var next: ListNode? 20 | public init(_ val: Int) { 21 | self.val = val 22 | self.next = nil 23 | } 24 | } 25 | 26 | class Solution { 27 | func rotateRight(_ head: ListNode?, _ k: Int) -> ListNode? { 28 | guard let head = head else { return nil } 29 | guard head.next != nil else { return head } 30 | 31 | var node = head 32 | var n = 1 33 | while node.next != nil { 34 | node = node.next! 35 | n += 1 36 | } 37 | node.next = head 38 | 39 | var newTail = head 40 | for _ in 0..<(n - k % n - 1) { 41 | newTail = newTail.next! 42 | } 43 | let newHead = newTail.next 44 | newTail.next = nil 45 | 46 | return newHead 47 | } 48 | } 49 | 50 | /** 51 | 示例1: 52 | ``` 53 | 输入: 1->2->3->4->5->NULL, k = 2 54 | 输出: 4->5->1->2->3->NULL 55 | 解释: 56 | 向右旋转 1 步: 5->1->2->3->4->NULL 57 | 向右旋转 2 步: 4->5->1->2->3->NULL 58 | ``` 59 | 示例 2: 60 | ``` 61 | 输入: 0->1->2->NULL, k = 4 62 | 输出: 2->0->1->NULL 63 | 解释: 64 | 向右旋转 1 步: 2->0->1->NULL 65 | 向右旋转 2 步: 1->2->0->NULL 66 | 向右旋转 3 步: 0->1->2->NULL 67 | 向右旋转 4 步: 2->0->1->NULL 68 | ``` 69 | */ 70 | -------------------------------------------------------------------------------- /LinkedList/README.md: -------------------------------------------------------------------------------- 1 | # 链表 2 | 3 | ## 各种链表结构 4 | 5 | * 底层的储存结构 6 | * 数组:连续的内存空间 7 | * 链表:通过「指针」将一组**零散的内存块**串联 8 | 9 | [配图] 10 | 11 | * 单链表 12 | * 结点 13 | * 头结点 14 | * 尾结点 15 | * 后继指针`next` 16 | * 插入与删除操作,只需考虑相邻结点的指针改变,**时间复杂度O(1)** 17 | * 随机访问性能没有数组好,**时间复杂度O(n)** 18 | 19 | 20 | [配图] 21 | 22 | * 循环链表 23 | * 尾结点指向链表的头结点 24 | * [约瑟夫问题](https://zh.wikipedia.org/wiki/%E7%BA%A6%E7%91%9F%E5%A4%AB%E6%96%AF%E9%97%AE%E9%A2%98) 25 | 26 | [配图] 27 | 28 | * 双向链表 29 | * 实际开发中较为常用 30 | * 支持两个方向 31 | * 有一个后继指针 next 指向后面的结点 32 | * 还有一个前驱指针 prev 指向前面的结点 33 | * 删除、插入操作优势,**时间复杂度O(1)** 34 | * 双向链表有什么优势?适合解决哪种问题? 35 | * 有序链表按值查找效率更高 36 | * 删除、查找操作 37 | * 典型的**以空间换时间**的设计思想 38 | 39 | [配图] 40 | 41 | * 双向·循环列表 42 | 43 | [配图] 44 | 45 | 46 | 47 | ## 链表与数组性能对比 48 | 49 | * 数组 50 | * 简单易用、连续内存空间可利用 CPU 缓存机制,访问效率更高 51 | * 缺点是大小固定,一经声明就要占用整块连续空间 52 | * 对内存使用非常苛刻,更适合用数组,避免额外消耗和内存碎片 53 | * 链表 54 | * 在内存中不连续,对 CPU 缓存机制不友好,无法有效预读 55 | * 本身没有大小限制,天然支持动态扩容 56 | * 每个结点需要额外的内存空间,频繁插入、删除易造成内存碎片 57 | 58 | 59 | 60 | ## 如何基于链表实现 LRU 缓存淘汰算法 61 | 62 | 维护一个有序单链表,越靠近链表尾部的节点是越早之前访问的,当有一个新的数据被访问时,从链表头开始顺序遍历链表 63 | 64 | 1. 如果此数据之前已经被缓存在链表中了,遍历得到这个数据对应的结点,并将其从原有位置删除,插入到链表的头部 65 | 66 | 2. 如果此数据没有在缓存链表中,又分为两种情况: 67 | 68 | 1. 若缓存未满,则将此结点直接插入链表头部 69 | 70 | 2. 若缓存已满,则链表尾结点删除,将新的数据结点插入链表的头部 71 | 72 | > Tips: 后续采用散列表 HashMap 优化 73 | 74 | ## 链表经典问题练习小结 75 | 76 | 1. 通过一些测试用例可以节省一些时间 77 | 使用链表时不易调试。因此,在编写代码之前,尝试几个不同的示例来验证是很有帮助的。 78 | 79 | 2. 可以同时使用多个指针 80 | 有时,当一个链表问题不易解决时,可能需要同时使用多个结点指针。记住需要个跟踪的结点,并采用几个不同的结点指针。指针应当采用有意义的变量名。 81 | 82 | 3. 很多时候,需要额外跟踪记录当前结点的前序结点 83 | 单链表无法追溯前一个结点,因此,许多时候储存前一个结点时,也要同时储存前一个结点。这和双链表不同。 -------------------------------------------------------------------------------- /Sort/SortingAlgorithms.swift: -------------------------------------------------------------------------------- 1 | 2 | // 冒泡排序 3 | func bubbleSort(_ array: inout [Element]) { 4 | guard array.count >= 2 else { return } 5 | 6 | for end in (1..(_ array: inout [Element]) { 20 | guard array.count >= 2 else { return } 21 | 22 | for current in 0..(_ array: inout [Element]) { 37 | guard array.count >= 2 else { return } 38 | 39 | for current in 1.. Bool { 15 | var stack = [Character]() 16 | for char in S { 17 | if char == "c" { 18 | if stack.popLast() != "b" { 19 | return false 20 | } 21 | if stack.popLast() != "a" { 22 | return false 23 | } 24 | } else { 25 | stack.append(char) 26 | } 27 | } 28 | return stack.isEmpty 29 | } 30 | } 31 | 32 | // Tests 33 | let s = Solution() 34 | assert(s.isValid("aabcbc")) 35 | assert(s.isValid("abcabcababcc")) 36 | assert(!s.isValid("abccba")) 37 | assert(!s.isValid("cababc")) 38 | -------------------------------------------------------------------------------- /Stack/150_EvaluateReversePolishNotation.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 150. 逆波兰表达式求值 4 | // 5 | // 根据逆波兰表示法,求表达式的值。 6 | // 7 | // 题目链接:https://leetcode-cn.com/problems/evaluate-reverse-polish-notation/ 8 | // 标签:栈、 9 | // 要点:操作数压栈、操作符出栈 10 | // 时间复杂度:O(N) 11 | // 空间复杂度:O( Int { 18 | enum Operator: String { 19 | case add = "+" 20 | case minus = "-" 21 | case multiply = "*" 22 | case divide = "/" 23 | 24 | func exec(left: Int, right: Int) -> Int { 25 | switch self { 26 | case .add: return left + right 27 | case .minus: return left - right 28 | case .multiply: return left * right 29 | case .divide: return left / right 30 | } 31 | } 32 | } 33 | 34 | var stack = [Int]() 35 | 36 | for token in tokens { 37 | if let op = Operator(rawValue: token) { 38 | guard let right = stack.popLast(), let left = stack.popLast() else { break } 39 | stack.append(op.exec(left: left, right: right)) 40 | } else if let num = Int(token) { 41 | stack.append(num) 42 | } 43 | } 44 | 45 | return stack.first! 46 | } 47 | } 48 | 49 | /// Tests 50 | let s = Solution() 51 | s.evalRPN(["2", "1", "+", "3", "*"]) == 9 52 | s.evalRPN(["4", "13", "5", "/", "+"]) == 6 53 | s.evalRPN(["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]) == 22 54 | -------------------------------------------------------------------------------- /Stack/155_MinStack.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 155. 最小栈 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/min-stack/ 5 | // 标签:栈、设计 6 | // 要点:除数据栈外,额外利用一个**辅助栈**放最小值,在 Swift 中采用数组实现 7 | // 时间复杂度:O(1) 8 | // 空间复杂度:O(N) 9 | // 10 | 11 | class MinStack { 12 | 13 | private var _innerArray: [Int] 14 | private var _helperArray: [Int] 15 | 16 | /** initialize your data structure here. */ 17 | init() { 18 | _innerArray = [] 19 | _helperArray = [] 20 | } 21 | 22 | func push(_ x: Int) { 23 | _innerArray.append(x) 24 | if _helperArray.isEmpty || x <= _helperArray.last! { 25 | _helperArray.append(x) 26 | } else if let last = _helperArray.last { 27 | _helperArray.append(last) 28 | } 29 | } 30 | 31 | func pop() { 32 | if let _ = _innerArray.popLast() { 33 | _helperArray.popLast() 34 | } 35 | } 36 | 37 | func top() -> Int { 38 | guard let e = _innerArray.last else { return -1 } 39 | return e 40 | } 41 | 42 | func getMin() -> Int { 43 | guard let min = _helperArray.last else { return -1 } 44 | return min 45 | } 46 | } 47 | 48 | // Tests 49 | let obj = MinStack() 50 | obj.push(-2) 51 | obj.push(0) 52 | obj.push(-3) 53 | obj.getMin() 54 | obj.pop() 55 | let ret_3: Int = obj.top() 56 | let ret_4: Int = obj.getMin() 57 | 58 | /** 59 | * Your MinStack object will be instantiated and called as such: 60 | * let obj = MinStack() 61 | * obj.push(x) 62 | * obj.pop() 63 | * let ret_3: Int = obj.top() 64 | * let ret_4: Int = obj.getMin() 65 | */ 66 | -------------------------------------------------------------------------------- /Stack/20_ValidParentheses.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 20. 有效的括号 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/valid-parentheses/ 6 | // 标签:栈、字符串 7 | // 要点:栈的特点,考虑入栈、出栈条件,以及最终有效性条件 8 | // 时间复杂度:O(N) 9 | // 空间复杂度:O(N) 10 | // 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func isValid(_ s: String) -> Bool { 16 | var stack: [String] = [] 17 | let paren_pairs = [ 18 | ")":"(", 19 | "]": "[", 20 | "}": "{" 21 | ] 22 | for c in s { 23 | if !paren_pairs.keys.contains("\(c)") { 24 | stack.append("\(c)") 25 | } else if stack.isEmpty || paren_pairs["\(c)"] != stack.removeLast() { 26 | return false 27 | } 28 | } 29 | return stack.isEmpty 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Stack/71_SimplifyPath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 71. 简化路径 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/simplify-path/ 5 | // 标签:栈、字符串 6 | // 要点:根据题意,考虑清楚出入栈条件,以及跳过逻辑 7 | // 时间复杂度:O(N) 8 | // 空间复杂度:O(N) 9 | // 10 | 11 | import Foundation 12 | 13 | class Solution { 14 | func simplifyPath(_ path: String) -> String { 15 | let paths = path.split(separator: "/") 16 | 17 | var pathStack = [String]() 18 | 19 | for path in paths { 20 | guard path != ".", !path.isEmpty else { continue } 21 | 22 | if path == ".." { 23 | pathStack.popLast() 24 | } else { 25 | pathStack.append(String(path)) 26 | } 27 | } 28 | 29 | return "/" + pathStack.joined(separator: "/") 30 | } 31 | } 32 | 33 | // Tests 34 | let s = Solution() 35 | s.simplifyPath("/home/") == "/home" 36 | s.simplifyPath("/../") == "/" 37 | s.simplifyPath("/home//foo/") == "/home/foo" 38 | s.simplifyPath("/a/./b/../../c/") == "/c" 39 | s.simplifyPath("/a/../../b/../c//.//") == "/c" 40 | s.simplifyPath("/a//b////c/d//././/..") == "/a/b/c" 41 | -------------------------------------------------------------------------------- /Stack/739_DailyTemperatures.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 739. 每日温度 3 | // 4 | // 根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。 5 | // 6 | // 题目链接:https://leetcode-cn.com/problems/daily-temperatures/ 7 | // 标签:栈、哈希表 8 | // 要点:递减栈 9 | // 时间复杂度:O(N) 10 | // 空间复杂度:O(W),W 是 T[i] 的可取值数 11 | // 12 | 13 | import Foundation 14 | 15 | class Solution { 16 | func dailyTemperatures(_ T: [Int]) -> [Int] { 17 | var res = [Int](repeating: 0, count: T.count) 18 | var stack = [Int]() 19 | 20 | for i in 0.. T[stack.last!] { 22 | res[stack.last!] = i - stack.last! 23 | stack.popLast() 24 | } 25 | stack.append(i) 26 | } 27 | 28 | return res 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Stack/README.md: -------------------------------------------------------------------------------- 1 | # 栈 2 | 3 | - 如何理解栈? 4 | 5 | ![img](.assets/stack_intro.jpg) 6 | 7 | - 后进者先出,先进者后出 8 | - 一种“操作受限”的线性表:只允许在一端插入和删除数据 9 | 10 | - 如何实现一个栈? 11 | 12 | - 数组实现,顺序栈 13 | - 链表实现,链式栈 14 | 15 | - 支持动态扩容的顺序栈 16 | 17 | - 栈在函数调用中的应用 18 | 19 | - 函数调用栈 20 | - 栈帧 21 | 22 | - 栈在表达式求值中的应用 23 | 24 | - 编译器通过两个栈实现表达式求值 25 | 26 | - 栈在括号匹配中的应用 -------------------------------------------------------------------------------- /String/14_LongestCommonPrefix.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 14. 最长公共前缀 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/longest-common-prefix/ 6 | // 标签:字符串 7 | // 要点:字符串的扫描遍历,字符串API接口应用 8 | // 时间复杂度:O(N), N = 数组中字符串左右字符数总和 9 | // 空间复杂度:O(1) 10 | // 11 | 12 | class Solution { 13 | func longestCommonPrefix(_ strs: [String]) -> String { 14 | 15 | guard !strs.isEmpty else { return "" } 16 | 17 | var prefix = strs.first! 18 | for string in strs { 19 | // Think about hasPrefix vs. starts(with:) 20 | while !string.hasPrefix(prefix) { 21 | prefix = String(prefix.dropLast()) 22 | } 23 | } 24 | 25 | return prefix 26 | } 27 | } 28 | 29 | // Tests 30 | let s = Solution() 31 | s.longestCommonPrefix(["flower","flow","flight"]) == "fl" 32 | s.longestCommonPrefix(["dog","racecar","car"]) == "" 33 | -------------------------------------------------------------------------------- /String/67_AddBinary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // 67. 二进制求和 3 | // 4 | // 题目链接:https://leetcode-cn.com/problems/add-binary/ 5 | // 标签:字符串、数学 6 | // 要点:按位逆序遍历,异或相加,重点思考进位(carry)🤔 7 | // 时间复杂度:O(n) 8 | // 空间复杂度:O(n) 9 | // 注意:1. 转整数【Int(a, radix:2)】再相加的方案,无法处理溢出的情况 10 | // 2. Swift 中 String 不支持直接下标随机访问,需要先转为数组 11 | 12 | import Foundation 13 | 14 | class Solution { 15 | func addBinary(_ a: String, _ b: String) -> String { 16 | let aChars = Array(a), bChars = Array(b) 17 | var sum = 0, carry = 0, res = "" 18 | var i = aChars.count - 1, j = bChars.count - 1 19 | 20 | while i >= 0 || j >= 0 || carry > 0 { 21 | let bitA: Int = { 22 | if i < 0 { return 0 } 23 | defer { i -= 1 } 24 | return Int(String(aChars[i]))! 25 | }() 26 | let bitB: Int = { 27 | if j < 0 { return 0 } 28 | defer { j -= 1 } 29 | return Int(String(bChars[j]))! 30 | }() 31 | 32 | sum = bitA ^ bitB ^ carry 33 | carry = (bitA & bitB) | (carry & (bitA | bitB)) 34 | 35 | res = String(sum) + res 36 | } 37 | return res 38 | } 39 | } 40 | 41 | // Tests 42 | let s = Solution() 43 | assert(s.addBinary("11", "1") == "100") 44 | assert(s.addBinary("1010", "1011") == "10101") 45 | 46 | let bigA = "10100000100100110110010000010101111011011001101110111111111101000000101111001110001111100001101" 47 | let bigB = "110101001011101110001111100110001010100001101011101010000011011011001011101111001100000011011110011" 48 | let bigExpectation = "110111101100010011000101110110100000011101000101011001000011011000001100011110011010010011000000000" 49 | assert(s.addBinary(bigA, bigB) == bigExpectation) 50 | -------------------------------------------------------------------------------- /String/93_RestoreIPAddresses.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 93. 复原IP地址 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/restore-ip-addresses/ 6 | // 标签:字符串 7 | // 要点:字符串的扫描遍历,回溯算法 8 | // 时间复杂度: 9 | // 空间复杂度: 10 | // 11 | 12 | class Solution { 13 | 14 | func restoreIpAddresses(_ s: String) -> [String] { 15 | guard s.count >= 4, s.count <= 12 else { return [] } 16 | var result = [String]() 17 | _backtrack(s, index: 0, segments: [], result: &result) 18 | return result 19 | } 20 | 21 | private func _backtrack(_ s: String, index: Int, segments: [String], result: inout [String]) { 22 | if index == s.count && segments.count == 4 { 23 | result.append(segments.joined(separator: ".")) 24 | return 25 | } 26 | 27 | let chars = [Character](s) 28 | for i in 1...3 { 29 | if index + i > s.count { continue } 30 | if i != 1 && chars[index] == "0" { continue } 31 | let segment = String(chars[index.. [[Int]] { 26 | guard let root = root else { return [] } 27 | 28 | var result = [[Int]]() 29 | func _helper(_ node: TreeNode, level: Int) { 30 | if result.count == level { 31 | result.append([]) 32 | } 33 | result[level].append(node.val) 34 | if let left = node.left { 35 | _helper(left, level: level + 1) 36 | } 37 | if let right = node.right { 38 | _helper(right, level: level + 1) 39 | } 40 | } 41 | 42 | _helper(root, level: 0) 43 | return result 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Tree/236_LowestCommonAncestorofaBinaryTree.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 236. 二叉树的最近公共祖先 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/ 6 | // 标签:树 7 | // 要点:递归,理解并把握返回的终止条件 8 | // 时间复杂度: O(N) 9 | // 空间复杂度: O(N) 10 | // 11 | 12 | /// Definition for a binary tree node. 13 | public class TreeNode { 14 | public var val: Int 15 | public var left: TreeNode? 16 | public var right: TreeNode? 17 | public init(_ val: Int) { 18 | self.val = val 19 | self.left = nil 20 | self.right = nil 21 | } 22 | } 23 | 24 | 25 | class Solution { 26 | func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? { 27 | guard let root = root else { return nil } 28 | if root.val == p?.val || root.val == q?.val { return root } 29 | 30 | let left = lowestCommonAncestor(root.left, p, q) 31 | let right = lowestCommonAncestor(root.right, p, q) 32 | 33 | return left == nil ? right : (right == nil ? left : root) 34 | } 35 | } -------------------------------------------------------------------------------- /Tree/98_ValidateBinarySearchTree.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 98. 验证二叉搜索树 4 | // 5 | // 题目链接:https://leetcode-cn.com/problems/validate-binary-search-tree 6 | // 标签:树、深度优先搜索 7 | // 要点:递归判断或中序遍历 8 | // 时间复杂度: O(N) 9 | // 空间复杂度: O(N) 10 | // 11 | 12 | /// Definition for a binary tree node. 13 | public class TreeNode { 14 | public var val: Int 15 | public var left: TreeNode? 16 | public var right: TreeNode? 17 | public init(_ val: Int) { 18 | self.val = val 19 | self.left = nil 20 | self.right = nil 21 | } 22 | } 23 | 24 | class Solution { 25 | func isValidBST(_ root: TreeNode?) -> Bool { 26 | return _validate(root) 27 | } 28 | 29 | private func _validate(_ node: TreeNode?, min: Int? = nil, max: Int? = nil) -> Bool { 30 | 31 | guard let node = node else { return true } 32 | 33 | if let min = min, node.val <= min { 34 | return false 35 | } 36 | if let max = max, node.val >= max { 37 | return false 38 | } 39 | return _validate(node.left, min: min, max: node.val) 40 | && _validate(node.right, min: node.val, max: max) 41 | } 42 | } 43 | --------------------------------------------------------------------------------