Merge pull request #34 from zztian1024/main

为数组篇&链表篇&二叉树 增加 Swift 实现
This commit is contained in:
算法基地 2021-07-20 15:05:11 +08:00 committed by GitHub
commit 10a7420457
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1472 additions and 4 deletions

View File

@ -102,3 +102,34 @@ class Solution {
}
```
Swift Code
```swift
class Solution {
func inorderTraversal(_ root: TreeNode?) -> [Int] {
var list:[Int] = []
guard root != nil else {
return list
}
var p1 = root, p2: TreeNode?
while p1 != nil {
p2 = p1!.left
if p2 != nil {
while p2!.right != nil && p2!.right !== p1 {
p2 = p2!.right
}
if p2!.right == nil {
p2!.right = p1
p1 = p1!.left
continue
} else {
p2!.right = nil
}
}
list.append(p1!.val)
p1 = p1!.right
}
return list
}
}
```

View File

@ -51,5 +51,32 @@ class Solution {
}
```
Swift Code
```swift
class Solution {
func inorderTraversal(_ root: TreeNode?) -> [Int] {
var arr:[Int] = []
var cur = root
var stack:[TreeNode] = []
while !stack.isEmpty || cur != nil {
//找到当前应该遍历的那个节点
while cur != nil {
stack.append(cur!)
cur = cur!.left
}
//此时指针指向空也就是没有左子节点则开始执行出栈操作
if let temp = stack.popLast() {
arr.append(temp.val)
//指向右子节点
cur = temp.right
}
}
return arr
}
}
```
###

View File

@ -406,6 +406,42 @@ public:
};
```
Swift Code
```swift
class Solution {
func levelOrder(_ root: TreeNode?) -> [[Int]] {
var res:[[Int]] = []
guard root != nil else {
return res
}
var queue:[TreeNode?] = []
queue.append(root!)
while !queue.isEmpty {
let size = queue.count
var list:[Int] = []
for i in 0..<size {
guard let node = queue.removeFirst() else {
continue
}
if node.left != nil {
queue.append(node.left)
}
if node.right != nil {
queue.append(node.right);
}
list.append(node.val)
}
res.append(list)
}
return res
}
}
```
时间复杂度On 空间复杂度On
大家如果吃透了二叉树的层序遍历的话可以顺手把下面几道题目解决掉思路一致甚至都不用拐弯

View File

@ -103,4 +103,41 @@ class Solution {
}
```
Swift Code
```swift
class Solution {
func preorderTraversal(_ root: TreeNode?) -> [Int] {
var list:[Int] = []
guard root != nil else {
return list
}
var p1 = root, p2: TreeNode?
while p1 != nil {
p2 = p1!.left
if p2 != nil {
//找到左子树的最右叶子节点
while p2!.right != nil && p2!.right !== p1 {
p2 = p2!.right
}
//添加 right 指针对应 right 指针为 null 的情况
if p2!.right == nil {
list.append(p1!.val)
p2!.right = p1
p1 = p1!.left
continue
}
//对应 right 指针存在的情况则去掉 right 指针
p2!.right = nil
} else {
list.append(p1!.val)
}
//移动 p1
p1 = p1!.right
}
return list
}
}
```
好啦今天就看到这里吧咱们下期见

View File

@ -67,3 +67,32 @@ class Solution {
}
```
Swift Code
```swift
class Solution {
func preorderTraversal(_ root: TreeNode?) -> [Int] {
var list:[Int] = []
var stack:[TreeNode] = []
guard root != nil else {
return list
}
stack.append(root!)
while !stack.isEmpty {
let temp = stack.popLast()
if let right = temp?.right {
stack.append(right)
}
if let left = temp?.left {
stack.append(left)
}
//这里也可以放到前面
list.append((temp?.val)!)
}
return list
}
}
```

View File

@ -71,6 +71,39 @@ class Solution {
}
```
Swift Code
```swift
class Solution {
func postorderTraversal(_ root: TreeNode?) -> [Int] {
var list:[Int] = []
var stack:[TreeNode] = []
var cur = root, preNode: TreeNode?
while !stack.isEmpty || cur != nil {
//和之前写的中序一致
while cur != nil {
stack.append(cur!)
cur = cur!.left
}
//1.出栈可以想一下这一步的原因
cur = stack.popLast()
//2.if 里的判断语句有什么含义
if cur!.right === nil || cur!.right === preNode {
list.append(cur!.val)
//更新下 preNode也就是定位住上一个访问节点
preNode = cur
cur = nil
} else {
//3.再次压入栈和上面那条 1 的关系
stack.append(cur!)
cur = cur!.right
}
}
return list
}
}
```
当然也可以修改下代码逻辑将 `cur = stack.pop()` 改成 `cur = stack.peek()`下面再修改一两行代码也可以实现这里这样写是方便动画模拟大家可以随意发挥
时间复杂度 On, 空间复杂度On

