哈希
1.两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var dic: [Int: Int] = [:]
for (index, value) in nums.enumerated() {
let dif = target - value
if dic[dif] != nil {
// 找到了
return [dic[dif]!, index]
} else {
dic[value] = index
}
}
return []
}
}
2.字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
字母异位词 是由重新排列源单词的所有字母得到的一个新单词。
class Solution {
func groupAnagrams(_ strs: [String]) -> [[String]] {
var dic: [String: [String]] = [:]
for str in strs {
let key = String(str.sorted())
if dic[key] != nil {
dic[key]!.append(str)
} else {
dic[key] = [str]
}
}
var result = [[String]]()
for value in dic {
result.append(value.value)
}
return result
}
}
3.最长连续序列
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) **的算法解决此问题。
class Solution {
func longestConsecutive(_ nums: [Int]) -> Int {
var maxLength = 0
var set = Set<Int>()
for value in nums {
set.insert(value)
}
for value in set {
if (!set.contains(value - 1)) {
var current = 1
var value = value
while set.contains(value + 1) {
current += 1
value += 1
}
maxLength = max(maxLength, current)
}
}
return maxLength
}
}
双指针
1.移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
class Solution {
// 双指针解法
func moveZeroes(_ nums: inout [Int]) {
var left = 0
var right = 0
while left < nums.count && right < nums.count {
if (nums[right] != 0) {
nums.swapAt(left, right)
left += 1
right += 1
} else {
right += 1
}
}
}
}
2.盛最多水的容器
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明: 你不能倾斜容器。
class Solution {
func maxArea(_ height: [Int]) -> Int {
let length = height.count
var left = 0
var right = length - 1
var maxWater = 0
while left <= right {
let length = right - left
let waterHeight = min(height[left], height[right])
let currentWater = waterHeight * length
maxWater = max(maxWater, currentWater)
if (height[left] <= height[right]) {
left += 1
} else {
right -= 1
}
}
return maxWater
}
}
3. 三数之和
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
class Solution {
func threeSum(_ nums: [Int]) -> [[Int]] {
var result = [[Int]]()
var set = Set<Set<Int>>()
for (index, value) in nums.enumerated() {
let target = -value
var dic = [Int: Int]()
for i in (index + 1)..<nums.count {
let dif = target - nums[i]
if dic[dif] != nil {
let currentResult = [-target, dif, dic[dif]!]
let resultSet = Set(currentResult)
if !set.contains(resultSet) {
set.insert(resultSet)
result.append(currentResult)
}
} else {
dic[nums[i]] = dif
}
}
}
return result
}
}
滑动窗口
1.无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度
class Solution {
func lengthOfLongestSubstring(_ s: String) -> Int {
let array = s.map { String($0) }
var maxLength = 0
var subString = Array<String>()
for value in array {
if let index = subString.firstIndex(where: { string in
string == value
}) {
subString.removeFirst(index + 1)
}
subString.append(value)
maxLength = max(maxLength, subString.count)
}
return maxLength
}
}
2. 找到字符串中所有字母异位词
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
class Solution {
func findAnagrams(_ s: String, _ p: String) -> [Int] {
var result = [Int]()
var sArray = Array(repeating: 0, count: 26)
var pArray = Array(repeating: 0, count: 26)
let sCount = s.count
let pCount = p.count
if sCount < pCount {
return []
}
for i in 0..<pCount {
sArray[Int(s[s.index(s.startIndex, offsetBy: i)].asciiValue! - Character("a").asciiValue!)] += 1
pArray[Int(p[p.index(p.startIndex, offsetBy: i)].asciiValue! - Character("a").asciiValue!)] += 1
}
if sArray == pArray {
result.append(0)
}
for i in 0..<sCount - pCount {
sArray[Int(s[s.index(s.startIndex, offsetBy: i)].asciiValue! - Character("a").asciiValue!)] -= 1
sArray[Int(s[s.index(s.startIndex, offsetBy: i + pCount)].asciiValue! - Character("a").asciiValue!)] += 1
if sArray == pArray {
result.append(i + 1)
}
}
return result
}
}
子串
1. 和为K的子数组
给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。
子数组是数组中元素的连续非空序列。
class Solution {
func subarraySum(_ nums: [Int], _ k: Int) -> Int {
var count = 0
var pre = 0
var map = Dictionary<Int, Int>()
map[0] = 1
for i in 0..<nums.count {
pre += nums[i]
let delta = pre - k
if let value = map[delta] {
count += value
}
map[pre] = (map[pre] ?? 0) + 1
}
return count
}
}
普通数组
1.最大子数组和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
class Solution {
func maxSubArray(_ nums: [Int]) -> Int {
guard nums.count > 0 else {
return 0
}
var pre = 0
var maxResult = nums[0]
for num in nums {
pre = max(pre + num, num)
maxResult = max(maxResult, pre)
}
return maxResult
}
}
2.合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
class Solution {
func merge(_ intervals: [[Int]]) -> [[Int]] {
guard intervals.count > 0 else {
return []
}
// 由大到小排列
var sortedIntervals = intervals.sorted { left, right in
left[0] > right[0]
}
var result = [[Int]]()
result.append(sortedIntervals.removeLast())
// 已经有元素了,开始比较
while sortedIntervals.last != nil {
let remainingLast = sortedIntervals.removeLast()
if remainingLast[0] <= result.last![1] {
// 需要合并
let resultLast = result.removeLast()
result.append([resultLast[0], max(resultLast[1], remainingLast[1])])
} else {
result.append(remainingLast)
}
}
return result
}
}
3.轮转数组
给定一个整数数组 nums,将数组中的元素向右轮转 k **个位置,其中 k **是非负数。
方案1:
class Solution {
func rotate(_ nums: inout [Int], _ k: Int) {
let count = nums.count
var k = k % count
// 现在k会小于count
var totalCount = 0
for i in 0..<count {
if totalCount >= count {
break
}
var start = i
var pre = nums[i]
var current = i
repeat {
var next = (k + current) % count
let tmp = nums[next]
nums[next] = pre
totalCount += 1
pre = tmp
current = next
} while current != start
}
print(nums)
}
}
方案2:
class Solution {
func rotate(_ nums: inout [Int], _ k: Int) {
let count = nums.count
var k = k % count
// 现在k会小于count
nums.reverse()
nums[0..<k].reverse()
nums[k..<count].reverse()
print(nums)
}
}
4.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。
题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。
请 不要使用除法, 且在 O(n) 时间复杂度内完成此题。
class Solution {
func productExceptSelf(_ nums: [Int]) -> [Int] {
let count = nums.count
var answer = Array(repeating: 0, count: count)
answer[0] = 1
// 得出元素i左边所有元素乘积的数组
for index in 1..<count {
answer[index] = answer[index - 1] * nums[index - 1]
}
var r = 1
for index in (0..<count).reversed() {
answer[index] = answer[index] * r
r = r * nums[index]
}
return answer
}
}
矩阵
1.矩阵置零
给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 [原地] 算法 。
class Solution {
func setZeroes(_ matrix: inout [[Int]]) {
guard matrix.count > 0 else {
return
}
let row = matrix.count
let column = matrix[0].count
var rowFlag = Array(repeating: 0, count: row)
var columFlag = Array(repeating: 0, count: column)
for i in 0..<row {
for j in 0..<column {
if matrix[i][j] == 0 {
print("i = (j), j = (j)")
rowFlag[i] = 1
columFlag[j] = 1
}
}
}
for i in 0..<row {
for j in 0..<column {
if rowFlag[i] == 1 || columFlag[j] == 1 {
matrix[i][j] = 0
}
}
}
}
}
2.螺旋矩阵
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
class Solution {
func spiralOrder(_ matrix: [[Int]]) -> [Int] {
var result = [Int]()
let m = matrix.count
let n = matrix[0].count
var left = 0
var right = n - 1
var top = 0
var bottom = m - 1
while left <= right && top <= bottom {
// 第一行向右走
if left > right {
break
}
for j in left...right {
result.append(matrix[top][j])
}
top += 1
if top > bottom {
break
}
for i in top...bottom {
result.append(matrix[i][right])
}
right -= 1
if left > right {
break
}
for j in (left...right).reversed() {
result.append(matrix[bottom][j])
}
bottom -= 1
if top > bottom {
break
}
for i in (top...bottom).reversed() {
result.append(matrix[i][left])
}
left += 1
}
return result
}
}
3.旋转图像
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 [原地] 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
先上下翻转,再对角线翻转。
class Solution {
func rotate(_ matrix: inout [[Int]]) {
let m = matrix.count
let n = matrix[0].count
for i in 0..<(m / 2) {
for j in 0..<n {
let tmp = matrix[m - i - 1][j]
matrix[m - i - 1][j] = matrix[i][j]
matrix[i][j] = tmp
}
}
for i in 0..<m {
for j in 0...i {
let tmp = matrix[j][i]
matrix[j][i] = matrix[i][j]
matrix[i][j] = tmp
}
}
print(matrix)
}
}
4.搜索二维矩阵II
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
- 每行的元素从左到右升序排列。
- 每列的元素从上到下升序排列。
class Solution {
func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool {
let m = matrix.count
let n = matrix[0].count
// 从右上角开始搜索
var x = 0
var y = n - 1
while x < m && y >= 0 {
if matrix[x][y] == target {
return true
}
if matrix[x][y] < target {
x += 1
} else {
y -= 1
}
}
return false
}
}
链表
1.相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
class Solution {
func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? {
var a = headA
var b = headB
if headA == nil || headB == nil {
return nil
}
while a !== b {
a = a == nil ? headB : a?.next
b = b == nil ? headA : b?.next
}
return a
}
}
2.反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
class Solution {
func reverseList(_ head: ListNode?) -> ListNode? {
var newHead: ListNode? = nil
var currrent = head
while currrent != nil {
let next = currrent!.next
currrent?.next = newHead
newHead = currrent
currrent = next
}
return newHead
}
}
3.回文链表
给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。
方法1:将值复制到数组中后用双指针法
class Solution {
func isPalindrome(_ head: ListNode?) -> Bool {
var array = [ListNode]()
var current = head
while current != nil {
array.append(current!)
current = current?.next
}
let length = array.count
guard length > 1 else {
return true
}
var left = 0
var right = length - 1
while left <= right && array[left].val == array[right].val {
left += 1
right -= 1
}
if left > right {
return true
} else {
return false
}
}
}
4.环形链表
给你一个链表的头节点 head ,判断链表中是否有环
class Solution {
func hasCycle(_ head: ListNode?) -> Bool {
var slow = head
var fast = head?.next
while slow != nil && fast != nil {
if slow === fast {
return true
} else {
slow = slow?.next
fast = fast?.next?.next
}
}
return false
}
}
5.环形链表II
给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
class Solution {
func detectCycle(_ head: ListNode?) -> ListNode? {
var slow = head
var fast = head
while fast?.next != nil {
slow = slow?.next
fast = fast?.next?.next
if (slow === fast) {
var ptr = head
while ptr !== slow {
ptr = ptr?.next
slow = slow?.next
}
return ptr
}
}
return nil
}
}
6.合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
class Solution {
func mergeTwoLists(_ list1: ListNode?, _ list2: ListNode?) -> ListNode? {
var dumpNode: ListNode? = ListNode(-1, nil)
var resultPreNode = dumpNode
var list1 = list1
var list2 = list2
while list1 != nil && list2 != nil {
if list1!.val <= list2!.val {
resultPreNode?.next = list1
list1 = list1?.next
resultPreNode = resultPreNode?.next
} else {
resultPreNode?.next = list2
list2 = list2?.next
resultPreNode = resultPreNode?.next
}
}
if list1 != nil {
resultPreNode?.next = list1
}
if list2 != nil {
resultPreNode?.next = list2
}
return dumpNode?.next
}
}
7.两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
class Solution {
func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
var dumpHead: ListNode? = ListNode(-1)
var result = dumpHead
var l1 = l1
var l2 = l2
var addition = 0
while l1 != nil || l2 != nil {
var sum = (l1?.val ?? 0) + (l2?.val ?? 0) + addition
if sum >= 10 {
addition = 1
sum = sum - 10
} else {
addition = 0
}
result?.next = ListNode(sum)
result = result?.next
l1 = l1?.next
l2 = l2?.next
}
if addition > 0 {
result?.next = ListNode(1)
}
return dumpHead?.next
}
}
8.删除链表的倒数第N个结点
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
class Solution {
func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? {
var dumpHead: ListNode? = ListNode(-1, head)
var fast = dumpHead
var fastPre = dumpHead
for _ in 0..<n {
fastPre = fast
fast = fast?.next
}
if fast == nil && fastPre == nil {
return head
}
var pre = dumpHead
var slow = dumpHead
while fast != nil {
pre = slow
slow = slow?.next
fast = fast?.next
}
// 移除slow节点
pre?.next = slow?.next
return dumpHead?.next
}
}
9.两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
class Solution {
func swapPairs(_ head: ListNode?) -> ListNode? {
if head == nil || head?.next == nil {
return head
}
var newHead = head?.next
head?.next = swapPairs(newHead?.next)
newHead?.next = head
return newHead
}
}
11.随机链表的复制
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
class Solution {
func copyRandomList(_ head: Node?) -> Node? {
var dumpNewHead = Node(-1)
var map: [ObjectIdentifier: Node] = [:]
do {
var newHead: Node? = dumpNewHead
var oldHead = head
while oldHead != nil {
// 先把next串起来
var newNode = Node(oldHead!.val)
map[ObjectIdentifier(oldHead!)] = newNode
newHead?.next = newNode
oldHead = oldHead?.next
newHead = newHead?.next
}
}
do {
var newHead: Node? = dumpNewHead.next
var oldHead = head
while oldHead != nil {
if let random = oldHead?.random {
newHead?.random = map[ObjectIdentifier(random)]
}
oldHead = oldHead?.next
newHead = newHead?.next
}
}
return dumpNewHead.next
}
}
12.排序链表
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
class Solution
{
func sortList(_ head: ListNode?) -> ListNode?
{
if head == nil || head?.next == nil {
return head
}
if head?.next?.next == nil{
var temp = head?.next
if head!.val > temp!.val{
temp?.next = head
head?.next = nil
return temp
}
else{
return head
}
}
let leftList = head
let middlePre = middleNode(head)
let middle = middlePre?.next
middlePre?.next = nil
let left = sortList(leftList)
let right = sortList(middle)
return mergeTwoLists(left, right)
}
func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
if l1 == nil{
return l2
}
if l2 == nil{
return l1
}
var list1 = l1;
var list2 = l2
var prev : ListNode?
let prehead : ListNode? = ListNode(-1)
prev = prehead
while list1 != nil && list2 != nil{
if (list1?.val)! <= (list2?.val)!{
prev?.next = list1
list1 = list1?.next
}
else{
prev?.next = list2
list2 = list2?.next
}
prev = prev?.next
}
prev?.next = list1 ?? list2
return prehead?.next
}
func middleNode(_ head: ListNode?) -> ListNode? {
if head == nil || head?.next == nil{
return head
}
if head?.next?.next == nil{
return head?.next
}
var fast = head?.next
var slow = head
var pre = slow
while fast != nil{
pre = slow
fast = fast?.next?.next
slow = slow?.next
}
return pre
}
}
13.困难
14.LRU缓存
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。
实现 LRUCache 类:
LRUCache(int capacity)以 正整数 作为容量capacity初始化 LRU 缓存int get(int key)如果关键字key存在于缓存中,则返回关键字的值,否则返回-1。void put(int key, int value)如果关键字key已经存在,则变更其数据值value;如果不存在,则向缓存中插入该组key-value。如果插入操作导致关键字数量超过capacity,则应该 逐出 最久未使用的关键字。
函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
class ListNode: CustomStringConvertible {
var description: String {
return "value: (value.0),(value.1)"
}
var value: (Int, Int)
var pre: ListNode?
var next: ListNode?
init(value: (Int, Int), pre: ListNode? = nil, next: ListNode? = nil) {
self.value = value
self.pre = pre
self.next = next
}
}
class List: CustomStringConvertible {
var description: String {
var result = ""
var current: ListNode? = dumpHead
while current != nil {
result += current!.description
result += "->"
current = current?.next
}
return result
}
// 双向链表使用虚拟头、尾节点,方便操作。
var dumpHead = ListNode(value: (-1, -1))
var dumpTail = ListNode(value: (-1, -1))
init() {
dumpHead.next = dumpTail
dumpTail.pre = dumpHead
}
func push(value: ListNode) {
let nextNode = dumpHead.next
value.next = nextNode
nextNode?.pre = value
dumpHead.next = value
value.pre = dumpHead
}
func removeLast() -> ListNode? {
let last = dumpTail.pre
last?.pre?.next = dumpTail
dumpTail.pre = last?.pre
last?.pre = nil
last?.next = nil
return last
}
func remove(value: ListNode) {
let previousNode = value.pre
let nextNode = value.next
previousNode?.next = nextNode
nextNode?.pre = previousNode
}
}
class LRUCache {
private var map:[Int: ListNode] = [:]
private var capacity = 0
private var list = List()
func showMap() {
print(map)
print(list)
}
init(_ capacity: Int) {
self.capacity = capacity
}
func get(_ key: Int) -> Int {
let value = map[key]
if value == nil {
return -1
} else {
defer {
list.remove(value: value!)
list.push(value: value!)
}
return value!.value.1
}
}
func put(_ key: Int, _ value: Int) {
if map[key] != nil {
let node = map[key]!
node.value = (key, value)
list.remove(value: node)
list.push(value: node)
return
}
let newNode = ListNode(value: (key, value))
if map.count >= capacity {
if let removed = list.removeLast() {
map[removed.value.0] = nil
}
}
list.push(value: newNode)
map[key] = newNode
}
}
二叉树
1.二叉树的中序遍历
给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。
class Solution {
private var result: [Int] = []
func inorderTraversal(_ root: TreeNode?) -> [Int] {
self.inorderTraversal1(root)
return result
}
private func inorderTraversal1(_ node: TreeNode?) {
guard let node = node else {
return
}
inorderTraversal1(node.left)
result.append(node.val)
inorderTraversal1(node.right)
}
}
2.二叉树的最大深度
给定一个二叉树 root ,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
class Solution {
func maxDepth(_ root: TreeNode?) -> Int {
return heightOfTree(root)
}
private func heightOfTree(_ node: TreeNode?) -> Int {
guard let node = node else {
return 0
}
let leftHeight = heightOfTree(node.left)
let rightHeight = heightOfTree(node.right)
return max(leftHeight, rightHeight) + 1
}
}