View File

@ -116,6 +116,62 @@ class Solution {
}
```
Swift Code
```swift
class Solution {
var list:[Int] = []
func postorderTraversal(_ root: TreeNode?) -> [Int] {
guard root != nil else {
return list
}
var p1 = root, p2: TreeNode?
while p1 != nil {
p2 = p1!.left
if p2 != nil {
while p2!.right != nil && p2!.right !== p1 {
p2 = p2!.right
}
if p2!.right == nil {
p2!.right = p1
p1 = p1!.left
continue
} else {
p2!.right = nil
postMorris(p1!.left)
}
}
p1 = p1!.right
}
//以根节点为起点的链表
postMorris(root!)
return list
}
func postMorris(_ root: TreeNode?) {
let reverseNode = reverseList(root)
//从后往前遍历
var cur = reverseNode
while cur != nil {
list.append(cur!.val)
cur = cur!.right
}
reverseList(reverseNode)
}
func reverseList(_ head: TreeNode?) -> TreeNode? {
var cur = head, pre: TreeNode?
while cur != nil {
let next = cur?.right
cur?.right = pre
pre = cur
cur = next
}
return pre
}
}
```
时间复杂度 On空间复杂度 O1
总结后序遍历比起前序和中序稍微复杂了一些所以我们解题的时候需要好好注意一下迭代法的核心是利用一个指针来定位我们上一个遍历的节点Morris 的核心是将某节点的右子节点看成是一条链表进行反向遍历

View File

@ -200,6 +200,31 @@ class Solution {
}
```
Swift Code:
```swift
class Solution {
func countDigitOne(_ n: Int) -> Int {
var high = n, low = 0, cur = 0, count = 0, num = 1
while high != 0 || cur != 0 {
cur = high % 10
high /= 10
//这里我们可以提出 high * num 因为我们发现无论为几都含有它
if cur == 0 {
count += high * num
} else if cur == 1 {
count += high * num + 1 + low
} else {
count += (high + 1) * num
}
low = cur * num + low
num *= 10
}
return count
}
}
```
时间复杂度 : O(logn) 空间复杂度 O(1)

View File

@ -114,5 +114,45 @@ class Solution:
ans = max(ans, t)
return ans
```
Swift Code
```swift
class Solution {
func maxSatisfied(_ customers: [Int], _ grumpy: [Int], _ minutes: Int) -> Int {
let len = customers.count
var winSum = 0, rightSum = 0, leftSum = 0
// 右区间的值
for i in minutes..<len {
if grumpy[i] == 0 {
rightSum += customers[i]
}
}
// 窗口的值
for i in 0..<minutes {
winSum += customers[i]
}
var maxCustomer = winSum + leftSum + rightSum
// 窗口左边缘
var left = 1, right = minutes
while right < len {
// 重新计算左区间的值也可以用 customer 值和 grumpy 值相乘获得
if grumpy[left - 1] == 0 {
leftSum += customers[left - 1]
}
// 重新计算右区间值
if grumpy[right] == 0 {
rightSum -= customers[right]
}
// 窗口值
winSum = winSum - customers[left - 1] + customers[right]
maxCustomer = max(maxCustomer, winSum + leftSum + rightSum) // 保留最大值
// 移动窗口
left += 1
right += 1
}
return maxCustomer
}
}
```

View File

@ -111,3 +111,152 @@ class Solution:
return maxwin
```
Swift Code
Swift数组模拟超时58 / 61 个通过测试用例
```swift
class Solution {
func longestSubarray(_ nums: [Int], _ limit: Int) -> Int {
var maxQueue:[Int] = []
var minQueue:[Int] = []
let len = nums.count
var right = 0, left = 0, maxWin = 0
while right < len {
while !maxQueue.isEmpty && (maxQueue.last! < nums[right]) {
maxQueue.removeLast()
}
while !minQueue.isEmpty && (minQueue.last! > nums[right]) {
minQueue.removeLast()
}
maxQueue.append(nums[right])
minQueue.append(nums[right])
while (maxQueue.first! - minQueue.first!) > limit {
if maxQueue.first! == nums[left] {
maxQueue.removeFirst()
}
if minQueue.first! == nums[left] {
minQueue.removeFirst()
}
left += 1
}
maxWin = max(maxWin, right - left + 1)
right += 1
}
return maxWin
}
}
```
Swift使用双端队列击败了100.00%
```swift
class Solution {
func longestSubarray(_ nums: [Int], _ limit: Int) -> Int {
var maxQueue = Deque<Int>.init()
var minQueue = Deque<Int>.init()
let len = nums.count
var right = 0, left = 0, maxWin = 0
while right < len {
while !maxQueue.isEmpty && (maxQueue.peekBack()! < nums[right]) {
maxQueue.dequeueBack()
}
while !minQueue.isEmpty && (minQueue.peekBack()! > nums[right]) {
minQueue.dequeueBack()
}
maxQueue.enqueue(nums[right])
minQueue.enqueue(nums[right])
while (maxQueue.peekFront()! - minQueue.peekFront()!) > limit {
if maxQueue.peekFront()! == nums[left] {
maxQueue.dequeue()
}
if minQueue.peekFront()! == nums[left] {
minQueue.dequeue()
}
left += 1
}
maxWin = max(maxWin, right - left + 1)
right += 1
}
return maxWin
}
// 双端队列数据结构
public struct Deque<T> {
private var array: [T?]
private var head: Int
private var capacity: Int
private let originalCapacity: Int
public init(_ capacity: Int = 10) {
self.capacity = max(capacity, 1)
originalCapacity = self.capacity
array = [T?](repeating: nil, count: capacity)
head = capacity
}
public var isEmpty: Bool {
return count == 0
}
public var count: Int {
return array.count - head
}
public mutating func enqueue(_ element: T) {
array.append(element)
}
public mutating func enqueueFront(_ element: T) {
if head == 0 {
capacity *= 2
let emptySpace = [T?](repeating: nil, count: capacity)
array.insert(contentsOf: emptySpace, at: 0)
head = capacity
}
head -= 1
array[head] = element
}
public mutating func dequeue() -> T? {
guard head < array.count, let element = array[head] else { return nil }
array[head] = nil
head += 1
if capacity >= originalCapacity && head >= capacity*2 {
let amountToRemove = capacity + capacity/2
array.removeFirst(amountToRemove)
head -= amountToRemove
capacity /= 2
}
return element
}
public mutating func dequeueBack() -> T? {
if isEmpty {
return nil
} else {
return array.removeLast()
}
}
public func peekFront() -> T? {
if isEmpty {
return nil
} else {
return array[head]
}
}
public func peekBack() -> T? {
if isEmpty {
return nil
} else {
return array.last!
}
}
}
}
```

View File

@ -76,6 +76,32 @@ class Solution:
return rearr
```
Swift Code:
```swift
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
let count = nums.count
if count < 2 {
return [0]
}
var rearr: [Int] = []
// 查询元素
for i in 0..<count {
for j in i+1..<count {
// 发现符合条件情况
if nums[i] + nums[j] == target {
rearr.append(i)
rearr.append(j)
}
}
}
return rearr
}
}
```
**哈希表**
**解析**
@ -159,3 +185,20 @@ class Solution:
return [0]
```
Swift Code:
```swift
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var m:[Int:Int] = [:]
for i in 0..<nums.count {
let n = nums[i]
if let k = m[target - n] { // 如果存在则返回
return [k, i]
}
m[n] = i // 不存在则存入
}
return [0]
}
}
```

View File

@ -94,6 +94,32 @@ public:
};
```
Swift Code
```swift
class Solution {
func containsNearbyDuplicate(_ nums: [Int], _ k: Int) -> Bool {
if nums.count == 0 {
return false
}
var dict:[Int:Int] = [:]
for i in 0..<nums.count {
// 如果含有
if let v = dict[nums[i]] {
// 判断是否小于K如果小于等于则直接返回
let abs = abs(i - v)
if abs <= k {
return true
}
}
// 更新索引此时有两种情况不存在或者存在时将后出现的索引保存
dict[nums[i]] = i
}
return false
}
}
```
**HashSet**
**解析**
@ -174,3 +200,27 @@ public:
};
```
Swift Code
```swift
class Solution {
func containsNearbyDuplicate(_ nums: [Int], _ k: Int) -> Bool {
if nums.count == 0 {
return false
}
var set:Set<Int> = []
for i in 0..<nums.count {
// 含有该元素返回true
if set.contains(nums[i]) {
return true
}
// 添加新元素
set.insert(nums[i])
if set.count > k {
set.remove(nums[i - k])
}
}
return false
}
}
```

View File

@ -164,3 +164,23 @@ public:
};
```
Swift Code
```swift
class Solution {
func removeElement(_ nums: inout [Int], _ val: Int) -> Int {
if nums.count == 0 {
return 0
}
var i = 0
for j in 0..<nums.count {
if nums[j] != val {
nums[i] = nums[j]
i += 1
}
}
return i
}
}
```

View File

@ -89,6 +89,33 @@ class Solution:
return len(res)
```
Swift Code
```swift
class Solution {
func firstMissingPositive(_ nums: [Int]) -> Int {
if nums.count == 0 {
return 1
}
// 因为是返回第一个正整数不包括 0所以需要长度加1细节1
var res:[Int] = Array.init(repeating: 0, count: nums.count + 1)
// 将数组元素添加到辅助数组中
for x in nums {
if x > 0 && x < res.count {
res[x] = x
}
}
// 遍历查找,发现不一样时直接返回
for i in 1..<res.count {
if res[i] != i {
return i
}
}
// 缺少最后一个例如 123此时缺少 4 细节2
return res.count
}
}
```
我们通过上面的例子了解这个解题思想我们有没有办法不使用辅助数组完成呢我们可以使用原地置换直接在 nums 数组内将值换到对应的索引处与上个方法思路一致只不过没有使用辅助数组理解起来也稍微难理解一些
@ -166,3 +193,42 @@ class Solution:
return n + 1
```
Swift Code
```swift
class Solution {
func firstMissingPositive(_ nums: [Int]) -> Int {
var nums = nums
let len = nums.count
if len == 0 {
return 1
}
// 遍历数组
for i in 0..<len {
// 需要考虑指针移动情况大于0小于len+1不等与i+1
// 两个交换的数相等时防止死循环
while nums[i] > 0
&& nums[i] < len + 1
&& nums[i] != i + 1
&& nums[i] != nums[nums[i] - 1]
{
//nums.swapAt(i, (nums[i] - 1)) // 系统方法
self.swap(&nums, i, (nums[i] - 1)) // 自定义方法
}
}
// 遍历寻找缺失的正整数
for i in 0..<len {
if nums[i] != i + 1 {
return i + 1
}
}
return len + 1
}
func swap(_ nums: inout [Int], _ i: Int, _ j: Int) {
let temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
}
}
```

View File

@ -84,6 +84,32 @@ class Solution:
return max(maxcount, right - left)
```
Swift Code
```swift
class Solution {
func findMaxConsecutiveOnes(_ nums: [Int]) -> Int {
var left = 0, right = 0, res = 0
let len = nums.count
while right < len {
if nums[right] == 1 {
right += 1
continue
}
// 保存最大值
res = max(res, right - left)
// 跳过 0 的情况
while right < len && nums[right] == 0 {
right += 1
}
// 同一起点继续遍历
left = right
}
return max(res, right - left)
}
}
```
刚才的效率虽然相对高一些但是代码不够优美欢迎各位改进下面我们说一下另外一种情况一个特别容易理解的方法
@ -132,3 +158,22 @@ class Solution:
return ans
```
Swift Code
```swift
class Solution {
func findMaxConsecutiveOnes(_ nums: [Int]) -> Int {
let len = nums.count
var maxCount = 0, count = 0
for i in 0..<len {
if nums[i] == 1 {
count += 1
} else { // 这里可以改成 while
maxCount = max(maxCount, count)
count = 0
}
}
return max(maxCount, count)
}
}
```

View File

@ -156,5 +156,40 @@ class Solution:
return arr
```
Swift Code
```swift
class Solution {
func spiralOrder(_ matrix: [[Int]]) -> [Int] {
var arr:[Int] = []
var left = 0, right = matrix[0].count - 1
var top = 0, down = matrix.count - 1
while (true) {
for i in left...right {
arr.append(matrix[top][i])
}
top += 1
if top > down { break }
for i in top...down {
arr.append(matrix[i][right])
}
right -= 1
if left > right { break}
for i in stride(from: right, through: left, by: -1) {
arr.append(matrix[down][i])
}
down -= 1
if top > down { break}
for i in stride(from: down, through: top, by: -1) {
arr.append(matrix[i][left])
}
left += 1
if left > right { break}
}
return arr
}
}
```

View File

@ -45,6 +45,8 @@ class Solution {
Python3版本的代码会超时
Swift版本的代码会超时
下面我们我们使用前缀和的方法来解决这个题目那么我们先来了解一下前缀和是什么东西其实这个思想我们很早就接触过了见下图
![](https://cdn.jsdelivr.net/gh/tan45du/github.io.phonto2@master/myphoto/微信截图_20210113193831.4wk2b9zc8vm0.png)
@ -160,3 +162,27 @@ class Solution {
}
```
Swift Code
```swift
class Solution {
func subarraySum(_ nums: [Int], _ k: Int) -> Int {
if nums.count == 0 {
return 0
}
var map: [Int: Int] = [:]
map[0] = 1 // 需要添加入一个元素垫底已支持前几位就满足的情况
var presum = 0, count = 0
for x in nums {
presum += x
//当前前缀和已知判断是否含有 presum - k的前缀和那么我们就知道某一区间的和为 k
if let v = map[presum - k] {
count += v //获取presum-k前缀和出现次数
}
map[presum] = (map[presum] ?? 0) + 1
}
return count
}
}
```

View File

@ -176,6 +176,43 @@ public:
};
```
Swift Code:
```swift
class Solution {
func spiralOrder(_ matrix: [[Int]]) -> [Int] {
var arr:[Int] = []
var left = 0, right = matrix[0].count - 1
var top = 0, down = matrix.count - 1
while (true) {
for i in left...right {
arr.append(matrix[top][i])
}
top += 1
if top > down { break }
for i in top...down {
arr.append(matrix[i][right])
}
right -= 1
if left > right { break}
for i in stride(from: right, through: left, by: -1) {
arr.append(matrix[down][i])
}
down -= 1
if top > down { break}
for i in stride(from: down, through: top, by: -1) {
arr.append(matrix[i][left])
}
left += 1
if left > right { break}
}
return arr
}
}
```
我们仅仅是将 54 反过来了往螺旋矩阵里面插值下面我们直接看代码吧,大家可以也可以对其改进大家可以思考一下如果修改能够让代码更简洁
Java Code:
@ -298,3 +335,44 @@ public:
};
```
Swift Code:
```swift
class Solution {
func generateMatrix(_ n: Int) -> [[Int]] {
var arr:[[Int]] = Array.init(repeating: Array.init(repeating: 0, count: n), count: n)
var left = 0, right = n - 1
var top = 0, bottom = n - 1
var num = 1, numSize = n * n
while true {
for i in left...right {
arr[top][i] = num
num += 1
}
top += 1
if num > numSize { break}
for i in top...bottom {
arr[i][right] = num
num += 1
}
right -= 1
if num > numSize { break}
for i in stride(from: right, through: left, by: -1) {
arr[bottom][i] = num
num += 1
}
bottom -= 1
if num > numSize { break}
for i in stride(from: bottom, through: top, by: -1) {
arr[i][left] = num
num += 1
}
left += 1
if num > numSize { break}
}
return arr
}
}
```

View File

@ -103,3 +103,23 @@ public:
};
```
Swift Code:
```swift
class Solution {
func plusOne(_ digits: [Int]) -> [Int] {
let count = digits.count
var digits = digits
for i in stride(from: count - 1, through: 0, by: -1) {
digits[i] = (digits[i] + 1) % 10
if digits[i] != 0 {
return digits
}
}
var arr: [Int] = Array.init(repeating: 0, count: count + 1)
arr[0] = 1
return arr
}
}
```

View File

@ -117,6 +117,38 @@ public:
};
```
Swift Code:
```swift
class Solution {
func sortColors(_ nums: inout [Int]) {
let count = nums.count
var left = 0, i = left, right = count - 1
while i <= right {
if nums[i] == 2 {
//nums.swapAt(i, right) 直接调用系统方法
self.swap(&nums, i, right) // 保持风格统一走自定义交换
right -= 1
} else if nums[i] == 0 {
//nums.swapAt(i, left) 直接调用系统方法
self.swap(&nums, i, left) // 保持风格统一走自定义交换
i += 1
left += 1
} else {
i += 1
}
}
}
func swap(_ nums: inout [Int], _ i: Int, _ j: Int) {
let temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
}
}
```
另外我们看这段代码有什么问题呢那就是我们即使完全符合时仍会交换元素这样会大大降低我们的效率
例如[0,0,0,1,1,1,2,2,2]
@ -220,3 +252,37 @@ public:
};
```
Swift Code:
```swift
class Solution {
func sortColors(_ nums: inout [Int]) {
let count = nums.count
var left = 0, i = left, right = count - 1
while i <= right {
if nums[i] == 0 {
//nums.swapAt(i, left) 直接调用系统方法
self.swap(&nums, i, left) // 保持风格统一走自定义交换
left += 1
}
if nums[i] == 2 {
//nums.swapAt(i, right) 直接调用系统方法
self.swap(&nums, i, right) // 保持风格统一走自定义交换
right -= 1
//如果不等于 1 则需要继续判断所以不移动 i 指针i--
if nums[i] != 1 {
i -= 1
}
}
i += 1
}
}
func swap(_ nums: inout [Int], _ i: Int, _ j: Int) {
let temp = nums[i]
nums[i] = nums[j]
nums[j] = temp
}
}
```

View File

@ -61,6 +61,24 @@ class Solution:
return -1
```
Swift Code:
```swift
class Solution {
func findRepeatNumber(_ nums: [Int]) -> Int {
var set: Set<Int> = []
for n in nums {
if set.contains(n) { // 如果发现某元素存在则返回
return n
}
set.insert(n) // 存入集合
}
return -1
}
}
```
#### **原地置换**
**解析**
@ -136,3 +154,26 @@ class Solution:
nums[temp] = temp
return -1
```
Swift Code:
```swift
class Solution {
func findRepeatNumber(_ nums: [Int]) -> Int {
if nums.isEmpty {
return -1
}
var nums = nums;
for i in 0..<nums.count {
while nums[i] != i {
if nums[i] == nums[nums[i]] {
return nums[i]
}
nums.swapAt(i, nums[i])
}
}
return -1
}
}
```

View File

@ -106,3 +106,22 @@ class Solution:
return windowlen
```
Swift Code
```swift
class Solution {
func minSubArrayLen(_ target: Int, _ nums: [Int]) -> Int {
var sum = 0, windowlen = Int.max, i = 0
for j in 0..<nums.count {
sum += nums[j]
while sum >= target {
windowlen = min(windowlen, j - i + 1)
sum -= nums[i]
i += 1
}
}
return windowlen == Int.max ? 0 : windowlen
}
}
```

View File

@ -145,6 +145,35 @@ class Solution:
return True
```
Swift Code
```swift
class Solution {
func isPalindrome(_ head: ListNode?) -> Bool {
// 这里需要用动态数组因为我们不知道链表的长度
var arr:[Int?] = []
var copynode = head
// 将链表的值复制到数组中
while copynode != nil {
arr.append(copynode?.val)
copynode = copynode?.next
}
// 双指针遍历数组
var back = 0, pro = arr.count - 1
while back < pro {
// 判断两个指针的值是否相等
if arr[pro] != arr[back] {
return false
}
// 移动指针
back += 1
pro -= 1
}
return true
}
}
```
这个方法可以直接通过但是这个方法需要辅助数组那我们还有其他更好的方法吗
**双指针翻转链表法**
@ -375,3 +404,57 @@ class Solution:
return low
```
Swift Code
```swift
class Solution {
func isPalindrome(_ head: ListNode?) -> Bool {
if head == nil || head?.next == nil {
return true
}
//找到中间节点也就是翻转的头节点,这个在昨天的题目中讲到
//但是今天和昨天有一些不一样的地方就是如果有两个中间节点返回第一个昨天的题目是第二个
var midnode = searchmidnode(head)
//原地翻转链表需要两个辅助指针这个也是面试题目大家可以做一下
//这里我们用的是midnode.next需要注意因为我们找到的是中点但是我们翻转的是后半部分
var backhalf = reverse(midnode?.next);
//遍历两部分链表判断值是否相等
var p1 = head
var p2 = backhalf
while p2 != nil {
if p1?.val != p2?.val {
midnode?.next = reverse(backhalf)
return false
}
p1 = p1?.next
p2 = p2?.next
}
//还原链表并返回结果这一步是需要注意的我们不可以破坏初始结构我们只是判断是否为回文
//当然如果没有这一步也是可以AC但是面试的时候题目要求可能会有这一条
midnode?.next = reverse(backhalf)
return true
}
//找到中点
func searchmidnode(_ head: ListNode?) -> ListNode? {
var fast = head, slow = head
while fast?.next != nil && fast?.next?.next != nil {
fast = fast?.next?.next
slow = slow?.next
}
return slow
}
//翻转链表
func reverse(_ slow: ListNode?) -> ListNode? {
var slow = slow
var low: ListNode?
var temp: ListNode?
while slow != nil {
temp = slow?.next
slow?.next = low
low = slow
slow = temp
}
return low
}
}
```

View File

@ -108,3 +108,20 @@ class Solution:
return False
```
Swift Code
```swift
class Solution {
func hasCycle(_ head: ListNode?) -> Bool {
var fast = head, slow = head
while fast != nil && fast?.next != nil {
fast = fast?.next?.next
slow = slow?.next
if fast === slow {
return true
}
}
return false
}
}
```

View File

@ -132,8 +132,6 @@ class Solution:
return head
```
### 快慢指针
这个方法是比较巧妙的方法但是不容易想到也不太容易理解利用快慢指针判断是否有环很容易但是判断环的入口就没有那么容易之前说过快慢指针肯定会在环内相遇见下图
@ -275,3 +273,29 @@ class Solution:
return slow
```
Swift Code
```swift
class Solution {
func detectCycle(_ head: ListNode?) -> ListNode? {
// 快慢指针
var fast = head, slow = head
while fast != nil && fast?.next != nil {
fast = fast?.next?.next
slow = slow?.next
// 相遇
if fast === slow {
// 设置一个新的指针从头节点出发慢指针速度为1所以可以使用慢指针从相遇点出发
// 此处也可以不创新结点直接将 fast = head
var newNode = head
while newNode !== slow {
slow = slow?.next
newNode = newNode?.next
}
return slow
}
}
return nil
}
}
```

View File

@ -225,5 +225,41 @@ class Solution:
return dummyNode.next
```
Swift Code
```swift
class Solution {
func insertionSortList(_ head: ListNode?) -> ListNode? {
if head == nil && head?.next == nil {
return head
}
//哑节点
var dummyNode = ListNode(-1)
dummyNode.next = head
//pre负责指向新元素last 负责指向新元素的前一元素
//判断是否需要执行插入操作
var pre = head?.next
var last = head
while pre != nil {
//不需要插入到合适位置则继续往下移动
if last!.val <= pre!.val {
pre = pre?.next
last = last?.next
continue
}
//开始出发查找新元素的合适位置
var temphead = dummyNode
while temphead.next!.val <= pre!.val {
temphead = temphead.next!
}
//此时我们已经找到了合适位置我们需要进行插入大家可以画一画
last?.next = pre?.next
pre?.next = temphead.next
temphead.next = pre
//继续往下移动
pre = last?.next
}
return dummyNode.next
}
}
```

View File

@ -138,6 +138,32 @@ class Solution:
return low
```
Swift Code:
```swift
class Solution {
func reverseList(_ head: ListNode?) -> ListNode? {
// 边界条件
if head == nil || head?.next == nil {
return head
}
var pro = head
var low: ListNode?
while pro != nil {
// 代表橙色指针
var temp = pro
// 移动绿色指针
pro = pro?.next
// 反转节点
temp?.next = low
// 移动黄色指针
low = temp
}
return low
}
}
```
上面的迭代写法是不是搞懂啦现在还有一种递归写法不是特别容易理解刚开始刷题的同学可以只看迭代解法
@ -227,6 +253,25 @@ class Solution:
return pro
```
Swift Code:
```swift
class Solution {
func reverseList(_ head: ListNode?) -> ListNode? {
// 结束条件
if head == nil || head?.next == nil {
return head
}
var pro = reverseList(head?.next)
// 将节点进行反转
head?.next?.next = head
// 防止循环
head?.next = nil
return pro
}
}
```
<br/>
> 贡献者[@jaredliw](https://github.com/jaredliw)

View File

@ -128,3 +128,27 @@ class Solution:
return head
```
Swift Code
```swift
class Solution {
func oddEvenList(_ head: ListNode?) -> ListNode? {
if head == nil || head?.next == nil {
return head
}
var odd = head
var even = head?.next
var evenHead = even
while odd?.next != nil && even?.next != nil {
//将偶数位合在一起奇数位合在一起
odd?.next = even?.next
odd = odd?.next
even?.next = odd?.next
even = even?.next
}
//链接
odd?.next = evenHead
return head
}
}
```

View File

@ -165,3 +165,34 @@ class Solution:
return dummy.next # 注意这里传回的不是head而是虚拟节点的下一个节点head有可能已经换了
```
Swift Code
```swift
class Solution {
func deleteDuplicates(_ head: ListNode?) -> ListNode? {
// 侦察兵指针
var pre = head
// 创建哑节点接上head
var dummy = ListNode(-1)
dummy.next = head
// 跟随的指针
var low:ListNode? = dummy
while pre != nil && pre?.next != nil {
if pre?.val == pre?.next?.val {
// 移动侦察兵指针直到找到与上一个不相同的元素
while pre != nil && pre?.next != nil && pre?.val == pre?.next?.val {
pre = pre?.next
}
// while循环后pre停留在最后一个重复的节点上
pre = pre?.next
// 连上新节点
low?.next = pre
} else {
pre = pre?.next
low = low?.next
}
}
return dummy.next // 注意这里传回的不是head而是虚拟节点的下一个节点head有可能已经换了
}
}
```

View File

@ -157,3 +157,34 @@ class Solution:
return headsmall.next
```
Swift Code
```swift
class Solution {
func partition(_ head: ListNode?, _ x: Int) -> ListNode? {
var pro = head
var big = ListNode(-1)
var small = ListNode(-1)
var headbig = big
var headsmall = small
//
while pro != nil {
//大于时放到 big 链表上
if pro!.val >= x {
big.next = pro
big = big.next!
//小于时放到 small 链表上
} else {
small.next = pro
small = small.next!
}
pro = pro?.next
}
//细节
big.next = nil
//
small.next = headbig.next
return headsmall.next
}
}
```

View File

@ -218,3 +218,50 @@ class Solution:
return low
```
Swift Code
```swift
class Solution {
func reverseBetween(_ head: ListNode?, _ left: Int, _ right: Int) -> ListNode? {
// 虚拟头结点
var temp = ListNode(-1)
temp.next = head
var pro:ListNode? = temp
// 来到 left 节点前的一个节点
var i = 0
for n in i..<left - 1 {
pro = pro?.next
i += 1
}
// 保存 left 节点前的一个节点
var leftNode = pro
// 来到 right 节点
for n in i..<right {
pro = pro?.next
}
// 保存 right 节点后的一个节点
var rightNode:ListNode? = pro?.next
// 切断链表
pro?.next = nil // 切断 right 后的部分
var newHead:ListNode? = leftNode?.next // 保存 left 节点
leftNode?.next = nil // 切断 left 前的部分
// 反转
leftNode?.next = reverse(newHead)
// 重新接头
newHead?.next = rightNode
return temp.next
}
// 和反转链表1代码一致
func reverse(_ head: ListNode?) -> ListNode? {
var low:ListNode?
var pro = head
while pro != nil {
var temp = pro
pro = pro?.next
temp?.next = low
low = temp
}
return low
}
}
```

View File

@ -123,3 +123,27 @@ class Solution:
return headtemp.next
```
Swift Code
```swift
class Solution {
func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
var l1 = l1, l2 = l2
var headpro: ListNode? = ListNode(-1)
var headtemp = headpro
while l1 != nil && l2 != nil {
//接上大的那个
if l1!.val >= l2!.val {
headpro?.next = l2
l2 = l2!.next
} else {
headpro?.next = l1
l1 = l1!.next
}
headpro = headpro?.next
}
headpro?.next = l1 != nil ? l1 : l2
return headtemp?.next
}
}
```

View File

@ -135,6 +135,40 @@ class Solution:
return tempb
```
Swift Code
```swift
class Solution {
func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? {
var tempa = headA
var tempb = headB
var arr:Set<ListNode> = []
//遍历链表A将所有值都存到arr中
while tempa != nil {
arr.insert(tempa!)
tempa = tempa?.next
}
//遍历列表B如果发现某个结点已在arr中则直接返回该节点
while tempb != nil {
if arr.contains(tempb!) {
return tempb
}
tempb = tempb?.next
}
//若上方没有返回此刻tempb为null
return tempb
}
}
extension ListNode: Hashable, Equatable {
public func hash(into hasher: inout Hasher) {
hasher.combine(val)
hasher.combine(ObjectIdentifier(self))
}
public static func ==(lhs: ListNode, rhs: ListNode) -> Bool {
return lhs === rhs
}
}
```
下面这个方法比较巧妙不是特别容易想到大家可以自己实现一下这个方法也是利用我们的双指针思想
@ -221,6 +255,25 @@ class Solution:
return tempa # 返回tempb也行
```
Swift Code
```swift
class Solution {
func getIntersectionNode(_ headA: ListNode?, _ headB: ListNode?) -> ListNode? {
//定义两个节点
var tempa = headA
var tempb = headB
//循环
while tempa != tempb {
// 如果不为空就指针下移为空就跳到另一链表的头部
tempa = tempa != nil ? tempa?.next : headB
tempb = tempb != nil ? tempb?.next : headA
}
return tempa //返回tempb也行
}
}
```
好啦链表的题目就结束啦希望大家能有所收获下周就要更新新的题型啦继续坚持肯定会有收获的
<br/>

View File

@ -136,3 +136,28 @@ class Solution:
return after
```
Swift Code
```swift
class Solution {
func getKthFromEnd(_ head: ListNode?, _ k: Int) -> ListNode? {
//特殊情况
if head == nil {
return head
}
//初始化两个指针
var pro = head, after = head
//先移动绿指针到指定位置
for i in 0..<k-1 {
pro = pro?.next
}
//两个指针同时移动
while pro?.next != nil {
pro = pro?.next
after = after?.next
}
//返回倒数第k个节点
return after
}
}
```

View File

@ -118,3 +118,20 @@ class Solution:
return slow
```
Swift Code
```swift
class Solution {
func middleNode(_ head: ListNode?) -> ListNode? {
var fast = head //快指针
var slow = head //慢指针
//循环条件思考一下跳出循环的情况
while fast != nil && fast?.next != nil {
fast = fast?.next?.next
slow = slow?.next
}
//返回slow指针指向的节点
return slow
}
}
```

View File

@ -230,3 +230,42 @@ class Solution:
return nList.next # 去除哑节点
```
Swift Code
```swift
class Solution {
func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
var l1 = l1, l2 = l2
var nList = ListNode(-1) // 哑节点
var tempnode = nList
// 用来保存进位值初始化为0
var summod = 0
while l1 != nil || l2 != nil {
// 链表的节点值
let l1num = l1?.val ?? 0
let l2num = l2?.val ?? 0
// 将链表的值和进位值相加得到为返回链表的值
var sum = l1num + l2num + summod
// 更新进位值例18/10=19/10=0
summod = sum / 10
// 新节点保存的值18%8=2则添加2
sum = sum % 10
// 添加节点
tempnode.next = ListNode(sum)
// 移动指针
tempnode = tempnode.next!
if l1 != nil {
l1 = l1?.next
}
if l2 != nil {
l2 = l2?.next
}
}
// 最后根据进位值判断需不需要继续添加节点
if (summod != 0) {
tempnode.next = ListNode(summod)
}
return nList.next //去除哑节点
}
}
```