diff --git a/Week_01/DequeDemo.java b/Week_01/DequeDemo.java new file mode 100644 index 00000000..0178a823 --- /dev/null +++ b/Week_01/DequeDemo.java @@ -0,0 +1,22 @@ + +public class DequeDemo { + public static void main(String[] args) { + System.out.println("Hello, world!"); + Deque deque = new LinkedList(); + deque.addLast("a"); + deque.addLast("b"); + deque.addLast("c"); + System.out.println(deque); + + String str = deque.peek(); + System.out.println(str); + System.out.println(deque); + while (deque.size() > 0) { + System.out.println(deque.removeFirst()); + } + System.out.println(deque); + } +} + + + diff --git a/Week_01/MyCircularDeque b/Week_01/MyCircularDeque new file mode 100755 index 00000000..3f1e5b6c Binary files /dev/null and b/Week_01/MyCircularDeque differ diff --git a/Week_01/MyCircularDeque.c b/Week_01/MyCircularDeque.c new file mode 100644 index 00000000..25b88108 --- /dev/null +++ b/Week_01/MyCircularDeque.c @@ -0,0 +1,125 @@ + +#include +#include +#include + +typedef struct { + int *arr; + int head; + int tail; + int size; +} MyCircularDeque; + +bool myCircularDequeIsFull(MyCircularDeque* obj); +bool myCircularDequeIsEmpty(MyCircularDeque* obj); + +/** Initialize your data structure here. Set the size of the deque to be k. */ + +MyCircularDeque* myCircularDequeCreate(int k) { + MyCircularDeque *obj = (MyCircularDeque *)malloc(sizeof(MyCircularDeque)); + obj->head = 0; + obj->tail = 0; + obj->size = k + 1; + obj->arr = (int *)malloc(sizeof(int) * (k + 1)); + return obj; +} + +/** Adds an item at the front of Deque. Return true if the operation is successful. */ +bool myCircularDequeInsertFront(MyCircularDeque* obj, int value) { + if (myCircularDequeIsFull(obj)) return false; + int pos = (obj->head + obj->size - 1) % obj->size; + obj->arr[pos] = value; + obj->head = pos; + return true; +} + +/** Adds an item at the rear of Deque. Return true if the operation is successful. */ +bool myCircularDequeInsertLast(MyCircularDeque* obj, int value) { + if (myCircularDequeIsFull(obj)) return false; + obj->arr[obj->tail] = value; + obj->tail = (obj->tail + 1) % obj->size; + return true; +} + +/** Deletes an item from the front of Deque. Return true if the operation is successful. */ +bool myCircularDequeDeleteFront(MyCircularDeque* obj) { + if (myCircularDequeIsEmpty(obj)) return false; + obj->head = (obj->head + 1) % obj->size; + return true; +} + +/** Deletes an item from the rear of Deque. Return true if the operation is successful. */ +bool myCircularDequeDeleteLast(MyCircularDeque* obj) { + if (myCircularDequeIsEmpty(obj)) return false; + obj->tail = (obj->size + obj->tail - 1) % obj->size; + return true; +} + +/** Get the front item from the deque. */ +int myCircularDequeGetFront(MyCircularDeque* obj) { + if (myCircularDequeIsEmpty(obj)) return -1; + return obj->arr[obj->head]; +} + +/** Get the last item from the deque. */ +int myCircularDequeGetRear(MyCircularDeque* obj) { + if (myCircularDequeIsEmpty(obj)) return -1; + int pos = (obj->tail - 1 + obj->size) % obj->size; + return obj->arr[pos]; +} + +/** Checks whether the circular deque is empty or not. */ +bool myCircularDequeIsEmpty(MyCircularDeque* obj) { + return (obj->head == obj->tail) ? true : false; +} + +/** Checks whether the circular deque is full or not. */ +bool myCircularDequeIsFull(MyCircularDeque* obj) { + return ((obj->head - 1 + obj->size) % obj->size == obj->tail) ? true : false; +} + +int myCircularDequeLength(MyCircularDeque* obj) { + if (obj->tail > obj->head) { + return obj->tail - obj->head; + } else { + return obj->tail - obj->head + obj->size; + } +} + +void myCircularDequeFree(MyCircularDeque* obj) { + free(obj->arr); + free(obj); + return; +} + +void PrintDeque(MyCircularDeque *obj); + +int main(int argc, const char *argv[]) { + MyCircularDeque *obj = myCircularDequeCreate(5); + myCircularDequeInsertFront(obj, 10); + myCircularDequeInsertFront(obj, 20); + myCircularDequeInsertFront(obj, 30); + myCircularDequeInsertLast(obj, 0); + myCircularDequeInsertLast(obj, 1); + myCircularDequeDeleteLast(obj); + int front = myCircularDequeGetFront(obj); + int rear = myCircularDequeGetRear(obj); + printf("front=%d, rear=%d\n", front, rear); + PrintDeque(obj); + return 0; +} + +// 打印 +void PrintDeque(MyCircularDeque *obj) { + printf("head=%d, tail=%d, size=%d\n", obj->head, obj->tail, obj->size); + printf("arr=["); + int length = myCircularDequeLength(obj); + int max = obj->head + length; + for (int i = obj->head; i < max; i++) { + printf("%d", obj->arr[i % obj->size]); + if (i != max - 1) { + printf(", "); + } + } + printf("]\n"); +} \ No newline at end of file diff --git a/Week_01/README.md b/Week_01/README.md index 50de3041..682047b9 100644 --- a/Week_01/README.md +++ b/Week_01/README.md @@ -1 +1,69 @@ -学习笔记 \ No newline at end of file +## 学习笔记 + +#### 学习感想 + +原本我觉得学习算法是一个比较枯燥乏味的事情,因为本身的基础不是很好,对数据结构学习不多,平时自己学习很难坚持,但是和大家一起刷题后感觉每解答出一道题还是挺有成就感的,尤其是当自己辛苦编码调试通过后的那一刻,感觉很畅快和欣慰。而且,当看到别人的算法清晰,代码简单的时候,心里莫名的崇拜,奈何没什么文化,只能感叹一声“NB”。哈哈,原来做题也能这么有意思。希望自己能和大家一起学习,坚持这十周让自己有所突破和进步。 + +#### 根据超哥的介绍自己也稍微总结了下刷题的步骤: + +- 想:思考怎么做,不要过于强求,没有思路不用纠结,直接看题解; +- 写:看过题解后,编写代码,可以选择多种实现方式,成功通过后,分析时间复杂度和空间复杂度; +- 看:看看国外网站讨论比较多的大神是如何解答的,学习优秀的思想和算法; +- 练:选择自己觉的比较好的算法,进行多次练习(五毒神掌),最好达到看到类似的题,马上能想到并正确写出代码; +- 记:在完成以上内容后,可以将思路和代码整理,写成题解(选做:根据时间情况而定)。 + +#### 基本数据结构 + +- 数组(顺序结构) + - 可以快速的查找元素,随机访问,时间复杂度O(1) + - 插入删除需要搬移数据,时间复杂度O(n) + - 无需为逻辑关系而增加额外的存储空间。 + +- 链表 + - 不支持随机访问,时间复杂度O(n) + - 插入和删除便捷,时间复杂度O(1) + - 比数组占用更多的存储空间。 + - 单链表,next + - 双向链表,prev和next + - 循环链表,尾结点指向头结点 + - 静态链表,数组描述的链表 + +- 栈 + - 先进后出 + - 入栈出栈时间复杂度O(1) + - 应用:浏览器前进后退、括号匹配、表达式计算 + +- 队列 + - 先进先出 + - 入队出队时间复杂度O(1) + - 应用:LRU Cache、操作有限资源 + - 双边队列:入口出口都可以入队出队(可作为栈和队列使用) + - 优先级队列:根据优先级出队 + - 循环队列:头尾相连,空出一个位置不用 + - 队空条件(front==rear) + - 队满条件(rear+1)%size==front + +#### 进阶数据结构 + +- 跳表 + - 有序链表 + - 插入删除搜索时间复杂度O(logn) + - 空间复杂度O(n),典型的空间换时间 + - 增加索引,维护成本高 + - 应用:Redis、LevelDB + +#### 迭代和递归 + +斐波那契数列是个典型的例子。 + +- 递归 + - 必须有递归终止条件 + - 直接或间接调用自己 + - 选择结构,使程序更简洁易懂 + - 但是大量递归建立函数的副本,耗费大量空间时间 + +- 迭代 + - 循环结构 + - 不需要反复调用 + - 不需要占用额外内存 + diff --git a/Week_01/Week01 b/Week_01/Week01 new file mode 100755 index 00000000..b4941e9a Binary files /dev/null and b/Week_01/Week01 differ diff --git a/Week_01/Week01.c b/Week_01/Week01.c new file mode 100644 index 00000000..1fce7fe1 --- /dev/null +++ b/Week_01/Week01.c @@ -0,0 +1,257 @@ + +#include +#include +#include +#include + +// 打印int数组 +void PrintIntArray(int *a, int size); +// 加一测试 +void TestPlusOne(); +//删除排序数组中的重复项测试 +void testRemoveDuplicates(); +//旋转数组测试 +void testRotate(); + +int main(int argc, const char *argv[]) { + //testPlusOne(); + //testRemoveDuplicates(); + //testRotate(); + return 0; +} + +/* 加一 */ +int* plusOne(int* digits, int digitsSize, int* returnSize) { + for (int i = digitsSize - 1; i >= 0; i--) { + if (digits[i] < 9) { + digits[i]++; + *returnSize = digitsSize; + return digits; + } + digits[i] = 0; + } + *returnSize = digitsSize + 1; + int *newDigits = (int *)malloc(sizeof(int) * (*returnSize)); + memset(newDigits, 0, (*returnSize) * sizeof(int)); + newDigits[0] = 1; + return newDigits; +} + +void testPlusOne() { + int a[] = {0, 0}; + int digitsSize = sizeof(a) / sizeof(int); + int returnSize = 0; + int *result = plusOne(a, digitsSize, &returnSize); + PrintIntArray(result, returnSize); +} + +/* 26、删除排序数组中的重复项 */ +int removeDuplicates(int* nums, int numsSize){ + if (numsSize <= 1) return numsSize; + int i = 0; + for (int j = 1; j < numsSize; j++) { + if (nums[j] != nums[i]) { + i++; + nums[i] = nums[j]; + } + } + return i + 1; +} + +void testRemoveDuplicates() { + int a[] = {0, 0, 1, 2, 2, 2, 4, 6, 6, 9}; + int size = sizeof(a) / sizeof(int); + int result = removeDuplicates(a, size); + printf("resultSize = %d\n", result); + PrintIntArray(a, result); +} + +/* 189. 旋转数组 */ + +//暴力求解 +void rotate01(int* nums, int numsSize, int k) { + k %= numsSize; + int temp, prev; + for (int i = 0; i < k; i++) { + prev = nums[numsSize - 1]; + for (int j = 0; j < numsSize; j++) { + temp = prev; + prev = nums[j]; + nums[j] = temp; + } + } +} + +//使用环状替换 +void rotate02(int* nums, int numsSize, int k) { + k %= numsSize; + int count = 0; + for (int start = 0; count < numsSize; start++) { + int current = start; + int prev = nums[start]; + do { + int next = (current + k) % numsSize; + int temp = nums[next]; + nums[next] = prev; + prev = temp; + current = next; + count++; + } while (start != current); + } +} + +//三次翻转(推荐,思路清晰,代码简洁) +void reverse(int *nums, int start, int end); + +void rotate03(int* nums, int numsSize, int k) { + k %= numsSize; + reverse(nums, 0, numsSize - 1); + reverse(nums, 0, k - 1); + reverse(nums, k, numsSize - 1); +} + +void reverse(int *nums, int start, int end) { + while (start < end) { + int temp = nums[start]; + nums[start] = nums[end]; + nums[end] = temp; + start++; + end--; + } +} + +void testRotate() { + int a[] = {0, 1, 2, 3, 4, 5, 6, 7}; + int size = sizeof(a) / sizeof(int); + //rotate01(a, size, 3); + //rotate02(a, size, 3); + rotate03(a, size, 3); + PrintIntArray(a, size); +} + +/* 合并两个有序链表 */ +struct ListNode { + int val; + struct ListNode *next; +}; + +struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) { + if (!l1) return l2; + if (!l2) return l1; + if (l1->val < l2->val) { + l1->next = mergeTwoLists(l1->next, l2); + return l1; + } else { + l2->next = mergeTwoLists(l1, l2->next); + return l2; + } +} + +/* 88、合并两个有序数组 */ +void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) { + int p = m + n - 1, p1 = m - 1, p2 = n - 1; + while (p2 >= 0) { + if (p1 >= 0) { + nums1[p--] = nums1[p1] > nums2[p2] ? nums1[p1--] : nums2[p2--]; + } else { + nums1[p--] = nums2[p2--]; + } + } +} + +/* 1、两数之和 */ +//暴力 +int* twoSum(int* nums, int numsSize, int target, int* returnSize){ + for (int i = 0; i < numsSize; i++) { + for (int j = i + 1; j < numsSize; j++) { + if (nums[i] + nums[j] == target) { + int *result = (int *)malloc(sizeof(int) * 2); + result[0] = i; + result[1] = j; + *returnSize = 2; + return result; + } + } + } + *returnSize = 0; + return NULL; +} +//哈希表 + +/* 283、移动零 */ +void moveZeroes(int* nums, int numsSize) { + int j = 0; + for (int i = 0; i < numsSize; i++) { + if (nums[i]) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + j++; + } + } +} + +/* 70、爬楼梯 */ +int climbStairs(int n) { + int p = 0, q = 0, r = 1; + for (int i = 1; i <= n; i++) { + p = q; + q = r; + r = p + q; + } + return r; +} + +/* 42、接雨水 */ +int trap(int* height, int heightSize){ + int left = 0, right = heightSize - 1; + int ans = 0; + int left_max = 0, right_max = 0; + while (left < right) { + if (height[left] < height[right]) { + if (height[left] >= left_max) { + left_max = height[left]; + } else { + ans += (left_max - height[left]); + } + left++; + } else { + if (height[right] >= right_max) { + right_max = height[right]; + } else { + ans += (right_max - height[right]); + } + right--; + } + } + return ans; +} + +/* 141、环形链表 */ +//快慢指针 +bool hasCycle(struct ListNode *head) { + struct ListNode *fast = head; + struct ListNode *slow = head; + while (fast && fast->next) { + fast = fast->next->next; + slow = slow->next; + if (fast == slow) return true; + } + return false; +} + +/* 工具方法 */ + +// 打印int数组 +void PrintIntArray(int *a, int size) { + printf("["); + for (int i = 0; i < size; i++) { + printf("%d", a[i]); + if (i != size - 1) { + printf(", "); + } + } + printf("]\n"); +} + + diff --git "a/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/QuickLook/Preview.jpg" "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/QuickLook/Preview.jpg" new file mode 100644 index 00000000..5490195a Binary files /dev/null and "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/QuickLook/Preview.jpg" differ diff --git "a/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/contents.xml" "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/contents.xml" new file mode 100644 index 00000000..c13b1a54 Binary files /dev/null and "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/contents.xml" differ diff --git "a/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/style.mindnodestyle/contents.xml" "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/style.mindnodestyle/contents.xml" new file mode 100644 index 00000000..dcc4788c Binary files /dev/null and "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/style.mindnodestyle/contents.xml" differ diff --git "a/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/style.mindnodestyle/metadata.plist" "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/style.mindnodestyle/metadata.plist" new file mode 100644 index 00000000..87c08d88 Binary files /dev/null and "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/style.mindnodestyle/metadata.plist" differ diff --git "a/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/viewState.plist" "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/viewState.plist" new file mode 100644 index 00000000..31c77803 Binary files /dev/null and "b/Week_01/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.mindnode/viewState.plist" differ diff --git a/Week_02/AddDigits.swift b/Week_02/AddDigits.swift new file mode 100644 index 00000000..8fc5afdc --- /dev/null +++ b/Week_02/AddDigits.swift @@ -0,0 +1,44 @@ +// +// AddDigits.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/11. +// + +import Foundation + +class AddDigits { + /// 各位相加 + /* + 思考 + x*100 + y*10 + z = x*99 + y*9 + x+y+z + */ + + func addDigits(_ num: Int) -> Int { + return (num - 1) % 9 + 1 + } + + func addDigits01(_ num: Int) -> Int { + if num % 9 == 0 { + return num == 0 ? num : 9 + } else { + return num % 9 + } + } + + /// 递归 + func addDigits02(_ num: Int) -> Int { + if num < 10 { + return num + } else { + var sum = 0 + var temp = num + while temp != 0 { + sum += temp % 10; + temp /= 10; + } + return addDigits(sum) + } + } + +} diff --git a/Week_02/BinaryTree.swift b/Week_02/BinaryTree.swift new file mode 100644 index 00000000..a3603467 --- /dev/null +++ b/Week_02/BinaryTree.swift @@ -0,0 +1,230 @@ +// +// BinaryTree.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/12. +// + +import Foundation + +class BinaryTree { + + // MARK: 中序遍历 + + /// 递归 + func inorderTraversal(_ root: TreeNode?) -> [Int] { + guard let root = root else { + return [] + } + var res = [Int]() + res.append(contentsOf: inorderTraversal(root.left)) + res.append(root.val) + res.append(contentsOf: inorderTraversal(root.right)) + return res + } + + /// 迭代 + func inorderTraversal10(_ root: TreeNode?) -> [Int] { + var stack = [TreeNode]() + var res = [Int]() + var node = root + while node != nil || !stack.isEmpty { + while node != nil { + //如果有左节点,一直向左 + stack.append(node!) + node = node!.left + } + //结果 + node = stack.popLast() + res.append(node!.val) + //右边节点 + node = node?.right + } + return res + } + /// 迭代 + func inorderTraversal11(_ root: TreeNode?) -> [Int] { + var stack = [TreeNode]() + var res = [Int]() + var node = root + while node != nil || !stack.isEmpty { + if node != nil { + //如果有左节点,一直向左 + stack.append(node!) + node = node!.left + } else { + //结果 + node = stack.popLast() + res.append(node!.val) + //右边节点 + node = node?.right + } + } + return res + } + + /* + Morris 算法 + 1.current如果没有有左子节点,直接加入结果,current向右走一步 + 2.predecessor节点就是当前current节点向左走一步,然后一直向右走至无法走为止 + 3.predecessor处于最右,若不等于current,将predecessor右子节点指向current + 4.predecessor等于current说明遍历完左子树,断开链接,current向右走一步 + */ + func inorderTraversal20(_ root: TreeNode?) -> [Int] { + var res = [Int]() + var current = root + var predecessor: TreeNode? = nil + while current != nil { + // 如果没有左子节点,则直接访问右子节点 + if current!.left == nil { + res.append(current!.val) + current = current!.right + continue + } + //predecessor 节点就是当前 root 节点向左走一步 然后一直向右走至无法走为止 + predecessor = current!.left + while predecessor!.right != nil && predecessor!.right !== current { + predecessor = predecessor!.right + } + + if predecessor!.right === current { + // 说明左子树已经访问完了,我们需要断开链接 + predecessor!.right = nil + res.append(current!.val) + current = current!.right + } else { + // 让 predecessor 的右指针指向 root,继续遍历左子树 + predecessor!.right = current + current = current!.left + } + } + return res + } + + // MARK: 前序遍历 + + /// 递归 + func preorderTraversal(_ root: TreeNode?) -> [Int] { + guard let root = root else { + return [] + } + var res: [Int] = [] + res.append(root.val) + res.append(contentsOf: preorderTraversal(root.left)) + res.append(contentsOf: preorderTraversal(root.right)) + return res + } + + /// 迭代 + func preorderTraversal10(_ root: TreeNode?) -> [Int] { + var stack = [TreeNode]() + var res = [Int]() + var node = root + while node != nil || !stack.isEmpty { + while node != nil { + //节点加入 + res.append(node!.val) + //有左一直向左 + stack.append(node!) + node = node!.left + } + node = stack.popLast() + //右边节点 + node = node?.right + } + return res + } + + /// 迭代 + func preorderTraversal11(_ root: TreeNode?) -> [Int] { + var res = [Int]() + guard let root = root else { + return res + } + var stack = [root] + while !stack.isEmpty { + let node = stack.popLast() + res.append(node!.val) + if node!.right != nil { + stack.append(node!.right!) + } + if node!.left != nil { + stack.append(node!.left!) + } + } + return res + } + + // MARK: 后序遍历 + + /// 递归 + func postorderTraversal(_ root: TreeNode?) -> [Int] { + guard let root = root else { + return [] + } + var res = [Int]() + res.append(contentsOf: postorderTraversal(root.left)) + res.append(contentsOf: postorderTraversal(root.right)) + res.append(root.val) + return res + } + + /// 迭代 + func postorderTraversal01(_ root: TreeNode?) -> [Int] { + var stack = [TreeNode]() + var res = [Int]() + var node = root + var prev: TreeNode? = nil + while node != nil || !stack.isEmpty { + //一路向左 + while node != nil { + stack.append(node!) + node = node!.left + } + node = stack.popLast() + //右子节点等于nil,没有右子节点 + //右子节点等于prev,遍历完右子节点回到根节点 + if node?.right == nil || node?.right === prev { + //值加入结果并设置为上次遍历值 + res.append(node!.val) + prev = node + //node设置为空,循环继续从栈内取值 + node = nil + } else { + //右子节点不为空,节点加入栈 + stack.append(node!) + //向右走 + node = node!.right + } + } + return res + } + +} + +// MARK: - + +public class TreeNode { + public var val: Int + public var left: TreeNode? + public var right: TreeNode? + + public init() { + self.val = 0; + self.left = nil; + self.right = nil; + } + + public init(_ val: Int) { + self.val = val; + self.left = nil; + self.right = nil; + } + + public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + self.val = val + self.left = left + self.right = right + } +} + diff --git a/Week_02/FizzBuzz.swift b/Week_02/FizzBuzz.swift new file mode 100644 index 00000000..70170832 --- /dev/null +++ b/Week_02/FizzBuzz.swift @@ -0,0 +1,66 @@ +// +// FizzBuzz.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/10. +// + +import Foundation + +class FizzBuzz { + + func fizzBuzz(_ n: Int) -> [String] { + var res = [String]() + let dic = [3: "Fizz", 5: "Buzz"] + for i in 1...n { + var string = "" + for key in dic.keys.sorted(by: <) { + if i % key == 0 { + string.append(dic[key]!) + } + } + if string == "" { + string.append(String(i)) + } + res.append(string) + } + return res + } + + func fizzBuzz01(_ n: Int) -> [String] { + var res = [String]() + for i in 1...n { + var string = "" + if i % 3 == 0 { + string.append("Fizz") + } + if i % 5 == 0 { + string.append("Buzz") + } + if string == "" { + string.append(String(i)) + } + res.append(string) + } + return res + } + + func fizzBuzz02(_ n: Int) -> [String] { + var res = [String]() + for i in 1...n { + var string = "" + if i % 3 == 0 && i % 5 == 0 { + string.append("FizzBuzz") + } else if i % 3 == 0 { + string.append("Fizz") + } else if i % 5 == 0 { + string.append("Buzz") + } + if string == "" { + string.append(String(i)) + } + res.append(string) + } + return res + } +} diff --git a/Week_02/GroupAnagrams.swift b/Week_02/GroupAnagrams.swift new file mode 100644 index 00000000..e6953e30 --- /dev/null +++ b/Week_02/GroupAnagrams.swift @@ -0,0 +1,28 @@ +// +// GroupAnagrams.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/12. +// + +import Foundation + +class GroupAnagrams { + + func groupAnagrams(_ strs: [String]) -> [[String]] { + var hashMap = [String: [String]]() + for str in strs { + let key = String(str.sorted()) + if hashMap[key] == nil { + hashMap[key] = [] + } + hashMap[key]!.append(str) + } + return Array(hashMap.values) + } + + func test(_ strs: [String]) { + let result = groupAnagrams(strs) + print(result) + } +} diff --git a/Week_02/Intersect.swift b/Week_02/Intersect.swift new file mode 100644 index 00000000..ff50a5f5 --- /dev/null +++ b/Week_02/Intersect.swift @@ -0,0 +1,41 @@ +// +// Intersect.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/7. +// + +import Foundation + +class Intersect { + /// 350 两个数组的交集 II + func intersect(_ nums1: [Int], _ nums2: [Int]) -> [Int] { + guard nums1.count <= nums2.count else { + return intersect(nums2, nums1) + } + var hs = [Int: Int](), res = [Int]() + for num in nums1 { + if let record = hs[num] { + hs[num] = record + 1 + } else { + hs[num] = 1 + } + } + for num in nums2 { + if let record = hs[num] { + if record > 0 { + res.append(num) + hs[num] = record - 1 + } + } + } + return res + } + + func test() { + let nums1 = [1,2,2,1] + let nums2 = [2,2] + let result = intersect(nums1, nums2) + print(result) + } +} diff --git a/Week_02/LemonnadeChange.swift b/Week_02/LemonnadeChange.swift new file mode 100644 index 00000000..fbd95f14 --- /dev/null +++ b/Week_02/LemonnadeChange.swift @@ -0,0 +1,31 @@ +// +// LemonnadeChange.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/10. +// + +import Foundation + +class LemonnadeChange { + /// 柠檬水找零(贪心算法) + func lemonadeChange(_ bills: [Int]) -> Bool { + var five = 0, ten = 0 + for b in bills { + if b == 5 { + five += 1 + } else if b == 10 { + five -= 1; ten += 1 + } else if ten > 0 { + five -= 1; ten -= 1 + } else { + five -= 3 + } + //每次找零结束后判断5元数量若小于0,找零失败 + if five < 0 { + return false + } + } + return true + } +} diff --git a/Week_02/MaxArea.swift b/Week_02/MaxArea.swift new file mode 100644 index 00000000..eba3b237 --- /dev/null +++ b/Week_02/MaxArea.swift @@ -0,0 +1,32 @@ +// +// MaxArea.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/10. +// + +import Foundation + +/* + 左右指针夹逼办法 + 1、初始左右指针最大宽度 + 2、小值向内移动 + 3、求面积和原来的面积比较,大的赋值 + */ + +class MaxArea { + /// 最大区域 + func maxArea(_ height: [Int]) -> Int { + var left = 0, right = height.count - 1, res = 0 + while left < right { + let area = min(height[left], height[right]) * (right - left) + if height[left] < height[right] { + left += 1 + } else { + right -= 1 + } + res = max(res, area) + } + return res + } +} diff --git a/Week_02/NAryTree.swift b/Week_02/NAryTree.swift new file mode 100644 index 00000000..24a28028 --- /dev/null +++ b/Week_02/NAryTree.swift @@ -0,0 +1,135 @@ +// +// N_aryTree.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/13. +// + +import Foundation + +class NAryTree { + /* 前序遍历 */ + /// 递归 + func preorder(_ root: Node?) -> [Int] { + guard let root = root else { + return [] + } + var res = [Int]() + res.append(root.val) + for node in root.children { + res += preorder(node) + } + return res + } + + /// 迭代 + func preorder01(_ root: Node?) -> [Int] { + guard let root = root else { + return [] + } + var stack = [Node]() + stack.append(root) + var res = [Int]() + while !stack.isEmpty { + let node = stack.popLast() + res.append(node!.val) + if node!.children.isEmpty { + continue + } + for child in node!.children.reversed() { + stack.append(child) + } + } + return res + } + + /* 后序遍历 */ + /// 递归 + func postorder(_ root: Node?) -> [Int] { + guard let root = root else { + return [] + } + var res = [Int]() + for node in root.children { + res += postorder(node) + } + res.append(root.val) + return res + } + + /// 迭代 + func postorder01(_ root: Node?) -> [Int] { + guard let root = root else { + return [] + } + var arr = [Node]() + arr.append(root) + var res = [Int]() + while !arr.isEmpty { + let node = arr.popLast() + res.insert(node!.val, at: 0) + if node!.children.isEmpty { + continue + } + for child in node!.children { + arr.append(child) + } + } + return res + } + + /* 层序遍历 */ + /// 递归 dfs + func levelOrder(_ root: Node?) -> [[Int]] { + var res = [[Int]]() + func dfs(_ root: Node?, _ depth: Int) { + guard let root = root else { + return + } + if res.count <= depth { + res.append([]) + } + res[depth].append(root.val) + for ch in root.children { + dfs(ch, depth + 1) + } + } + dfs(root, 0) + return res + } + + /// 迭代 bfs + func levelOrder01(_ root: Node?) -> [[Int]] { + var res = [[Int]]() + guard let root = root else { + return res + } + var queue = [Node]() + queue.insert(root, at: 0) + while !queue.isEmpty { + var level = [Int]() + for _ in 0..preOrder(r->left)->preOrder(r->right) + +中序遍历的递推公式: +inOrder(r) = inOrder(r->left)->print r->inOrder(r->right) + +后序遍历的递推公式: +postOrder(r) = postOrder(r->left)->postOrder(r->right)->print r + +``` + + +### 二叉查找树 + +- 左子树中每个节点的值都小于此节点的值 +- 右子树中每个节点的值都大于此节点的值 +- 左右子树也分别为二叉查找树 + +#### 二叉查找树基本操作 + +- 查询 +- 插入 +- 删除 +- 快速找到最大和最小节点 + +## 堆 Heap + +- 大顶堆或大根堆(根节点最大) +- 小顶堆或小根堆(根节点最小) + +### 二叉堆 + +- 堆是一颗完全二叉树。 +- 堆中每一个节点的值都必须大于等于(或小于等于)其子树中每个节点的值。 + +#### 二叉堆实现细节 +- 一般是数组实现 +- 假设根节点为0 + - 索引为i的左子节点 2*i+1 + - 索引为i的右子节点 2*i+2 + - 索引为i的父节点 floor((i-1)/2) + +#### 二叉堆基本操作 + +- 插入(HeapifyUp) + - 插入堆尾部 + - 依次向上调整结构,到根即可 + - O(logN) +- 删除(HeapifyDown) + - 将堆尾元素替换到顶部(替换被删除元素) + - 一次从根部向下调整,到底即可 + +## 图 Graph + +- Graph(V, E) +- V - vertex: 点 + - 度 入度和出度 + - 点与点之间:连通与否 +- E - edge: 边 + - 有向和无向(单行线) + - 权重(边长) + + + + diff --git a/Week_02/RemoveOutermostParentheses.swift b/Week_02/RemoveOutermostParentheses.swift new file mode 100644 index 00000000..73af8106 --- /dev/null +++ b/Week_02/RemoveOutermostParentheses.swift @@ -0,0 +1,22 @@ +// +// RemoveOutermostParentheses.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/9. +// + +import Foundation + +class RemoveOutermostParentheses { + /// 移除最外层括号 + func removeOuterParentheses(_ S: String) -> String { + var count = 0 + var res = "" + for c in S { + if c == ")" { count -= 1 } + if count >= 1 { res.append(c) } + if c == "(" { count += 1 } + } + return res + } +} diff --git a/Week_02/SlidingWindowMaximum.swift b/Week_02/SlidingWindowMaximum.swift new file mode 100644 index 00000000..7729faeb --- /dev/null +++ b/Week_02/SlidingWindowMaximum.swift @@ -0,0 +1,80 @@ +// +// SlidingWindowMaximum.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/8. +// + +import Foundation + +class SlidingWindowMaximum { + /// 滑动窗口最大值 + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + guard k > 0 && nums.count > 0 else { + return [] + } + var queue = [Int]() + var res = [Int]() + //没成窗前k个数 + for i in 0.. [Int] { + guard k > 0 && nums.count > 0 else { + return [] + } + var queue = [Int]() + var res = [Int]() + var j = 1 - k + for i in 0.. 0 && queue.first! == nums[j - 1] { + queue.removeFirst() + } + while !queue.isEmpty && queue.last! < nums[i] { + queue.removeLast() + } + queue.append(nums[i]) + if j >= 0 { + res.append(queue.first!) + } + j += 1 + } + return res + } + */ + + func test() { + let nums = [1, -2, 3, -4, 5, 6, 7, 8, 2] + let k = 3 + let result = maxSlidingWindow(nums, k) + print(result) + } +} + + diff --git a/Week_02/TopKFrequent.swift b/Week_02/TopKFrequent.swift new file mode 100644 index 00000000..79d87c7e --- /dev/null +++ b/Week_02/TopKFrequent.swift @@ -0,0 +1,23 @@ +// +// TopKFrequent.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/13. +// + +import Foundation + +class TopKFrequent { + func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] { + var dic = [Int: Int]() + for i in nums { + dic[i] = (dic[i] ?? 0) + 1 + } + let a = dic.sorted { $0.1 > $1.1 } + var res = [Int](repeating: 0, count: k) + for j in 0.. Int { + var left = 0, right = height.count - 1 + var leftMax = 0, rightMax = 0, res = 0 + while left < right { + if height[left] < height[right] { + if height[left] < leftMax { + res += leftMax - height[left] + } else { + leftMax = height[left] + } + left += 1 + } else { + if height[right] < rightMax { + res += rightMax - height[right] + } else { + rightMax = height[right] + } + right -= 1 + } + } + return res + } +} diff --git a/Week_02/TwoSum.swift b/Week_02/TwoSum.swift new file mode 100644 index 00000000..03635e04 --- /dev/null +++ b/Week_02/TwoSum.swift @@ -0,0 +1,34 @@ +// +// TwoSum.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/7. +// + +import Foundation + +class TwoSum { + /// 1 两数之和 + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + var dict = [Int: Int]() + for i in 0 ..< nums.count { + //如果存在返回 + if let index = dict[target - nums[i]] { + return [index, i] + } + //如果不存在,记录值 + dict[nums[i]] = i + } + return [] + } + + func test() { + let nums = [2,7,11,15] + let target = 9 + let result = twoSum(nums, target) + print(result) + } + +} + + diff --git a/Week_02/UglyNumber.swift b/Week_02/UglyNumber.swift new file mode 100644 index 00000000..6ec954fc --- /dev/null +++ b/Week_02/UglyNumber.swift @@ -0,0 +1,28 @@ +// +// UglyNumber.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/13. +// + +import Foundation + +/* + 我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。 + 可以用2|3|5相乘得到的数字叫做丑数 + */ + +class UglyNumber { + func nthUglyNumber(_ n: Int) -> Int { + var dp = [Int](repeating: 1, count: n) + var a = 0, b = 0, c = 0 + for i in 1.. Bool { + guard s.count == t.count else { + return false + } + if s.sorted() == t.sorted() { + return true + } else { + return false + } + } + + // 数组方式 + func isAnagram01(_ s: String, _ t: String) -> Bool { + guard s.count == t.count else { + return false + } + var arr = [Int](repeating: 0, count: 26) + for c in s { + let i = numFromCharacter(c) - numFromCharacter("a") + arr[i] += 1 + } + for c in t { + let i = numFromCharacter(c) - numFromCharacter("a") + arr[i] -= 1 + if arr[i] < 0 { + return false + } + } + return true + } + + func numFromCharacter(_ char: Character) -> Int { + let str = String(char) + var number: Int = 0 + for code in str.unicodeScalars { + number = Int(code.value) + } + return number + } + + //字典方式 + func isAnagram02(_ s: String, _ t: String) -> Bool { + guard s.count == t.count else { + return false + } + var hashMap = [Character: Int]() + for c in s { + if hashMap[c] == nil { + hashMap[c] = 0 + } + hashMap[c]! += 1 + } + for c in t { + if hashMap[c] == nil { + return false + } + hashMap[c]! -= 1 + if hashMap[c]! < 0 { + return false + } + } + return true + } +} diff --git a/Week_03/BuildTree.swift b/Week_03/BuildTree.swift new file mode 100644 index 00000000..6c7770d9 --- /dev/null +++ b/Week_03/BuildTree.swift @@ -0,0 +1,35 @@ +// +// BuildTree.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/19. +// + +import Foundation + +class BuildTree { + //根据前序遍历和中序遍历构造二叉树 + func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? { + guard preorder.count == inorder.count else { + return nil + } + var inDict = [Int: Int]() + for (index, value) in inorder.enumerated() { + inDict[value] = index + } + return myBuildTree(preorder, inDict, 0, preorder.count - 1, 0, inorder.count - 1) + } + + func myBuildTree(_ preorder: [Int], _ inDict: [Int: Int], _ preLeft: Int, _ preRight: Int, _ inLeft: Int, _ inRight: Int) -> TreeNode? { + guard preLeft <= preRight && inLeft <= inRight else { + return nil + } + let rootVal = preorder[preLeft] + let rootIndex = inDict[rootVal] + let node = TreeNode(rootVal) + node.left = myBuildTree(preorder, inDict, preLeft + 1, rootIndex! - inLeft + preLeft, inLeft, rootIndex! - 1) + node.right = myBuildTree(preorder, inDict, rootIndex! - inLeft + preLeft + 1, preRight, rootIndex! + 1, inRight) + return node + } + +} diff --git a/Week_03/Codec.swift b/Week_03/Codec.swift new file mode 100644 index 00000000..68508c11 --- /dev/null +++ b/Week_03/Codec.swift @@ -0,0 +1,40 @@ +// +// Codec.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/20. +// + +import Foundation + +/// 序列化和反序列化一个二叉树 + +class Codec { + + func serialize(_ root: TreeNode?) -> String { + var res = "" + guard let root = root else { + return res + "nil," + } + res += "\(root.val)," + res += serialize(root.left) + res += serialize(root.right) + return res + } + + func deserialize(_ data: String) -> TreeNode? { + var array = data.split(separator: ",") + return deserializeHelper(&array) + } + func deserializeHelper(_ data: inout [Substring]) -> TreeNode? { + if data.first == "nil" { + data.removeFirst() + return nil + } + let node = TreeNode(Int(String(data.first!))!) + data.removeFirst() + node.left = deserializeHelper(&data) + node.right = deserializeHelper(&data) + return node + } +} diff --git a/Week_03/Combinations.swift b/Week_03/Combinations.swift new file mode 100644 index 00000000..87bd3b5b --- /dev/null +++ b/Week_03/Combinations.swift @@ -0,0 +1,36 @@ +// +// Combinations.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/19. +// + +import Foundation + +class Combinations { + + var temp = [Int]() + var ans = [[Int]]() + func combine(_ n: Int, _ k: Int) -> [[Int]] { + dfs(1, n, k) + return ans + } + func dfs(_ cur: Int, _ n: Int, _ k: Int) { + // 剪枝:temp 长度加上区间 [cur, n] 的长度小于 k,不可能构造出长度为 k 的 temp + if temp.count + (n - cur + 1) < k { + return + } + //记录合法答案 + if temp.count == k { + ans.append(Array(temp)) + return + } + // 考虑选择当前位置 + temp.append(cur) + dfs(cur + 1, n, k) + temp.removeLast() + // 考虑不选择当前位置 + dfs(cur + 1, n, k) + } + +} diff --git a/Week_03/GenerateParenthesis.swift b/Week_03/GenerateParenthesis.swift new file mode 100644 index 00000000..de1b98e6 --- /dev/null +++ b/Week_03/GenerateParenthesis.swift @@ -0,0 +1,32 @@ +// +// GenerateParenthesis.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/15. +// + +import Foundation + +class GenerateParenthesis { + + func generateParenthesis(_ n: Int) -> [String] { + var res = [String]() + generate(0, 0, n, "", &res) + return res + } + + func generate(_ left: Int, _ right: Int, _ n: Int, _ s: String, _ res: inout [String]) { + if left == n && right == n { + res.append(s) + return + } + if left < n { + generate(left + 1, right, n, s + "(", &res) + } + if left > right { + generate(left, right + 1, n, s + ")", &res) + } + } + + +} diff --git a/Week_03/InvertTree.swift b/Week_03/InvertTree.swift new file mode 100644 index 00000000..7d72ed38 --- /dev/null +++ b/Week_03/InvertTree.swift @@ -0,0 +1,47 @@ +// +// InvertTree.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/18. +// + +import Foundation + +class InvertTree { + + /* + * 时间复杂度:O(n),n为树的节点数。 + * 空间复杂度:O(n),n为递归栈深度。 + */ + func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let root = root else { + return nil + } + //交换左右节点的值 drill down + (root.left, root.right) = (invertTree(root.right), invertTree(root.left)) + return root + } + + /* + * 时间复杂度:O(n),n为树的节点数。 + * 空间复杂度:O(n),n为栈深度。 + */ + func invertTree10(_ root: TreeNode?) -> TreeNode? { + guard let root = root else { + return nil + } + var stack = [root] + while !stack.isEmpty { + let node = stack.popLast() + (node!.left, node!.right) = (node!.right, node!.left) + if let left = node?.left { + stack.append(left) + } + if let right = node?.right { + stack.append(right) + } + } + return root + } + +} diff --git a/Week_03/IsValidBST.swift b/Week_03/IsValidBST.swift new file mode 100644 index 00000000..7c7c335d --- /dev/null +++ b/Week_03/IsValidBST.swift @@ -0,0 +1,96 @@ +// +// IsValidBST.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/18. +// + +import Foundation + +class IsValidBST { + + /* + 递归 + 时间复杂度:O(n) + 空间复杂度:O(n) + */ + + func isValidBST(_ root: TreeNode?) -> Bool { + return helper(root, Int.min, Int.max) + } + func helper(_ root: TreeNode?, _ min: Int, _ max: Int) -> Bool { + guard let root = root else { + return true + } + if root.val >= max || root.val <= min { + return false + } + let leftResult = helper(root.left, min, root.val) + let rightResult = helper(root.right, root.val, max) + return leftResult && rightResult + } + + /* + 中序遍历 + 时间复杂度:O(n) + 空间复杂度:O(n) + */ + func isValidBST10(_ root: TreeNode?) -> Bool { + var stack = [TreeNode]() + var node = root + var last = Int.min + while node != nil || !stack.isEmpty { + while node != nil { + stack.append(node!) + node = node!.left + } + node = stack.popLast() + if node!.val <= last { + return false + } + last = node!.val + node = node!.right + } + return true + } + + //中序遍历递归 + func isValidBST11(_ root: TreeNode?) -> Bool { + //内嵌函数 + func inorder(_ root: TreeNode?) -> Bool { + guard let root = root else { + return true + } + if inorder(root.left) { + if root.val <= last { + return false + } + last = root.val + return inorder(root.right) + } + return false + } + var last = Int.min + return inorder(root) + } + + //中序遍历递归 + func isValidBST12(_ root: TreeNode?) -> Bool { + var last = Int.min + return inorder(root, &last) + } + func inorder(_ root: TreeNode?, _ last: inout Int) -> Bool { + guard let root = root else { + return true + } + if inorder(root.left, &last) { + if root.val <= last { + return false + } + last = root.val + return inorder(root.right, &last) + } + return false + } + +} diff --git a/Week_03/LetterOfPhoneNumber.swift b/Week_03/LetterOfPhoneNumber.swift new file mode 100644 index 00000000..74d867a0 --- /dev/null +++ b/Week_03/LetterOfPhoneNumber.swift @@ -0,0 +1,34 @@ +// +// LetterOfPhoneNumber.swift +// LeetCodeDemo +// +// Created by Apple on 2020/12/22. +// + +import Foundation + +class LetterOfPhoneNumber { + /* 电话号码的字母组合 */ + func letterCombinations(_ digits: String) -> [String] { + guard digits.count > 0 else { + return [] + } + var res = [String]() + var temp = "" + let dic: [Character: String] = ["2": "abc", "3": "def", "4": "ghi", "5": "jkl", "6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz"] + func backtrack(_ index: Int) { + if index == digits.count { + res.append(String(temp)) + return + } + let str = dic[digits[digits.index(digits.startIndex, offsetBy: index)]] + for c in str! { + temp.append(String(c)) + backtrack(index + 1) + temp.removeLast() + } + } + backtrack(0) + return res + } +} diff --git a/Week_03/LowestCommonAncestor.swift b/Week_03/LowestCommonAncestor.swift new file mode 100644 index 00000000..3ff80e9e --- /dev/null +++ b/Week_03/LowestCommonAncestor.swift @@ -0,0 +1,29 @@ +// +// LowestCommonAncestor.swift +// LeetCodeDemo +// +// Created by Apple on 2020/12/17. +// + +import Foundation + +class LowestCommonAncestor { + + /* + 时间复杂度:O(n),其中n为树的节点总数。 + 空间复杂度:O(n),其中n为树的节点总数。 + */ + + func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? { + //如果root为空直接就是空,如果root等于p或者q,直接就是最近公共祖先 + if root == nil || root === p || root === q { return root } + //递归 + let left = lowestCommonAncestor(root!.left, p, q) + let right = lowestCommonAncestor(root!.right, p, q) + //根据情况处理返回值 + if left == nil { return right } + if right == nil { return left } + return root + } + +} diff --git a/Week_03/MajorityElement.swift b/Week_03/MajorityElement.swift new file mode 100644 index 00000000..675faa84 --- /dev/null +++ b/Week_03/MajorityElement.swift @@ -0,0 +1,53 @@ +// +// MajorityElement.swift +// LeetCodeDemo +// +// Created by Apple on 2020/12/22. +// + +import Foundation + +class MajorityElement { + /* + 遍历存到字典里面,如果一个数出现的次数大于n/2,这个数就是众数 + */ + func majorityElement(_ nums: [Int]) -> Int { + var hashMap = [Int: Int]() + for (_, value) in nums.enumerated() { + hashMap[value] = (hashMap[value] ?? 0) + 1 + if hashMap[value]! > nums.count / 2 { + return value + } + } + return -1 + } + + /* + 排序,后n/2处的数就是众数 + */ + func majorityElement10(_ nums: [Int]) -> Int { + let a = nums.sorted() + let halfIndex = nums.count / 2 + return a[halfIndex] + } + + /* + 摩尔投票法: + 先假设第一个数过半数并设cnt=1; + 遍历后面的数如果相同则cnt+1,不同则减一, + 当cnt为0时则更换新的数字为候选数 + (成立前提:有出现次数大于n/2的数存在) + */ + func majorityElement20(_ nums: [Int]) -> Int { + var count = 0, res = 0 + for (_, value) in nums.enumerated() { + if count == 0 { + res = value + count += 1 + } else { + res == value ? (count += 1) : (count -= 1) + } + } + return res + } +} diff --git a/Week_03/MaxDepth.swift b/Week_03/MaxDepth.swift new file mode 100644 index 00000000..0c06aa5c --- /dev/null +++ b/Week_03/MaxDepth.swift @@ -0,0 +1,15 @@ +// +// MaxDepth.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/18. +// + +import Foundation + +class MaxDepth { + func maxDepth(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + return max(maxDepth(root.left), maxDepth(root.right)) + 1 + } +} diff --git a/Week_03/MinDepth.swift b/Week_03/MinDepth.swift new file mode 100644 index 00000000..e1bc4e13 --- /dev/null +++ b/Week_03/MinDepth.swift @@ -0,0 +1,41 @@ +// +// MinDepth.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/19. +// + +import Foundation + +class MinDepth { + + func minDepth(_ root: TreeNode?) -> Int { + guard let root = root else { + return 0 + } + if root.left == nil && root.right == nil { + return 1 + } + var minD = Int.max + if root.left != nil { + minD = min(minDepth(root.left), minD) + } + if root.right != nil { + minD = min(minDepth(root.right), minD) + } + return minD + 1 + } + + func minDepth10(_ root: TreeNode?) -> Int { + guard let root = root else { + return 0 + } + let left = minDepth(root.left) + let right = minDepth(root.right) + if left == 0 || right == 0 { + return left + right + 1 + } + return min(left, right) + 1 + } + +} diff --git a/Week_03/MyCircularDeque.swift b/Week_03/MyCircularDeque.swift new file mode 100644 index 00000000..655847e8 --- /dev/null +++ b/Week_03/MyCircularDeque.swift @@ -0,0 +1,121 @@ +// +// MyCircularDeque.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/18. +// + +import Foundation + +class MyCircularDeque { + var head: Int + var tail: Int + let size: Int + var array: [Int] + /** Initialize your data structure here. Set the size of the deque to be k. */ + init(_ k: Int) { + head = 0 + tail = 0 + size = k + 1 + array = [Int](repeating: 0, count: k + 1) + } + + /** Adds an item at the front of Deque. Return true if the operation is successful. */ + func insertFront(_ value: Int) -> Bool { + if isFull() { + return false + } + head = (head - 1 + size) % size + array[head] = value + return true + } + + /** Adds an item at the rear of Deque. Return true if the operation is successful. */ + func insertLast(_ value: Int) -> Bool { + if isFull() { + return false + } + array[tail] = value + tail = (tail + 1) % size + return true + } + + /** Deletes an item from the front of Deque. Return true if the operation is successful. */ + func deleteFront() -> Bool { + if isEmpty() { + return false + } + head = (head + 1) % size + return true + } + + /** Deletes an item from the rear of Deque. Return true if the operation is successful. */ + func deleteLast() -> Bool { + if isEmpty() { + return false + } + tail = (tail - 1 + size) % size + return true + } + + /** Get the front item from the deque. */ + func getFront() -> Int { + if isEmpty() { + return -1 + } + return array[head] + } + + /** Get the last item from the deque. */ + func getRear() -> Int { + if isEmpty() { + return -1 + } + let pos = (tail - 1 + size) % size + return array[pos] + } + + /** Checks whether the circular deque is empty or not. */ + func isEmpty() -> Bool { + return head == tail + } + + /** Checks whether the circular deque is full or not. */ + func isFull() -> Bool { + return head == ((tail + 1) % size) + } + +} + +/** + * Your MyCircularDeque object will be instantiated and called as such: + * let obj = MyCircularDeque(k) + * let ret_1: Bool = obj.insertFront(value) + * let ret_2: Bool = obj.insertLast(value) + * let ret_3: Bool = obj.deleteFront() + * let ret_4: Bool = obj.deleteLast() + * let ret_5: Int = obj.getFront() + * let ret_6: Int = obj.getRear() + * let ret_7: Bool = obj.isEmpty() + * let ret_8: Bool = obj.isFull() + */ + +extension MyCircularDeque { + class func test() { + let deque = MyCircularDeque(5) + print(deque.getRear()) + print(deque.getFront()) + print(deque.insertLast(1)) + print(deque.insertFront(4)) + print(deque.insertLast(2)) + print(deque.insertLast(3)) + print(deque.insertLast(5)) + print(deque.insertLast(6)) + print(deque.head, deque.tail, deque.size) + print(deque.array) + print(deque.isFull()) + print(deque.isEmpty()) + print(deque.getRear()) + print(deque.getFront()) + } +} diff --git a/Week_03/NQueens.swift b/Week_03/NQueens.swift new file mode 100644 index 00000000..5f8e43da --- /dev/null +++ b/Week_03/NQueens.swift @@ -0,0 +1,57 @@ +// +// NQueens.swift +// LeetCodeDemo +// +// Created by Apple on 2020/12/23. +// + +import Foundation + +class NQueens { + + func solveNQueens(_ n: Int) -> [[String]] { + var res = [[String]]() + var queens = [Int](repeating: -1, count: n) + var cols = Set(), dia1 = Set(), dia2 = Set() + func backtrack(_ row: Int) { + if row == n { + res.append(generateQueensToString(queens, n)) + return + } + for i in 0.. [String] { + var queensStrings = [String]() + for i in 0.. [[Int]] { + func backtrack(_ n: Int, _ first: Int) { + if first == n { + res.append(Array(output)) + } + for i in first.. [[Int]] { + func backtrack() { + if temp.count == nums.count { + res.append(Array(temp)) + return + } + for i in 0.. [[Int]] { + func backstrack(_ index: Int) { + if temp.count == numsSorted.count { + res.append(Array(temp)) + return + } + for i in 0.. 0 && numsSorted[i] == numsSorted[i - 1] && !visited[i - 1]) { + continue + } + temp.append(numsSorted[i]) + visited[i] = true + backstrack(index + 1) + visited[i] = false + temp.remove(at: index) + } + } + var res = [[Int]]() + var temp = [Int]() + let numsSorted = nums.sorted() + var visited = [Bool](repeating: false, count: nums.count) + backstrack(0) + return res + } +} diff --git a/Week_03/Pow.swift b/Week_03/Pow.swift new file mode 100644 index 00000000..b38ba4e8 --- /dev/null +++ b/Week_03/Pow.swift @@ -0,0 +1,21 @@ +// +// Pow.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/20. +// + +import Foundation + +class Pow { + func myPow(_ x: Double, _ n: Int) -> Double { + return n > 0 ? myPowHelper(x, n) : 1 / myPowHelper(x, -n) + } + func myPowHelper(_ x: Double, _ n: Int) -> Double { + if x == 1.0 || n == 0 { return 1.0 } + if x == 0.0 { return 0.0 } + if n == 1 { return x } + let y = myPowHelper(x, n / 2); + return n % 2 == 0 ? y * y : y * y * x; + } +} diff --git a/Week_03/README.md b/Week_03/README.md index 50de3041..d246ad7a 100644 --- a/Week_03/README.md +++ b/Week_03/README.md @@ -1 +1,77 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 总结 + +第三周的学习有些不太好,递归逻辑老是梳理不对,搞不懂分治和回溯咋回事,好难!!! + +刷题代码好难懂啊!!! + +## 递归 +#### 一、什么是递归? +1. 递归是一种非常高效、简洁的编码技巧,一种应用非常广泛的算法,比如DFS深度优先搜索、前中后序二叉树遍历等都是使用递归。 +2. 方法或函数调用自身的方式称为递归调用,调用称为递,返回称为归。 +3. 基本上,所有的递归问题都可以用递推公式来表示,比如 +f(n) = f(n-1) + 1; +f(n) = f(n-1) + f(n-2); +f(n)=n*f(n-1); + +#### 二、为什么使用递归?递归的优缺点? +1. 优点:代码的表达力很强,写起来简洁。 +2. 缺点:空间复杂度高、有堆栈溢出风险、存在重复计算、过多的函数调用会耗时较多等问题。 + + +#### 三、什么样的问题可以用递归解决呢? +1. 问题的解可以分解为几个子问题的解。何为子问题?就是数据规模更小的问题。 +2. 问题与子问题,除了数据规模不同,求解思路完全一样 +3. 存在递归终止条件 + + +#### 四、如何实现递归? + +##### 递归的代码模板 +1. 递归终止条件 recursion terminator +2. 处理当前层 process logic in current level +3. 下探到下一层 drill down +4. 清理当前层 reverse the current level status if needed + + +##### 递归思维要点 + +1. 抵制人肉递归 +2. 找最近重复性 +3. 数学归纳法思维 + + +#### 五、递归常见问题及解决方案 +1. 警惕堆栈溢出:可以声明一个全局变量来控制递归的深度,从而避免堆栈溢出。 +2. 警惕重复计算:通过某种数据结构来保存已经求解过的值,从而避免重复计算。 + + +#### 六、如何将递归改写为非递归代码? +笼统的讲,所有的递归代码都可以改写为迭代循环的非递归写法。如何做?抽象出递推公式、初始值和边界条件,然后用迭代循环实现。 + +## 分治(分而治之) + +##### 分治的代码模板 +1. 递归终止条件 recursion terminator +2. 准备数据拆分问题 prepare data +3. 递归处理子问题 conquer subproblems +4. 合并子结果 process and generate the final result +5. 清理当前层 reverse the current level status + +分治是一种处理问题的思想,多适合用递归来实现。 + +* 分解:将原问题分解成一系列子问题; +* 解决:递归地求解各个子问题,若子问题足够小,则直接求解; +* 合并:将子问题的结果合并成原问题。 + +分治算法能解决的问题,一般需要满足下面这几个条件: + +* 原问题与分解成的小问题具有相同的模式; +* 原问题分解成的子问题可以独立求解,子问题之间没有相关性; +* 具有分解终止条件,也就是说,当问题足够小时,可以直接求解; +* 可以将子问题合并成原问题,而这个合并操作的复杂度不能太高,否则就起不到减小算法总体复杂度的效果了。 + +## 回溯 + +回溯算法的思想非常简单,大部分情况下,都是用来解决广义的搜索问题,也就是,从一组可能的解中,选择出一个满足要求的解。回溯算法非常适合用递归来实现,在实现的过程中,剪枝操作是提高回溯效率的一种技巧。利用剪枝,我们并不需要穷举搜索所有的情况,从而提高搜索效率。 \ No newline at end of file diff --git a/Week_03/ReversePrint.swift b/Week_03/ReversePrint.swift new file mode 100644 index 00000000..a6c06f98 --- /dev/null +++ b/Week_03/ReversePrint.swift @@ -0,0 +1,86 @@ +// +// ReversePrint.swift +// LeetCodeDemo +// +// Created by Apple on 2020/12/17. +// + +import Foundation + +class ReversePrint { + // MARK: 递归 + + /* + - 时间复杂度:O(n),其中 n 为链表节点的个数。链表的遍历中每个节点会被访问一次且只会被访问一次。 + - 空间复杂度:O(n)。空间复杂度取决于递归的栈深度,而栈深度为一条链的情况下会达到 O(n) 的级别。 + */ + func reversePrint(_ head: ListNode?) -> [Int] { + var res = [Int]() + reverse(head, &res) + return res + } + func reverse(_ head: ListNode?, _ res: inout [Int]) { + if head == nil { + return + } + reverse(head!.next, &res) + res.append(head!.val) + } + + // MARK: 栈 + + /* + - 时间复杂度:O(n),其中 n 为链表节点的个数。链表的遍历中每个节点会被访问二次,入栈一次出栈一次。 + - 空间复杂度:O(n)。空间复杂度取决于栈深度,而栈深度会达到 O(n) 的级别。 + */ + func reversePrint10(_ head: ListNode?) -> [Int] { + var res = [Int]() + var stack = [ListNode]() + var node = head + while node != nil { + stack.append(node!) + node = node!.next + } + while !stack.isEmpty { + res.append(stack.popLast()!.val) + } + return res + } + + // MARK: 先遍历后翻转 + + /* + - 时间复杂度:O(n),其中 n 为链表节点的个数。链表的遍历中每个节点,翻转为n/2。 + - 空间复杂度:O(1)。不使用额外的栈空间,翻转是原地操作。 + */ + func reversePrint20(_ head: ListNode?) -> [Int] { + var res = [Int]() + var node = head + while node != nil { + res.append(node!.val) + node = node!.next + } + reverseArray(&res) + return res + } + + func reverseArray(_ array: inout [Int]) { + var left = 0, right = array.count - 1 + while left < right { + array[left] = array[left] ^ array[right] + array[right] = array[left] ^ array[right] + array[left] = array[left] ^ array[right] + left += 1 + right -= 1 + } + } +} + +public class ListNode { + public var val: Int + public var next: ListNode? + public init(_ val: Int) { + self.val = val + self.next = nil + } +} diff --git a/Week_03/Subset.swift b/Week_03/Subset.swift new file mode 100644 index 00000000..7ff16f9c --- /dev/null +++ b/Week_03/Subset.swift @@ -0,0 +1,62 @@ +// +// Subset.swift +// LeetCodeDemo +// +// Created by Apple on 2020/12/21. +// + +import Foundation + +// MARK: 子集 +class Subset { + + func subsets(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var temp = [Int]() + func backtrack(_ start: Int) { + res.append(Array(temp)) + for i in start.. [[Int]] { + var res = [[Int]]() + let n = nums.count + let p = 1 << n + for i in 0..

> j) & 1 == 1 { + temp.append(nums[j]) + } + } + res.append(temp) + } + return res + } + + func subsets20(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var temp = [Int]() + func backtrack(_ cur: Int) { + if cur == nums.count { + res.append(Array(temp)) + return + } + temp.append(nums[cur]) + backtrack(cur + 1) + temp.removeLast() + backtrack(cur + 1) + } + backtrack(0) + return res + } + +} diff --git a/Week_03/Tree.swift b/Week_03/Tree.swift new file mode 100644 index 00000000..02991f48 --- /dev/null +++ b/Week_03/Tree.swift @@ -0,0 +1,43 @@ +// +// Tree.swift +// LeetCodeDemo +// +// Created by Apple on 2020/12/17. +// + +import Foundation + +// MARK: - 二叉树 +public class TreeNode { + public var val: Int + public var left: TreeNode? + public var right: TreeNode? + + public init() { + self.val = 0; + self.left = nil; + self.right = nil; + } + + public init(_ val: Int) { + self.val = val; + self.left = nil; + self.right = nil; + } + + public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + self.val = val + self.left = left + self.right = right + } +} + +// MARK: - N叉树 +public class Node { + public var val: Int + public var children: [Node] + public init(_ val: Int) { + self.val = val + self.children = [] + } +} diff --git a/Week_04/AssignCookies.swift b/Week_04/AssignCookies.swift new file mode 100644 index 00000000..e62610ef --- /dev/null +++ b/Week_04/AssignCookies.swift @@ -0,0 +1,24 @@ +// +// AssignCookies.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/24. +// + +import Foundation + +class AssignCookies { + //455. 分发饼干 + func findContentChildren(_ g: [Int], _ s: [Int]) -> Int { + let gSorted = g.sorted() // 孩子胃口排序 + let sSorted = s.sorted() // 饼干排序 + var res = 0, sIndex = 0 // 最终结果和饼干的下标 + while sIndex < s.count && res < g.count { + if sSorted[sIndex] >= gSorted[res] { + res += 1 // 如果饼干满足孩子,结果加一 + } + sIndex += 1 // 无论饼干是否满足,结果都加一 + } + return res + } +} diff --git a/Week_04/FindMinInRotatedSortedArray.swift b/Week_04/FindMinInRotatedSortedArray.swift new file mode 100644 index 00000000..d7e32e38 --- /dev/null +++ b/Week_04/FindMinInRotatedSortedArray.swift @@ -0,0 +1,58 @@ +// +// FindMinInRotatedSortedArray.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/26. +// + +import Foundation + +class FindMinInRotatedSortedArray { + func findMin(_ nums: [Int]) -> Int { + let n = nums.count + if n == 1 { + return nums[0] + } + var minValue = Int.max + var left = 0, right = nums.count - 1 + while left <= right { + let mid = (left + right) / 2 + if nums[left] <= nums[mid] { + //左未旋转 + minValue = min(nums[left], minValue) + left = mid + 1 + } else { + //右未旋转 + minValue = min(nums[mid], minValue) + right = mid - 1 + } + } + return minValue + } + + func findMin10(_ nums: [Int]) -> Int { + let n = nums.count + var left = 0, right = n - 1 + if nums[right] >= nums[0] { + //未旋转 + return nums[0] + } + while left <= right { + let mid = (left + right) / 2 + if nums[mid] > nums[mid + 1] { + return nums[mid + 1] + } + if nums[mid - 1] > nums[mid] { + return nums[mid] + } + if nums[left] < nums[mid] { + //左未旋转 + left = mid + 1 + } else { + //右未旋转 + right = mid - 1 + } + } + return -1 + } +} diff --git a/Week_04/JumpGame.swift b/Week_04/JumpGame.swift new file mode 100644 index 00000000..18e8366b --- /dev/null +++ b/Week_04/JumpGame.swift @@ -0,0 +1,32 @@ +// +// JumpGame.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/26. +// + +import Foundation + +class JumpGame { + + func canJump(_ nums: [Int]) -> Bool { + var reach = 0 + for i in 0.. reach { + return false + } + reach = max(reach, i + nums[i]) + } + return true + } + + func canJump10(_ nums: [Int]) -> Bool { + var last = 0 + for (i, v) in nums.enumerated().reversed() { + if i + v >= last { + last = i + } + } + return last == 0 + } +} diff --git a/Week_04/JumpGameII.swift b/Week_04/JumpGameII.swift new file mode 100644 index 00000000..5c0f4a21 --- /dev/null +++ b/Week_04/JumpGameII.swift @@ -0,0 +1,50 @@ +// +// JumpGameII.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/27. +// + +import Foundation + +class JumpGameII { + + /* 超时 从后往前贪心 */ + func jump(_ nums: [Int]) -> Int { + if nums.count <= 1 { + return 0 + } + var position = nums.count - 1 + var step = 0 + while position > 0 { + for i in 0..= position { + step += 1 + position = i + break + } + } + } + return step + } + + /* 从前往后贪心 */ + func jump10(_ nums: [Int]) -> Int { + if nums.count <= 1 { + return 0 + } + var maxIndex = 0, step = 0, end = 0 + for i in 0.. Bool { + guard bills.count > 0, bills.first == 5 else { + return false + } + var five = 0, ten = 0 + for b in bills { + if b == 5 { + five += 1 + } else if b == 10 { + five -= 1; ten += 1 + } else if ten > 0 { + five -= 1; ten -= 1 + } else { + five -= 3 + } + //每次找零结束后判断5元数量若小于0,找零失败 + if five < 0 { + return false + } + } + return true + } +} diff --git a/Week_04/MaxProfit.swift b/Week_04/MaxProfit.swift new file mode 100644 index 00000000..6181ea1c --- /dev/null +++ b/Week_04/MaxProfit.swift @@ -0,0 +1,19 @@ +// +// MaxProfit.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/23. +// + +import Foundation + +class MaxProfit { + //贪心算法: 第二天与前一天的差值大于零,加入答案,既是最大收益 + func maxProfit(_ prices: [Int]) -> Int { + var ans = 0 + for i in 1.. [[Character]] { + let x = click[0], y = click[1] + var res = board + if res[x][y] == "M" { + //点到地雷 + res[x][y] = "X" + } else { + dfs(&res, x, y) + } + return res + } + + func dfs(_ board: inout [[Character]], _ x: Int, _ y: Int) { + var count = 0 + for i in 0..<8 { + //查看周边有多少个地雷 + let tx = x + dx[i], ty = y + dy[i] + if tx < 0 || tx >= board.count || ty < 0 || ty >= board.first!.count { + continue + } + count += (board[tx][ty] == "M" ? 1 : 0) + } + if count > 0 { + //有地雷 将地雷数量标记 + board[x][y] = Character("\(count)") + } else { + //无地雷 递归处理 + board[x][y] = "B" + for i in 0..<8 { + let tx = x + dx[i], ty = y + dy[i] + if tx < 0 || tx >= board.count || ty < 0 || ty >= board.first!.count || board[tx][ty] != "E" { + continue + } + dfs(&board, tx, ty) + } + } + } + + + // 广度优先 + func updateBoard10(_ board: [[Character]], _ click: [Int]) -> [[Character]] { + let x = click[0], y = click[1] + var res = board + if res[x][y] == "M" { + res[x][y] = "X" + } else { + bfs(&res, x, y) + } + return res + } + + func bfs(_ board: inout [[Character]], _ x: Int, _ y: Int) { + var queue = [[x, y]] + let row = board.count, col = board.first!.count + var visited = [[Bool]](repeating: [Bool](repeating: false, count: col), count: row) + while !queue.isEmpty { + let pos = queue.removeFirst() + let x = pos[0], y = pos[1] + var count = 0 + for i in 0..<8 { + let tx = x + dx[i], ty = y + dy[i] + if tx < 0 || tx >= row || ty < 0 || ty >= col { + continue + } + count += (board[tx][ty] == "M" ? 1 : 0) + } + if count > 0 { + board[x][y] = Character("\(count)") + continue + } + board[x][y] = "B" + for i in 0..<8 { + let tx = x + dx[i], ty = y + dy[i] + if tx < 0 || tx >= row || ty < 0 || ty >= col || board[tx][ty] != "E" || visited[tx][ty] { + continue + } + queue.append([tx, ty]) + visited[tx][ty] = true + } + } + } + + func test() { + let board: [[Character]] = [["E","M","E","E","E"],["E","E","E","M","E"],["M","E","E","E","E"],["E","E","M","E","E"]] + let click = [3, 4] + let res = updateBoard(board, click) + for i in res { + print(i) + } + } +} diff --git a/Week_04/NumberOfIsland.swift b/Week_04/NumberOfIsland.swift new file mode 100644 index 00000000..0dfe52dd --- /dev/null +++ b/Week_04/NumberOfIsland.swift @@ -0,0 +1,38 @@ +// +// NumberOfIsland.swift +// LeetCodeDemo +// +// Created by Apple on 2020/12/25. +// + +import Foundation + +class NumberOfIsland { + func numIslands(_ grid: [[Character]]) -> Int { + guard grid.count > 0, grid.first != nil, grid.first!.count > 0 else { + return 0 + } + func dfs(_ row: Int, _ col: Int) { + guard row >= 0, row < rowCount, col >= 0, col < colCount, temp[row][col] == "1" else { + return + } + temp[row][col] = "0" + dfs(row + 1, col) + dfs(row - 1, col) + dfs(row, col + 1) + dfs(row, col - 1) + } + var res = 0, temp = grid + let rowCount = grid.count, colCount = grid.first!.count + for row in 0..> levelOrder(TreeNode root) { + List> allResults = new ArrayList<>(); + if (root == null) { + return allResults; + } + Queue nodes = new LinkedList<>(); + nodes.add(root); + while (!nodes.isEmpty()) { + int size = nodes.size(); + List results = new ArrayList<>(); + for (int i = 0; i < size; i++) { + TreeNode node = nodes.poll(); + results.add(node.val); + if (node.left != null) { + nodes.add(node.left); + } + if (node.right != null) { + nodes.add(node.right); + } + } + allResults.add(results); + } + return allResults; +} + +``` + +- 时间复杂度:O(E),E表示边的个数 +- 空间复杂度:O(E),E表示边的个数 + +## 深度优先搜索DFS + +是回溯思想的体现。 + +``` java +//Java +public List> levelOrder(TreeNode root) { + List> allResults = new ArrayList<>(); + if(root==null){ + return allResults; + } + travel(root,0,allResults); + return allResults; +} + + +private void travel(TreeNode root,int level,List> results){ + if(results.size()==level){ + results.add(new ArrayList<>()); + } + results.get(level).add(root.val); + if(root.left!=null){ + travel(root.left,level+1,results); + } + if(root.right!=null){ + travel(root.right,level+1,results); + } +} + +``` + +- 时间复杂度:O(E),E表示边的个数 +- 空间复杂度:O(V),V表示顶点的个数 + +## 贪心算法 + +总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,算法得到的是在某种意义上的局部最优解 + +## 二分查找 + +条件: + +- 数组存储 +- 有序数据 +- 数据量太小不适合(没必要) +- 数据量太大也不适合(依赖于数组数据结构) +- 时间复杂度:O(logn) + +代码模板如下: + +``` java +// Java +public int binarySearch(int[] array, int target) { + int left = 0, right = array.length - 1, mid; + while (left <= right) { + //直接使用 (right+left) / 2 有溢出风险 + mid = (right - left) / 2 + left; + + if (array[mid] == target) { + return mid; + } else if (array[mid] > target) { + right = mid - 1; + } else { + left = mid + 1; + } + } + + return -1; +} +``` + +#### 扩展 + +在搜索旋转排序数组题目中,部分数据旋转,可以用mid值和left或者right值进行比较判断哪一边是有序的。 + diff --git a/Week_04/RobotSim.swift b/Week_04/RobotSim.swift new file mode 100644 index 00000000..8b60cf6d --- /dev/null +++ b/Week_04/RobotSim.swift @@ -0,0 +1,39 @@ +// +// RobotSim.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/26. +// + +import Foundation + +class RobotSim { + struct Location: Hashable { + var x: Int + var y: Int + } + func robotSim(_ commands: [Int], _ obstacles: [[Int]]) -> Int { + var res = 0, x = 0, y = 0, d = 0 // 0北, 1东, 2南, 3西 + let dx = [0, 1, 0, -1], dy = [1, 0, -1, 0] + var obstacleSet = Set() + for ob in obstacles { + obstacleSet.insert(Location(x: ob[0], y: ob[1])) + } + for c in commands { + if c == -2 { + d = d == 0 ? 3 : d - 1 + } else if c == -1 { + d = d == 3 ? 0 : d + 1 + } else { + var step = c + while step > 0 && !obstacleSet.contains(Location(x:x + dx[d], y: y + dy[d])) { + x += dx[d] + y += dy[d] + step -= 1 + } + res = max(x * x + y * y, res) + } + } + return res + } +} diff --git a/Week_04/Search2DMatrix.swift b/Week_04/Search2DMatrix.swift new file mode 100644 index 00000000..eb245dbc --- /dev/null +++ b/Week_04/Search2DMatrix.swift @@ -0,0 +1,32 @@ +// +// Search2DMatrix.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/26. +// + +import Foundation + +class Search2DMatrix { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + let m = matrix.count + guard m > 0 else { + return false + } + let n = matrix[0].count + var l = 0, r = m * n - 1 + while l <= r { + let mid = (l + r) / 2 + let midValue = matrix[mid / n][mid % n] + if midValue == target { + return true + } + if midValue > target { + r = mid - 1 + } else { + l = mid + 1 + } + } + return false + } +} diff --git a/Week_04/SearchInRotatedSortedArray.swift b/Week_04/SearchInRotatedSortedArray.swift new file mode 100644 index 00000000..cdad3733 --- /dev/null +++ b/Week_04/SearchInRotatedSortedArray.swift @@ -0,0 +1,47 @@ +// +// SearchInRotatedSortedArray.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/26. +// + +import Foundation + +class SearchInRotatedSortedArray { + func search(_ nums: [Int], _ target: Int) -> Int { + let n = nums.count + guard n > 0 else { + return -1 + } + if n == 1 { + return target == nums[0] ? 0 : -1 + } + var l = 0, r = n - 1 + while l <= r { + let mid = (l + r) / 2 + if nums[mid] == target { + return mid + } + if nums[l] <= nums[mid] { + //左边有序 + if nums[l] <= target && nums[mid] > target { + //在左边 + r = mid - 1 + } else { + //在右边 + l = mid + 1 + } + } else { + //右边有序 + if nums[r] >= target && nums[mid] < target { + //在右边 + l = mid + 1 + } else { + //在左边 + r = mid - 1 + } + } + } + return -1 + } +} diff --git a/Week_04/WordLadder.swift b/Week_04/WordLadder.swift new file mode 100644 index 00000000..e5aa3242 --- /dev/null +++ b/Week_04/WordLadder.swift @@ -0,0 +1,110 @@ +// +// WordLadder.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/26. +// + +import Foundation + +class WordLadder { + + //单向bfs + func ladderLength(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + var wordSet = Set(wordList) + guard wordSet.contains(endWord) else { + return 0 + } + wordSet.remove(beginWord) + var queue = [beginWord] + var visited: Set = [beginWord] + + var res = 1 + while !queue.isEmpty { + let size = queue.count + for _ in 0.., _ visited: inout Set) -> Bool { + var tempArr = Array(curWord) + for i in 0.. Int { + let wordSet = Set(wordList) + guard wordSet.contains(endWord) else { + return 0 + } + var beginVisited: Set = [beginWord] + var endVisited: Set = [endWord] + var visited = Set() + + var res = 1 + while !beginVisited.isEmpty && !endVisited.isEmpty { + if beginVisited.count > endVisited.count { + swap(&beginVisited, &endVisited) + } + var nextLevelVisited = Set() + for word in beginVisited { + if changeWordEveryOneLetter10(word, endVisited, &visited, wordSet, &nextLevelVisited) { + return res + 1 + } + } + beginVisited = nextLevelVisited + res += 1 + } + return 0 + } + + func changeWordEveryOneLetter10(_ word: String, _ endVisited: Set, _ visited: inout Set, _ wordSet: Set, _ nextLevelVisited: inout Set) -> Bool { + var wordArr = Array(word) + for i in 0.. [[String]] { + //将所有单词加入到wordId表中 + var id = 0 + for word in wordList { + if wordId[word] == nil { + wordId[word] = id + idWord.append(word) + id += 1 + } + } + //如果结束词不在单词列表 则无解 + if wordId[endWord] == nil { + return [] + } + //开始单词也加入到表格 + if wordId[beginWord] == nil { + wordId[beginWord] = id + idWord.append(beginWord) + id += 1 + } + //初始化边数组 + edges = [[Int]](repeating: [], count: idWord.count) + for i in 0.. Bool { + var diff = 0 + for i in 0..= 2 { + break + } + } + return diff == 1 + } + + func test() { + let b = "hit" + let e = "cog" + let wordList = ["hot","dot","dog","lot","log","cog"] + print(findLadders(b, e, wordList)) + } +} diff --git a/Week_05/README.md b/Week_05/README.md index 50de3041..14c7d4cd 100644 --- a/Week_05/README.md +++ b/Week_05/README.md @@ -1 +1,4 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 动态规划 + diff --git a/Week_06/CoinChange.swift b/Week_06/CoinChange.swift new file mode 100644 index 00000000..3b734f5a --- /dev/null +++ b/Week_06/CoinChange.swift @@ -0,0 +1,28 @@ +// +// CoinChange.swift +// LeetCodeDemo +// +// Created by Apple on 2021/1/5. +// + +import Foundation + +class CoinChange { + //零钱兑换 + func coinChange(_ coins: [Int], _ amount: Int) -> Int { + guard amount > 0 else { + return 0 + } + var dp = [Int](repeating:amount + 1, count: amount + 1) + dp[0] = 0 + for i in 1...amount { + for coin in coins { + if coin <= i { + dp[i] = min(dp[i], dp[i - coin] + 1) + } + } + } + return dp[amount] > amount ? -1 : dp[amount] + } + +} diff --git a/Week_06/CoinChangeII.swift b/Week_06/CoinChangeII.swift new file mode 100644 index 00000000..4928f626 --- /dev/null +++ b/Week_06/CoinChangeII.swift @@ -0,0 +1,54 @@ +// +// CoinChangeII.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/7. +// + +import Foundation + +class CoinChangeII { + + //组合数 + func change(_ amount: Int, _ coins: [Int]) -> Int { + if amount == 0 { + return 1 + } + if coins.count == 0 { + return 0 + } + var dp = [Int](repeating: 0, count: amount + 1) + dp[0] = 1 + for coin in coins { + if coin > amount { + continue + } + for i in coin.. Int { + if amount == 0 { + return 1 + } + if coins.count == 0 { + return 0 + } + var dp = [Int](repeating: 0, count: amount + 1) + dp[0] = 1 + + for i in 0.. Int { + let m = word1.count, n = word2.count + if m * n == 0 { + return m + n + } + let word1 = Array(word1), word2 = Array(word2) + var dp = [[Int]](repeating: [Int](repeating: 0, count: n + 1), count: m + 1) + for i in 0.. 1. + + 斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。 + + 答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。 + */ + + //动态规划 + func fib(_ n: Int) -> Int { + var a = 0, b = 1, sum = 0 + for _ in 0.. Int { + if n < 2 { + return n + } + var p = 0, q = 1, r = p + q + for _ in 2.. 1 + + 给你 n ,请计算 F(n) 。 + + 提示:0 <= n <= 30 + */ + + //动态规划 + func fib200(_ n: Int) -> Int { + var a = 0, b = 1, sum = 0 + for _ in 0.. Int { + if n < 2 { + return n + } + var p = 0, q = 1, r = p + q + for _ in 2.. Int { + let q = [[1, 1], [1, 0]] + let r = myPow(q, n) + return r[0][0] + } + + func myPow(_ a: [[Int]], _ n: Int) -> [[Int]] { + var ret = [[1, 0], [0, 1]] + while n > 0 { + if n & 1 == 1 { + ret = myMultiply(ret, a) + } + } + return ret + } + + func myMultiply(_ a: [[Int]], _ b: [[Int]]) -> [[Int]] { + var c = [[Int]](repeating: [Int](repeating: 0, count: 2), count: 2); + for i in 0..<2 { + for j in 0..<2 { + c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j]; + } + } + return c; + } + + //通项公式 + func dib220(_ n: Int) -> Int { + let sqrt5 = sqrt(5.0) + let temp = pow((1.0 + sqrt5) / 2.0, Double(n)) - pow((1.0 - sqrt5) / 2.0, Double(n)) + let res = temp / sqrt5 + return Int(res) + } + + //有限个枚举处理 + func dib230(_ n: Int) -> Int { + let fibs = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040] + return fibs[n] + } + + //递归(带缓存) + var resCache = [Int: Int]() + func fib240(_ n: Int) -> Int { + if n < 2 { + return n + } + if resCache[n] != nil { + return resCache[n]! + } + return fib240(n - 1) + fib240(n - 2) + } + +} diff --git a/Week_06/FourSum.swift b/Week_06/FourSum.swift new file mode 100644 index 00000000..382f442d --- /dev/null +++ b/Week_06/FourSum.swift @@ -0,0 +1,69 @@ +// +// FourSum.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/1. +// + +import Foundation + +class FourSum { + /*四数之和*/ + func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] { + guard nums.count >= 4 else { + return [] + } + var res = [[Int]]() + let nums = nums.sorted() + let n = nums.count + for i in 0.. 0 && nums[i] == nums[i - 1] { + continue + } + if nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target{ + break + } + if nums[i] + nums[n - 1] + nums[n - 2] + nums[n - 3] < target { + continue + } + for j in i + 1.. i + 1 && nums[j] == nums[j - 1] { + continue + } + if nums[i] + nums[i + 1] + nums[i + 2] + nums[j] > target{ + break + } + if nums[i] + nums[n - 1] + nums[n - 2] + nums[j] < target { + continue + } + var left = j + 1, right = n - 1 + while left < right { + let sum = nums[i] + nums[j] + nums[left] + nums[right] + if sum == target { + res.append([nums[i], nums[j], nums[left], nums[right]]) + leftAddOne(&left, right, nums) + rightSubOne(left, &right, nums) + } else if sum < target { + leftAddOne(&left, right, nums) + } else { + rightSubOne(left, &right, nums) + } + } + } + } + return res + } + + func leftAddOne(_ left: inout Int, _ right: Int, _ nums: [Int]) { + while left < right && nums[left] == nums[left + 1] { + left += 1 + } + left += 1 + } + func rightSubOne(_ left: Int, _ right: inout Int, _ nums: [Int]) { + while left < right && nums[right] == nums[right - 1] { + right -= 1 + } + right -= 1 + } +} diff --git a/Week_06/HouseRobber.swift b/Week_06/HouseRobber.swift new file mode 100644 index 00000000..dda22f22 --- /dev/null +++ b/Week_06/HouseRobber.swift @@ -0,0 +1,55 @@ +// +// HouseRobber.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/6. +// + +import Foundation + +class HouseRobber { + func rob(_ nums: [Int]) -> Int { + let n = nums.count + if n == 0 { + return 0 + } + if n == 1 { + return nums[0] + } + var dp = [Int](repeating: 0, count: n) + dp[0] = nums[0] + dp[1] = max(nums[0], nums[1]) + for i in 2.. Int { + let n = nums.count + if n == 0 { + return 0 + } + if n == 1 { + return nums[0] + } + var pre = nums[0], cur = max(nums[0], nums[1]) + for i in 2.. Int { + var pre = 0, cur = 0, temp: Int + for i in 0.. Int { + let n = nums.count + if n == 0 { + return 0 + } + if n == 1 { + return nums[0] + } + let nums1 = Array(nums[1.. Int { + var pre = 0, cur = 0, temp = 0 + for i in 0.. Bool { + var reach = 0 + for i in 0.. reach { + return false + } + reach = max(reach, i + nums[i]) + } + return true + } + + //贪心, 从后往前,维护终点 + func canJump10(_ nums: [Int]) -> Bool { + var last = 0 + for (i, v) in nums.enumerated().reversed() { + if i + v >= last { + last = i + } + } + return last == 0 + } + func canJump20(_ nums: [Int]) -> Bool { + var position = 0 + var i = nums.count - 1 + while i >= 0 { + if i + nums[i] >= position { + position = i + } + i -= 1 + } + return position == 0 + } + + //动态规划(超时) + func canJump30(_ nums: [Int]) -> Bool { + let n = nums.count + var dp = [Bool](repeating: false, count: n) + dp[0] = true + for i in 0..= i { + dp[i] = true + break + } + } + } + return dp[n - 1] + } + +} diff --git a/Week_06/JumpGameII.swift b/Week_06/JumpGameII.swift new file mode 100644 index 00000000..297886b4 --- /dev/null +++ b/Week_06/JumpGameII.swift @@ -0,0 +1,63 @@ +// +// JumpGameII.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/27. +// + +import Foundation + +class JumpGameII { + + /* 超时 从后往前贪心 */ + func jump(_ nums: [Int]) -> Int { + if nums.count <= 1 { + return 0 + } + var position = nums.count - 1 + var step = 0 + while position > 0 { + for i in 0..= position { + step += 1 + position = i + break + } + } + } + return step + } + + /* 从前往后贪心 */ + func jump10(_ nums: [Int]) -> Int { + if nums.count <= 1 { + return 0 + } + var maxIndex = 0, step = 0, end = 0 + for i in 0.. Int { + let n = nums.count + var dp = [Int](repeating: n + 1, count: n) + dp[0] = 0 + for i in 1..= i { + dp[i] = min(dp[i], dp[j] + 1) + } + } + } + return dp[n - 1] + } + +} diff --git a/Week_06/LongestCommonSubsequence.swift b/Week_06/LongestCommonSubsequence.swift new file mode 100644 index 00000000..2e993815 --- /dev/null +++ b/Week_06/LongestCommonSubsequence.swift @@ -0,0 +1,33 @@ +// +// LongestCommonSubsequence.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/1. +// + +import Foundation + +class LongestCommonSubsequence { + //最长公共子序列 + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + guard text1.count > 0, text2.count > 0 else { + return 0 + } + let n1 = text1.count, n2 = text2.count + var dp = [[Int]](repeating: [Int](repeating: 0, count: n2 + 1), count: n1 + 1) + let charArr1 = Array(text1), charArr2 = Array(text2) + for i in 1.. Int { + if matrix.count <= 0 || matrix[0].count <= 0 { + return 0 + } + let m = matrix.count, n = matrix[0].count + var dp = [[Int]](repeating: [Int](repeating: 0, count: n), count: m) + var maxSide = 0 + for i in 0.. Int { + guard nums.count > 0 else { + return 0 + } + var pre = 0, ans = nums[0] + for i in nums { + pre = max(pre + i, i) + ans = max(pre, ans) + } + return ans + } +} diff --git a/Week_06/MinPathSum.swift b/Week_06/MinPathSum.swift new file mode 100644 index 00000000..4ab77c3b --- /dev/null +++ b/Week_06/MinPathSum.swift @@ -0,0 +1,52 @@ +// +// MinPathSum.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/3. +// + +import Foundation + +class MinPathSum { + //最小路径和 + func minPathSum(_ grid: [[Int]]) -> Int { + guard grid.count > 0 else { + return 0 + } + let m = grid.count, n = grid[0].count + var dp = grid + for i in 1.. Int { + guard grid.count > 0, grid.first!.count > 0 else { + return 0 + } + let m = grid.count, n = grid.first!.count + var dp = grid + for i in 0.. Int { + guard n > 0 else { + return 0 + } + var dp = [Int](repeating: n + 1, count: n + 1) + dp[0] = 0 + for i in 1...n { + dp[i] = i + var j = 1 + while i >= j * j { + dp[i] = min(dp[i], dp[i - j * j] + 1) + //print(dp[i]) + j += 1 + } + } + return dp[n] + } + + func test() { + print(numSquares(2)) + } +} diff --git a/Week_06/README.md b/Week_06/README.md index 50de3041..d26ec152 100644 --- a/Week_06/README.md +++ b/Week_06/README.md @@ -1 +1,38 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 总结 + +这周题目是真的多啊,做不完啊,只能慢慢做了。。。 + +DP方程写不出,看到题目就懵懵的。 + +## 动态规划 + +[动态规划维基百科定义](https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92) + +### 特点和适合问题 + +- 适用于有重叠子问题 +- 适用于最优子结构 +- 无后效性(状态一旦确定,不受后续状态影响) +- 所耗时间往往远少于朴素解法 + +### 解题方法 + +#### 状态转移表 +- 大多动态规划可以解决的问题都可以画出状态转移表 +- 一般都是二维的,可以优化空间复杂度为一维的 + +#### 状态转移方程 + +状态转移方程是解决动态规划的关键,也是比较难的地方。 + +### 常见问题 + +- 爬楼梯 +- Fibonacci +- 零钱兑换 +- 最长公共子序列 +- 不同路径 +- 最小路径和 +- 0-1背包问题 \ No newline at end of file diff --git a/Week_06/StockIII.swift b/Week_06/StockIII.swift new file mode 100644 index 00000000..15993da6 --- /dev/null +++ b/Week_06/StockIII.swift @@ -0,0 +1,23 @@ +// +// StockIII.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/9. +// + +import Foundation + +class StockIII { + func maxProfit(_ prices: [Int]) -> Int { + let n = prices.count + var buy1 = -prices[0], sell1 = 0 + var buy2 = -prices[0], sell2 = 0 + for i in 1.. Int { + var dp = triangle + let n = dp.count + for i in 1.. Int { + var dp = triangle + let n = dp.count + for i in (0.. Int { + let n = triangle.count + var dp = triangle[n - 1] + for i in (0.. Int { + guard m > 0, n > 0 else { + return 0 + } + var dp = [[Int]](repeating: [Int](repeating: 1, count: n), count: m) + for i in 1.. Int { + guard m > 0, n > 0 else { + return 0 + } + var cur = [Int](repeating: 1, count: n) + for _ in 1.. Int { + var ans = 1 + var x = n, y = 1 + while y < m { + ans = ans * x / y + x += 1 + y += 1 + } + return ans + } + +} diff --git a/Week_06/UniquePathsII.swift b/Week_06/UniquePathsII.swift new file mode 100644 index 00000000..56701360 --- /dev/null +++ b/Week_06/UniquePathsII.swift @@ -0,0 +1,58 @@ +// +// UniquePathsII.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/2. +// + +import Foundation + +class UniquePathsII { + + func uniquePathsWithObstacles(_ obstacleGrid: [[Int]]) -> Int { + guard obstacleGrid.count > 0 else { + return 0 + } + let m = obstacleGrid.count, n = obstacleGrid[0].count + var dp = [[Int]](repeating: [Int](repeating: 0, count: n), count: m) + dp[0][0] = 1 + for i in 0..= 0 { + dp[i][j] += dp[i - 1][j] + } + if j - 1 >= 0 { + dp[i][j] += dp[i][j - 1] + } + } + } + return dp[m-1][n-1] + } + + + func uniquePathsWithObstacles10(_ obstacleGrid: [[Int]]) -> Int { + guard obstacleGrid.count > 0 else { + return 0 + } + let m = obstacleGrid.count, n = obstacleGrid[0].count + var f = [Int](repeating: 0, count: n) + f[0] = 1 + for i in 0..= 0 && obstacleGrid[i][j - 1] == 0 { + f[j] += f[j - 1] + } + } + } + return f[n - 1] + } + +} diff --git a/Week_07/ClimbStairs.swift b/Week_07/ClimbStairs.swift new file mode 100644 index 00000000..2e98a595 --- /dev/null +++ b/Week_07/ClimbStairs.swift @@ -0,0 +1,44 @@ +// +// ClimbStairs.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/23. +// + +import Foundation + +class ClimbStairs { + //动态规划 + func climbStairs(_ n: Int) -> Int { + var p = 0, q = 0, r = 1 + for _ in 0.. Int { + if dic[n] == nil { + dic[n] = climbStairs(n - 1) + climbStairs(n - 2) + } + return dic[n]! + } + //可以指定每步台阶数 + func climbStairs20(_ n: Int) -> Int { + let steps = [1, 2] + var dp = [Int](repeating: 0, count: n + 1) + dp[0] = 1 + for i in 0.. [String] { + var res = [String]() + generate(0, 0, n, "", &res) + return res + } + + func generate(_ left: Int, _ right: Int, _ n: Int, _ s: String, _ res: inout [String]) { + if left == n && right == n { + res.append(s) + return + } + //剪枝 + if left < n { + generate(left + 1, right, n, s + "(", &res) + } + if left > right { + generate(left, right + 1, n, s + ")", &res) + } + } + + +} diff --git a/Week_07/MinGeneticMutation.swift b/Week_07/MinGeneticMutation.swift new file mode 100644 index 00000000..0127083b --- /dev/null +++ b/Week_07/MinGeneticMutation.swift @@ -0,0 +1,107 @@ +// +// MinGeneticMutation.swift +// LeetCodeDemo +// +// Created by Apple on 2020/12/28. +// + +import Foundation +class MinGeneticMutation { + //单向BFS + func minMutation(_ start: String, _ end: String, _ bank: [String]) -> Int { + let bankSet = Set(bank) + guard bankSet.contains(end) else { + return -1 + } + var queue = [start] + var visited = Set() + visited.insert(start) + var res = 0 + while !queue.isEmpty { + let levelCount = queue.count + for _ in 0.., _ queue: inout [String], _ visited: inout Set) -> Bool { + var arr: [Character] = Array(cur) + for i in 0.. Int { + let bankSet = Set(bank) + guard bankSet.contains(end) else { + return -1 + } + var startSet: Set = [start], endSet: Set = [end], visited: Set = [start] + var res = 0 + while !startSet.isEmpty && !endSet.isEmpty { + if startSet.count > endSet.count { + swap(&startSet, &endSet) + } + var nextSet = Set() + for word in startSet { + if changeGenetic10(word, &nextSet, endSet, &visited, bankSet) { + return res + 1 + } + } + res += 1 + startSet = nextSet + } + return -1 + } + + func changeGenetic10(_ word: String, _ nextSet: inout Set, _ endSet: Set, _ visited: inout Set, _ bankSet: Set) -> Bool { + var word = Array(word) + for i in 0.. [[String]] { + var res = [[String]]() + var queens = [Int](repeating: -1, count: n) + var cols = Set(), dia1 = Set(), dia2 = Set() + func backtrack(_ row: Int) { + if row == n { + res.append(generateBoard(queens, n)) + return + } + for i in 0.. [String] { + var board = [String]() + for i in 0.. Int { + guard grid.count > 0, grid[0].count > 0 else { + return 0 + } + var temp = grid, res = 0 + for i in 0..= 0, row < m, col >= 0, col < n, temp[row][col] == "1" else { + return + } + temp[row][col] = "0" + dfs(row - 1, col, m, n, &temp) + dfs(row + 1, col, m, n, &temp) + dfs(row, col - 1, m, n, &temp) + dfs(row, col + 1, m, n, &temp) + } + +} diff --git a/Week_07/README.md b/Week_07/README.md index 50de3041..20110c54 100644 --- a/Week_07/README.md +++ b/Week_07/README.md @@ -1 +1,157 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 总结 + +时间过得好快啊,开始下半学期的学习了,上学期的东西感觉还有好多没有掌握,还要加油啊,还好这周的题目好几个都是以前做过的,比较熟悉,拍拍我的小心脏,缓缓气。加油!!! + +## Trie 树 + +别名:字典树,单词查找树或键树 +### 基本结构 +- 它是一个树形结构。 +- 它是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。 +- 典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计 +- 优点,最大限度地减少无谓的字符串比较,查询效率比哈希表高。 + +### 基本性质 +- 节点不存完整单词 + - 字符(也可以通过数组位置对应得到) + - 下一个字符对应的节点列表 + - 是否是最后一个字符(到此是否可以组成单词) +- 从根结点到某一结点,路径上经过的字符连接起来,为该结点对应的字符串; +- 每个结点的所有子结点路径代表的字符都不相同。 + +### 核心思想 +- Trie 树的核心思想是空间换时间。 +- 利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。 + +### 时间复杂度: +- 插入:O(n),n是所有插入字符串的长度和 +- 查找:O(k),k是查找单词的字符长度 + +### 代码 + +``` swift + +class TrieTreeNode { + public var next = [Character: TrieTreeNode]() + public var end: Bool + + public init() { + self.end = false + } +} + +class Trie { + + var root: TrieTreeNode + + /** Initialize your data structure here. */ + init() { + root = TrieTreeNode() + } + + /** Inserts a word into the trie. */ + func insert(_ word: String) { + var node = root + for c in word { + if node.next[c] == nil { + node.next[c] = TrieTreeNode() + } + node = node.next[c]! + } + node.end = true + } + + /** Returns if the word is in the trie. */ + func search(_ word: String) -> Bool { + return findWord(word)?.end ?? false + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + func startsWith(_ prefix: String) -> Bool { + return findWord(prefix) != nil + } + + func findWord(_ word: String) -> TrieTreeNode? { + var node = root + for c in word { + if let next = node.next[c] { + node = next + } else { + return nil + } + } + return node + } +} + +``` + +## 高级搜索 + +- 朴素搜索 +- 优化方式: + - 不重复,利用缓存 + - 剪枝,剪掉不必要的分支 +- 搜索方向 + - 广度优先搜索 DFS + - 深度优先搜索 BFS +- 双向搜索 + - 首尾同时扩散 + - 避免减少搜索访问数量 +- 启发式搜索 Heuristic Search (A*) + - 估价函数 + - 优先级搜索 + +启发式函数:h(n),它用来评价哪些结点最有希望的是一个我们要找的结点,h(n) 会返回一个非负实数,也可以认为是从结点n的目标结点路径的估计成本。 +启发式函数是一种告知搜索方向的方法。它提供了一种明智的方法来猜测哪个邻居结点会导向一个目标。 + +## 二叉树 + +### 二叉树的遍历 +- 前序遍历Pre-order:根左右 +- 中序遍历In-order:左根右 +- 后序遍历Post-order:左右根 + +### 二叉搜索树(Binary Search Tree) +别名:有序二叉树,排序二叉树(Sorted Binary Tree),有序二叉树 +- 左子树所有结点的值均小于根节点的值,右子树所有结点的值均大于根结点的值 +- 依次类推,左右子树也为二叉搜索树(这就是重复性) +- 中序遍历是升序排列的 +- 空树也是二叉搜索树 + +#### 问题 +当二叉树的结构趋于一个链表的时候,查找时间复杂的退化为O(n),保证性能的关键是保证二维维度。 + +## 平衡二叉搜索树 + +### AVL树 + +- 左右两个子树的高度差的绝对值不超过1 +- 左右两个子树都是一棵平衡二叉树 + +#### 平衡因子 +- 结点的左子树与右子树的高度(深度)差即为该结点的平衡因子(BF,Balance Factor)。 +- 平衡二叉树上所有结点的平衡因子只可能是 -1,0 或 1 + +#### 添加节点 +- 添加节点会破坏平衡 +- 通过旋转操作进行平衡(左旋,右旋,左右旋,右左旋) + +### 红黑树 + +红黑树是一种近似平衡的二叉搜索树(Binary Search Tree),它能够确保任何一 +个结点的左右子树的高度差小于两倍。 + +- 每个结点要么是红色,要么是黑色 +- 根节点是黑色的; +- 每个叶子节点都是黑色的空节点(NIL),也就是说,叶子节点不存储数据; +- 任何相邻的节点都不能同时为红色,也就是说,红色节点是被黑色节点隔开的; +- 每个节点,从该节点到达其可达叶子节点的所有路径,都包含相同数目的黑色节点; + +### AVL树和红黑树的区别 +- AVL树是严格平衡,红黑树是近似平衡 +- 红黑树的查询性能略微逊色于AVL树; +- 红黑树在插入和删除上优于AVL树,AVL树每次插入删除会进行大量的平衡度计算; +- 实际应用中,若搜索的次数远远大于插入和删除,那么选择AVL,如果搜索,插入删除次数几乎差不多,应该选择红黑树。 diff --git a/Week_07/SolveSudoku.swift b/Week_07/SolveSudoku.swift new file mode 100644 index 00000000..741ea689 --- /dev/null +++ b/Week_07/SolveSudoku.swift @@ -0,0 +1,65 @@ +// +// SolveSudoku.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/20. +// + +import Foundation + +class SolveSudoku { + + //第一种方式 + func solveSudoku10(_ board: inout [[Character]]) { + guard board.count > 0, board[0].count > 0 else { + return + } + solve(&board) + } + + @discardableResult + func solve(_ board: inout [[Character]]) -> Bool { + for i in 0..<9 { + for j in 0..<9 { + if board[i][j] == "." { + for c in "123456789" { + if isValid(board, i, j, c) { + board[i][j] = c + if solve(&board) { + return true + } else { + board[i][j] = "." + } + } + } + return false + } + } + } + return true + } + + func isValid(_ board: [[Character]], _ i: Int, _ j: Int, _ c: Character) -> Bool { + for k in 0..<9 { + if board[i][k] == c { + return false + } + if board[k][j] == c { + return false + } + if board[3 * (i / 3) + k / 3][3 * (j / 3) + k % 3] == c { + return false + } + } + return true + } + + func test() { + var a: [[Character]] = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]] + solveSudoku10(&a) + print(a) + } + +} + + diff --git a/Week_07/TrieTree.swift b/Week_07/TrieTree.swift new file mode 100644 index 00000000..f569cb90 --- /dev/null +++ b/Week_07/TrieTree.swift @@ -0,0 +1,80 @@ +// +// TrieTree.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/16. +// + +import Foundation + +class TrieTreeNode { + public var next = [Character: TrieTreeNode]() + public var end: Bool + + public init() { + self.end = false + } +} + +class Trie { + + var root: TrieTreeNode + + /** Initialize your data structure here. */ + init() { + root = TrieTreeNode() + } + + /** Inserts a word into the trie. */ + func insert(_ word: String) { + var node = root + for c in word { + if node.next[c] == nil { + node.next[c] = TrieTreeNode() + } + node = node.next[c]! + } + node.end = true + } + + /** Returns if the word is in the trie. */ + func search(_ word: String) -> Bool { + return findWord(word)?.end ?? false + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + func startsWith(_ prefix: String) -> Bool { + return findWord(prefix) != nil + } + + func findWord(_ word: String) -> TrieTreeNode? { + var node = root + for c in word { + if let next = node.next[c] { + node = next + } else { + return nil + } + } + return node + } + + func test() { + let word = "apple" + let obj = Trie() + obj.insert(word) + let ret_2: Bool = obj.search(word) + let ret_3: Bool = obj.startsWith("app") + let ret_4: Bool = obj.search("app") + let ret_5: Bool = obj.startsWith("apl") + print(ret_2, ret_3, ret_4, ret_5); + } +} + +/** + * Your Trie object will be instantiated and called as such: + * let obj = Trie() + * obj.insert(word) + * let ret_2: Bool = obj.search(word) + * let ret_3: Bool = obj.startsWith(prefix) + */ diff --git a/Week_07/ValidSudoku.swift b/Week_07/ValidSudoku.swift new file mode 100644 index 00000000..8805ec3e --- /dev/null +++ b/Week_07/ValidSudoku.swift @@ -0,0 +1,33 @@ +// +// ValidSudoku.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/21. +// + +import Foundation + +class ValidSudoku { + //有效的数独 + func isValidSudoku(_ board: [[Character]]) -> Bool { + var cols = [Set](repeating: [], count: 9) + var rows = [Set](repeating: [], count: 9) + var boxs = [Set](repeating: [], count: 9) + for i in 0..<9 { + for j in 0..<9 { + let char = board[i][j] + if char == "." { + continue + } + let boxIndex = (i / 3) * 3 + j / 3 + if rows[i].contains(char) || cols[j].contains(char) || boxs[boxIndex].contains(char) { + return false + } + rows[i].insert(char) + cols[j].insert(char) + boxs[boxIndex].insert(char) + } + } + return true + } +} diff --git a/Week_07/WordLadder.swift b/Week_07/WordLadder.swift new file mode 100644 index 00000000..53e98781 --- /dev/null +++ b/Week_07/WordLadder.swift @@ -0,0 +1,106 @@ +// +// WordLadder.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/26. +// + +import Foundation + +class WordLadder { + + //单向bfs + func ladderLength(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + let wordSet = Set(wordList) + guard wordSet.contains(endWord) else { + return 0 + } + var queue = [beginWord] + var visited: Set = [beginWord] + var res = 1 + while !queue.isEmpty { + let n = queue.count + for _ in 0.., _ visited: inout Set) -> Bool { + var wordArr = Array(curWord) + for i in 0.. Int { + let wordSet = Set(wordList) + guard wordSet.contains(endWord) else { + return 0 + } + var beginSet: Set = [beginWord], endSet: Set = [endWord], visited: Set = [beginWord] + var res = 1 + while !beginSet.isEmpty && !endSet.isEmpty { + if beginSet.count > endSet.count { + swap(&beginSet, &endSet) + } + var nextLevelSet = Set() + for word in beginSet { + if changeWordEveryOneLetter10(word, endSet, wordSet, &visited, &nextLevelSet) { + return res + 1 + } + } + beginSet = nextLevelSet + res += 1 + } + return 0 + } + + func changeWordEveryOneLetter10(_ word: String, _ endSet: Set, _ wordSet: Set, _ visited: inout Set, _ nextLevelSet: inout Set) -> Bool { + var wordArr = Array(word) + for i in 0.. [Int] { + var dp = [Int](repeating: 0, count: num + 1) + for i in 1..> 1] + i & 1 + } + return dp + } + + func countBits10(_ num: Int) -> [Int] { + var dp = [Int](repeating: 0, count: num + 1) + for i in 1.. [[String]] { + var res = [[String]]() + var queens = [Int](repeating: -1, count: n) + var cols = Set(), dia1 = Set(), dia2 = Set() + func backtrack(_ row: Int) { + if row == n { + res.append(generateBoard(queens, n)) + return + } + for i in 0.. [String] { + var board = [String]() + for i in 0.. [[String]] { + var res = [[String]]() + var queens = [Int](repeating: -1, count: n) + var colSet = Set(), diaSet1 = Set(), diaSet2 = Set() + backtrack(0, n, &queens, &colSet, &diaSet1, &diaSet2, &res) + return res + } + + func backtrack(_ row: Int, _ n: Int, _ queens: inout [Int], _ colSet: inout Set, _ diaSet1: inout Set, _ diaSet2: inout Set, _ res: inout [[String]]) { + if row == n { + res.append(generateBoard(queens, n)) + return + } + for i in 0.. Int { + var res = 0, n = n + while n != 0 { + n &= (n - 1) + res += 1 + } + return res + } + + func hammingWeight10(_ n: Int) -> Int { + var count = 0, n = n + while n != 0 { + if n & 1 == 1{ + count += 1 + } + n >>= 1 + } + return count + } + +} diff --git a/Week_08/PowerOfTwo.swift b/Week_08/PowerOfTwo.swift new file mode 100644 index 00000000..af8f8172 --- /dev/null +++ b/Week_08/PowerOfTwo.swift @@ -0,0 +1,27 @@ +// +// PowerOfTwo.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/21. +// + +import Foundation + +class PowerOfTwo { + + //2的幂, 如果一个数是2的幂, 则这个数的二进制只有一个位是1 + + /* + n & (n - 1) 清除最低位的1, 如果结果等于0, 说明只有一位是1 + */ + func isPowerOfTwo(_ n: Int) -> Bool { + return n > 0 && n & (n - 1) == 0 + } + + /* + n & (-n) 保留最小位的1, 如果结果等于n, 说明只有一位是1 + */ + func isPowerOfTwo10(_ n: Int) -> Bool { + return n > 0 && n & (-n) == n + } +} diff --git a/Week_08/README.md b/Week_08/README.md index 50de3041..b4587160 100644 --- a/Week_08/README.md +++ b/Week_08/README.md @@ -1 +1,146 @@ -学习笔记 \ No newline at end of file +# 学习笔记 + +## 总结 + +这周学习了位运算,布隆过滤器,LRU Cache,排序算法,感觉这周内容还是挺多的,排序的很多代码都没有完成,需要慢慢完善下。这周题目做的不多,还需要加油。 + +## 位运算 + +#### 基本的位运算 + +- 左移 >> 0011=>0110 +- 右移 << 0110=>0011 + +- 按位或 | 有一得一 +- 按位与 & 有零得零 +- 按位取反 ~ 一变零,零变一 +- 按位异或 ^ 不同得一,相同得零 + +#### 异或常用操作 + +* x ^ 0 = x +* x ^ 1s = ~x // 1s = ~0 +* x ^ (~x) = 1s +* x ^ x = 0 +* c = a ^ b => a ^ c = b , b ^ c = a // 交换两个数 +* a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c // associative + +#### 指定位置的位运算 + +1. 将x最右边的n位清零:x & (~0 << n) +2. 获取x的第你位值(0或1):(x >> n) & 1 +3. 获取x的第n位幂值: x & (1 << n) +4. 仅将第n位置为1: x | (1 << n) +5. 仅将第n位置为0: x & (~(1 << n)) +6. 将x的最高位到第n位清零: x & ((1 << n) - 1) + +#### 实战运算要点 + +* 判断奇偶 + * x % 2 == 1 => x & 1 == 1 + * x % 2 == 0 => x & 1 == 0 +* x >> 1 => x / 2 +* x = x & (x - 1) //清零最低位的1 +* x & (-x) //得到最低位的1 +* x & ~x => 0 + +## 布隆过滤器 Bloom Filter + +#### 介绍 + +* 作用:检索一个元素是否在一个集合中。 +* 优点:空间效率和查询时间都远远超出一般算法。 +* 缺点:有一定的误识别率和删除困难。 + +#### 案例 + +1. 比特币网络 +2. 分布式系统 +3. Redis缓存 +4. 垃圾邮件、评论过滤 + +## LRU Cache + +least recently used 最近最少使用 + +## 排序 + +#### 比较类排序 + +- 交换排序 + - 冒泡排序 + - 快速排序 +- 插入排序 + - 简单插入排序 + - 希尔排序 +- 选择排序 + - 简单选择排序 + - 堆排序 +- 归并排序 + - 二路归并排序 + - 多路归并排序 + +#### 非比较类排序 + +- 计数排序 +- 桶排序 +- 基数排序 + +#### 简单排序的代码 + +``` +/* + 插入排序: + 1. 从第一个元素开始,该元素可以认为已经被排序 + 2. 取出下一个元素,在已经排序的元素序列中从后向前扫描 + 3. 如果该元素(已排序)大于新元素,将该元素移到下一位置 + 4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置 + 5. 将新元素插入到该位置中 + 6. 重复步骤2 + */ +func insertSort(_ arr: inout [Int]) { + for i in 1..= 0 && arr[j] > key { + arr[j + 1] = arr[j] + j -= 1 + } + arr[j + 1] = key + } +} + +/* + 选择排序: + 1. 遍历数组,找到最小的元素,将其置于数组起始位置。 + 2. 从上次最小元素存放的后一个元素开始遍历至数组尾,将最小的元素置于开始处。 + 3. 重复上述过程,直到元素排序完毕。 + */ +func selectionSort(_ arr: inout [Int]) { + for i in 0.. arr[j + 1] { + arr.swapAt(j, j + 1) + } + } + } +} +``` \ No newline at end of file diff --git a/Week_08/RelativeSortArray.swift b/Week_08/RelativeSortArray.swift new file mode 100644 index 00000000..589833f0 --- /dev/null +++ b/Week_08/RelativeSortArray.swift @@ -0,0 +1,46 @@ +// +// RelativeSortArray.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/24. +// + +import Foundation + +/*数组的相对排序*/ + +class RelativeSortArray { + + func relativeSortArray(_ arr1: [Int], _ arr2: [Int]) -> [Int] { + var dict = [Int: Int]() + for i in arr1 { + dict[i] = (dict[i] ?? 0) + 1 + } + var res = [Int]() + for j in arr2 { + res.append(contentsOf: Array(repeating: j, count: dict[j]!)) + dict[j] = nil + } + for (key, val) in dict.sorted(by: {$0.0 < $1.0}) { + res.append(contentsOf: Array(repeating: key, count: val)) + } + return res + } + + func relativeSortArray10(_ arr1: [Int], _ arr2: [Int]) -> [Int] { + var countArr = [Int](repeating: 0, count: 1001) + for i in arr1 { + countArr[i] += 1 + } + var res = [Int]() + for j in arr2 { + res.append(contentsOf: Array(repeating: j, count: countArr[j])) + countArr[j] = 0 + } + for (index, value) in countArr.enumerated() where value > 0 { + res.append(contentsOf: Array(repeating: index, count: value)) + } + return res + } + +} diff --git a/Week_08/ReverseBits.swift b/Week_08/ReverseBits.swift new file mode 100644 index 00000000..ddccc6df --- /dev/null +++ b/Week_08/ReverseBits.swift @@ -0,0 +1,32 @@ +// +// ReverseBits.swift +// LeetCodeDemo +// +// Created by Apple on 2021/1/21. +// + +import Foundation + +class ReverseBits { + //颠倒二进制位 + func reverseBits(_ n: Int) -> Int { + let n = UInt32(n) + var res = UInt32(0) + for i in 0..<32 { + let temp = (n >> i) & 1 + res |= (temp << (31 - i)) + } + return Int(res) + } + + //思路更清晰 + func reverseBits10(_ n: Int) -> Int { + var n = UInt32(n), res = UInt32(0) + for _ in 0..<32 { + res <<= 1 + res |= n & 1 + n >>= 1 + } + return Int(res) + } +} diff --git a/Week_08/SolveSudoku.swift b/Week_08/SolveSudoku.swift new file mode 100644 index 00000000..1742c4fd --- /dev/null +++ b/Week_08/SolveSudoku.swift @@ -0,0 +1,130 @@ +// +// SolveSudoku.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/20. +// + +import Foundation + +class SolveSudoku { + + /* + 第一种方式: + 直接找出空格位置 + 对指定的空格和剩余的数字进行匹配 + 效率更高 + */ + + var rows = Array(repeating: Set("123456789"), count: 9) + var cols = Array(repeating: Set("123456789"), count: 9) + var blocks = Array(repeating: Set("123456789"), count: 9) + var spaces = [[Int]]() + func solveSudoku(_ board: inout [[Character]]) { + let m = board.count, n = board[0].count + for i in 0.. Bool { + if iter == spaces.count { + return true + } + let i = spaces[iter][0], j = spaces[iter][1], b = getBlockIndex(i, j) + //三个方向可以填入的值取交集, 放到temp + let temp = rows[i].intersection(cols[j]).intersection(blocks[b]) + for val in temp { + rows[i].remove(val) + cols[j].remove(val) + blocks[b].remove(val) + board[i][j] = val + if backtrack(iter + 1, &board) { + return true + } + board[i][j] = "." + rows[i].insert(val) + cols[j].insert(val) + blocks[b].insert(val) + } + return false + } + + func getBlockIndex(_ i: Int, _ j: Int) -> Int { + return 3 * (i / 3) + j / 3 + } + + /* + 第二种方式: + 相比第一种方案每次都从1~9尝试, 会有一些无用的尝试操作 + */ + func solveSudoku10(_ board: inout [[Character]]) { + guard board.count > 0, board[0].count > 0 else { + return + } + solve(&board) + } + + @discardableResult + func solve(_ board: inout [[Character]]) -> Bool { + for i in 0..<9 { + for j in 0..<9 { + if board[i][j] != "." { + continue + } + //没有值 + for c in "123456789" { + if !isValid(board, i, j, c) { + continue + } + //c是有效的, 设置值, 进行回溯 + board[i][j] = c + if solve(&board) { + return true + } + board[i][j] = "." + } + return false + } + } + return true + } + + func isValid(_ board: [[Character]], _ i: Int, _ j: Int, _ c: Character) -> Bool { + for k in 0..<9 { + if board[i][k] == c { + return false + } + if board[k][j] == c { + return false + } + if board[3 * (i / 3) + k / 3][3 * (j / 3) + k % 3] == c { + return false + } + } + return true + } + + + + func test() { + var a: [[Character]] = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]] + solveSudoku(&a) + print(a) + } + + +} + + diff --git a/Week_08/Sort.swift b/Week_08/Sort.swift new file mode 100644 index 00000000..98e5c72b --- /dev/null +++ b/Week_08/Sort.swift @@ -0,0 +1,200 @@ +// +// Sort.swift +// LeetCodeDemo +// +// Created by Apple on 2021/1/25. +// + +import Foundation + +class Sort { + + /* + 插入排序:O(n^2) O(1) 稳定 + 1. 从第一个元素开始,该元素可以认为已经被排序 + 2. 取出下一个元素,在已经排序的元素序列中从后向前扫描 + 3. 如果该元素(已排序)大于新元素,将该元素移到下一位置 + 4. 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置 + 5. 将新元素插入到该位置中 + 6. 重复步骤2 + */ + func insertSort(_ arr: inout [Int]) { + for i in 1..= 0 && arr[j] > key { + arr[j + 1] = arr[j] + j -= 1 + } + arr[j + 1] = key + } + } + + /* + 选择排序:O(n^2) O(1) 不稳定 + 1. 遍历数组,找到最小的元素,将其置于数组起始位置。 + 2. 从上次最小元素存放的后一个元素开始遍历至数组尾,将最小的元素置于开始处。 + 3. 重复上述过程,直到元素排序完毕。 + */ + func selectionSort(_ arr: inout [Int]) { + for i in 0.. arr[j + 1] { + arr.swapAt(j, j + 1) + } + } + } + } + + + /* + 归并排序: O(nlogn) O(n) 稳定 + 1. 申请空间,创建两个数组,长度分别为两个有序数组的长度 + 2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置 + 3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 + 4. 重复步骤3直到某一指针达到序列尾 + 5. 将另一序列剩下的所有元素直接复制到合并序列尾 + */ + func mergeSort(_ arr: inout [Int]) { + mergeSortHelper(&arr, 0, arr.count - 1) + } + + func mergeSortHelper(_ arr: inout [Int], _ left: Int, _ right: Int) { + if left >= right { + return + } + let mid = (left + right) >> 1 + mergeSortHelper(&arr, left, mid) + mergeSortHelper(&arr, mid + 1, right) + merge(&arr, left, mid, right) + } + + func merge(_ arr: inout [Int], _ left: Int, _ mid: Int, _ right: Int) { + var temp = [Int]() + var i = left, j = mid + 1 + while i <= mid && j <= right { + if arr[i] <= arr[j] { + temp.append(arr[i]) + i += 1 + } else { + temp.append(arr[j]) + j += 1 + } + } + while i <= mid { + temp.append(arr[i]) + i += 1 + } + while j <= right { + temp.append(arr[j]) + j += 1 + } + for p in 0..= right { + return + } + let pivot = partition(&arr, left, right) + quickSortHelper(&arr, left, pivot - 1) + quickSortHelper(&arr, pivot + 1, right) + } + + func partition(_ arr: inout [Int], _ left: Int, _ right: Int) -> Int { + var pivot = right, counter = left + for i in left.. 0 { + arr.swapAt(0, k) + k -= 1 + heapify(&arr, k, 0) + } + } + + func buildHeap(_ arr: inout [Int], _ n: Int) { + var i = n / 2 + while i >= 0 { + heapify(&arr, n, i) + i -= 1 + } + } + + func heapify(_ arr: inout [Int], _ n: Int, _ i: Int) { + var i = i + while true { + var maxPos = i + let left = i * 2 + 1 + if left <= n && arr[left] > arr[maxPos] { + maxPos = left + } + let right = i * 2 + 2 + if right <= n && arr[right] > arr[maxPos] { + maxPos = right + } + if maxPos == i { + break + } + arr.swapAt(maxPos, i) + i = maxPos + } + } + + + func test() { + var arr = [15,2,1,6,7,9,34,5] + heapSort(&arr) + print(arr) + } + +} diff --git a/Week_08/ValidAnagram.swift b/Week_08/ValidAnagram.swift new file mode 100644 index 00000000..b68db83c --- /dev/null +++ b/Week_08/ValidAnagram.swift @@ -0,0 +1,64 @@ +// +// ValidAnagram.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/12. +// + +import Foundation + +class ValidAnagram { + /// 有效异位词 + func isAnagram(_ s: String, _ t: String) -> Bool { + guard s.count == t.count else { + return false + } + if s.sorted() == t.sorted() { + return true + } else { + return false + } + } + + // 数组方式 + func isAnagram01(_ s: String, _ t: String) -> Bool { + guard s.count == t.count else { + return false + } + var arr = [Int](repeating: 0, count: 26) + let aCharUnicodeScalar = Int("a".unicodeScalars.first!.value) + for c in s.unicodeScalars { + arr[Int(c.value) - aCharUnicodeScalar] += 1 + } + for c in t.unicodeScalars { + arr[Int(c.value) - aCharUnicodeScalar] -= 1 + } + guard arr.first( where: {$0 != 0} ) == nil else { + return false + } + return true + } + + //字典方式 + func isAnagram02(_ s: String, _ t: String) -> Bool { + guard s.count == t.count else { + return false + } + var hashMap = [Character: Int]() + for c in s { + hashMap[c] = hashMap[c] ?? 0 + 1 + } + for c in t { + if hashMap[c] == nil { + return false + } + hashMap[c]! -= 1 + if hashMap[c]! < 0 { + return false + } + } + return true + } + + +} diff --git a/Week_08/ValidSudoku.swift b/Week_08/ValidSudoku.swift new file mode 100644 index 00000000..8805ec3e --- /dev/null +++ b/Week_08/ValidSudoku.swift @@ -0,0 +1,33 @@ +// +// ValidSudoku.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/21. +// + +import Foundation + +class ValidSudoku { + //有效的数独 + func isValidSudoku(_ board: [[Character]]) -> Bool { + var cols = [Set](repeating: [], count: 9) + var rows = [Set](repeating: [], count: 9) + var boxs = [Set](repeating: [], count: 9) + for i in 0..<9 { + for j in 0..<9 { + let char = board[i][j] + if char == "." { + continue + } + let boxIndex = (i / 3) * 3 + j / 3 + if rows[i].contains(char) || cols[j].contains(char) || boxs[boxIndex].contains(char) { + return false + } + rows[i].insert(char) + cols[j].insert(char) + boxs[boxIndex].insert(char) + } + } + return true + } +} diff --git a/Week_09/DecodeWays.swift b/Week_09/DecodeWays.swift new file mode 100644 index 00000000..b61059bb --- /dev/null +++ b/Week_09/DecodeWays.swift @@ -0,0 +1,37 @@ +// +// DecodeWays.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/10. +// + +import Foundation + +class DecodeWays { + + func numDecodings(_ s: String) -> Int { + let s = Array(s) + var pre = 1, cur = 1 + if s[0] == "0" { return 0 } + for i in 1.. [Int] { + guard s.count >= p.count else { + return [] + } + var pf = [Int](repeating: 0, count: 26) + for c in p.unicodeScalars { + pf[Int(c.value) - 97] += 1 + } + let pCnt = p.count + var res = [Int](), s = Array(s) + var popLatter: Character? = nil + for i in 0...s.count - pCnt { + if s[i + pCnt - 1] == popLatter { + res.append(i) + popLatter = s[i] + continue + } + if isAnagrams(String(s[i.. Bool { + var pf = pf + for c in s.unicodeScalars { + pf[Int(c.value) - 97] -= 1 + if pf[Int(c.value) - 97] < 0 { + return false + } + } + for i in pf { + if i != 0 { + return false + } + } + return true + } + + + + func findAnagrams10(_ s: String, _ p: String) -> [Int] { + + //滑动窗口的值,和p的值 + var window = [Character: Int]() + var needs = [Character: Int]() + for char in p { + needs[char, default: 0] += 1 + } + + let sArray = Array(s) + var left = 0, right = 0 + var match = 0 //匹配上的字母数量 + var res = [Int]() + + while right < sArray.count { + let rightChar = sArray[right] + right += 1 + + if let needCharCount = needs[rightChar] { + window[rightChar, default: 0] += 1 + if window[rightChar] == needCharCount { + match += 1 + } + } else { + continue + } + + while match == needs.count { + //匹配上的时候如果字符串长度等于P的长度,加入答案 + if right - left == p.count { + res.append(left) + } + //否者左边向前移动一位 + let leftChar = sArray[left] + left += 1 + //如果移出去的字符在P中 + if let needCharCount = needs[leftChar] { + //如果窗口值和P值相等,match记录减一 + if window[leftChar] == needCharCount { + match -= 1 + } + //窗口值减一 + window[leftChar]! -= 1 + } + } + } + + return res + } + + + func findAnagrams20(_ s: String, _ p: String) -> [Int] { + let arrs = Array(s) + let arrp = Array(p) + let base = Character("a").asciiValue! + var window = Array(repeating: 0, count: 26) + var needs = Array(repeating: 0, count: 26) + var res = [Int]() + for c in arrp { + needs[Int(c.asciiValue! - base)] += 1 + } + var left = 0, right = 0 + while right < arrs.count { + let curR = Int(arrs[right].asciiValue! - base) + right += 1 + window[curR] += 1 + while window[curR] > needs[curR] { + let curL = Int(arrs[left].asciiValue! - base) + left += 1 + window[curL] -= 1 + } + if right - left == arrp.count { + res.append(left) + } + } + return res + } + + + + + func test() { + print(findAnagrams20("cba", "abc")) + } +} diff --git a/Week_09/FirstUniqueChar.swift b/Week_09/FirstUniqueChar.swift new file mode 100644 index 00000000..243570bf --- /dev/null +++ b/Week_09/FirstUniqueChar.swift @@ -0,0 +1,89 @@ +// +// FirstUniqueChar.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/25. +// + +import Foundation + +/* + 字符串中的第一个唯一字符 + 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 + 提示:你可以假定该字符串只包含小写字母。 + */ + +class FirstUniqueChar { + + func firstUniqChar(_ s: String) -> Int { + var dict = [Character: Int]() + for c in s { + dict[c] = (dict[c] ?? 0) + 1 + } + for (i, v) in s.enumerated() { + if dict[v] == 1 { + return i + } + } + return -1 + } + + func firstUniqChar10(_ s: String) -> Int { + var position = [Character: Int]() + for (i, v) in s.enumerated() { + position[v] = position[v] == nil ? i : -1 + } + var first = s.count + for val in position.values { + if val != -1 && val < first { + first = val + } + } + return first == s.count ? -1 : first + } + + + func firstUniqChar30(_ s: String) -> Int { + var sa = [Int](repeating: 0, count: 26) + for c in s.unicodeScalars { + sa[Int(c.value) - 97] += 1 + } + var i = 0 + for c in s.unicodeScalars { + if sa[Int(c.value) - 97] == 1 { + return i + } + i += 1 + } + return -1 + } + + + //队列的方式 + func firstUniqChar20(_ s: String) -> Int { + var position = [Character: Int]() + var queue = [Pair]() + for (i, v) in s.enumerated() { + if position[v] == nil { + position[v] = i + queue.append(Pair(v, i)) + } else { + position[v] = -1 + while !queue.isEmpty && position[queue.first!.char] == -1 { + queue.removeFirst() + } + } + } + return queue.isEmpty ? -1 : queue.first!.pos + } + +} + +class Pair { + public var char: Character + public var pos: Int + public init(_ char: Character,_ pos: Int) { + self.char = char + self.pos = pos + } +} diff --git a/Week_09/GroupAnagrams.swift b/Week_09/GroupAnagrams.swift new file mode 100644 index 00000000..e6953e30 --- /dev/null +++ b/Week_09/GroupAnagrams.swift @@ -0,0 +1,28 @@ +// +// GroupAnagrams.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/12. +// + +import Foundation + +class GroupAnagrams { + + func groupAnagrams(_ strs: [String]) -> [[String]] { + var hashMap = [String: [String]]() + for str in strs { + let key = String(str.sorted()) + if hashMap[key] == nil { + hashMap[key] = [] + } + hashMap[key]!.append(str) + } + return Array(hashMap.values) + } + + func test(_ strs: [String]) { + let result = groupAnagrams(strs) + print(result) + } +} diff --git a/Week_09/IsomorphicStrings.swift b/Week_09/IsomorphicStrings.swift new file mode 100644 index 00000000..2c87f575 --- /dev/null +++ b/Week_09/IsomorphicStrings.swift @@ -0,0 +1,61 @@ +// +// IsomorphicStrings.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/31. +// + +import Foundation + +/* + 给定两个字符串 s 和 t,判断它们是否是同构的。 + + 如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。 + + 每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。 + + + + 示例 1: + + 输入:s = "egg", t = "add" + 输出:true + + 示例 2: + + 输入:s = "foo", t = "bar" + 输出:false + + 示例 3: + + 输入:s = "paper", t = "title" + 输出:true + + + + 提示: + + 可以假设 s 和 t 长度相同。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/isomorphic-strings + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + +class Solution { + func isIsomorphic(_ s: String, _ t: String) -> Bool { + var s2t = [Character: Character]() + var t2s = [Character: Character]() + let s = Array(s), t = Array(t) + for i in 0.. Int { + let jSet = Set(jewels) + var cnt = 0 + for c in stones { + if jSet.contains(c) { + cnt += 1 + } + } + return cnt + } +} diff --git a/Week_09/LengthOfLIS.swift b/Week_09/LengthOfLIS.swift new file mode 100644 index 00000000..0bfe56b5 --- /dev/null +++ b/Week_09/LengthOfLIS.swift @@ -0,0 +1,90 @@ +// +// LengthOfLIS.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/31. +// + +import Foundation +/* + 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 + + 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。 + + + 示例 1: + + 输入:nums = [10,9,2,5,3,7,101,18] + 输出:4 + 解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。 + + 示例 2: + + 输入:nums = [0,1,0,3,2,3] + 输出:4 + + 示例 3: + + 输入:nums = [7,7,7,7,7,7,7] + 输出:1 + + + + 提示: + + 1 <= nums.length <= 2500 + -104 <= nums[i] <= 104 + + + + 进阶: + + 你可以设计时间复杂度为 O(n2) 的解决方案吗? + 你能将算法的时间复杂度降低到 O(n log(n)) 吗? + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/longest-increasing-subsequence + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + +class LengthOfLIS { + + func lengthOfLIS(_ nums: [Int]) -> Int { + var tails = [Int](repeating: 0, count: nums.count) + var res = 0 + for num in nums { + var i = 0, j = res + while i < j { + let m = (i + j) >> 1 + if tails[m] < num { + i = m + 1 + } else { + j = m + } + } + tails[i] = num + if res == j { + res += 1 + } + } + return res + } + + func lengthOfLIS10(_ nums: [Int]) -> Int { + guard nums.count > 0 else { + return 0 + } + let n = nums.count + var dp = [Int](repeating: 1, count: n) + var ans = 1 + for i in 0.. nums[j] { + dp[i] = max(dp[i], dp[j] + 1) + } + } + ans = max(ans, dp[i]) + } + return ans + } +} diff --git a/Week_09/LengthOfLastWord.swift b/Week_09/LengthOfLastWord.swift new file mode 100644 index 00000000..ac879b92 --- /dev/null +++ b/Week_09/LengthOfLastWord.swift @@ -0,0 +1,43 @@ +// +// LengthOfLastWord.swift +// LeetCodeDemo +// +// Created by Apple on 2021/1/28. +// + +import Foundation +/* + 给定一个仅包含大小写字母和空格 ' ' 的字符串 s,返回其最后一个单词的长度。如果字符串从左向右滚动显示,那么最后一个单词就是最后出现的单词。 + + 如果不存在最后一个单词,请返回 0 。 + + 说明:一个单词是指仅由字母组成、不包含任何空格字符的 最大子字符串。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/length-of-last-word + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ +class LengthOfLastWord { + + func lengthOfLastWord(_ s: String) -> Int { + let s = Array(s) + var count = 0, i = s.count + while i >= 0 { + if s[i] == " " && count != 0 { + break + } else if s[i] != " " { + count += 1 + } + i -= 1 + } + return count + } + + func lengthOfLastWord10(_ s: String) -> Int { + let arr = s.split(separator: " ") + if let last = arr.last { + return last.count + } + return 0 + } +} diff --git a/Week_09/LongestCommonPrefix.swift b/Week_09/LongestCommonPrefix.swift new file mode 100644 index 00000000..56d7913d --- /dev/null +++ b/Week_09/LongestCommonPrefix.swift @@ -0,0 +1,39 @@ +// +// LongestCommonPrefix.swift +// LeetCodeDemo +// +// Created by Apple on 2021/1/29. +// + +import Foundation + +/* + 编写一个函数来查找字符串数组中的最长公共前缀。 + + 如果不存在公共前缀,返回空字符串 ""。 + + 提示: + 0 <= strs.length <= 200 + 0 <= strs[i].length <= 200 + strs[i] 仅由小写英文字母组成 + */ + +class LongestCommonPrefix { + + func longestCommonPrefix(_ strs: [String]) -> String { + guard strs.count > 0 else { + return "" + } + let firstStr = Array(strs.first!) + for i in 0.. Int { + guard text1.count > 0, text2.count > 0 else { + return 0 + } + let n1 = text1.count, n2 = text2.count + var dp = [[Int]](repeating: [Int](repeating: 0, count: n2 + 1), count: n1 + 1) + let charArr1 = Array(text1), charArr2 = Array(text2) + for i in 1.. String { + guard s.count > 1 else { + return s + } + let n = s.count + var dp = [[Bool]](repeating: [Bool](repeating: false, count: n), count: n) + var res = "", s = Array(s) + for i in (0.. res.count { + res = String(s[i.. String { + guard s.count > 1 else { + return s + } + let n = s.count + var dp = [[Bool]](repeating: [Bool](repeating: false, count: n), count: n) + var maxLengh = 1, begin = 0, s = Array(s) + //中间赋值,空串 + for i in 0.. maxLengh { + maxLengh = j - i + 1 + begin = i + } + + } + } + return String(s[begin.. String { + guard s.count > 1 else { + return s + } + let s = Array(s) + var start = 0, end = 0 + for i in 0.. end - start { + start = i - (len - 1) / 2 + end = i + len / 2 + } + } + return String(s[start.. Int { + var l = left, r = right + while l >= 0 && l < s.count && r < s.count && r < s.count && s[l] == s[r] { + l -= 1 + r += 1 + } + return r - l - 1 + } + + func test() { + print(longestPalindrome("aaaaaa")) + } +} diff --git a/Week_09/MinCostClimbingStairs.swift b/Week_09/MinCostClimbingStairs.swift new file mode 100644 index 00000000..3d6d6325 --- /dev/null +++ b/Week_09/MinCostClimbingStairs.swift @@ -0,0 +1,51 @@ +// +// MinCostClimbingStairs.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/26. +// + +import Foundation + +/* + 数组的每个下标作为一个阶梯,第 i 个阶梯对应着一个非负数的体力花费值 cost[i](下标从 0 开始)。 + + 每当你爬上一个阶梯你都要花费对应的体力值,一旦支付了相应的体力值,你就可以选择向上爬一个阶梯或者爬两个阶梯。 + + 请你找出达到楼层顶部的最低花费。在开始时,你可以选择从下标为 0 或 1 的元素作为初始阶梯。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/min-cost-climbing-stairs + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + +class MinCostClimbingStairs { + + func minCostClimbingStairs(_ cost: [Int]) -> Int { + guard cost.count >= 2 else { + return 0 + } + let n = cost.count + var pre = 0, cur = 0, temp = 0 + for i in 2.. Int { + guard cost.count >= 2 else { + return 0 + } + let n = cost.count + var dp = [Int](repeating: 0, count: n + 1) + dp[0] = 0; dp[1] = 0 + for i in 2.. String { + var S = Array(S) + var left = 0, right = S.count - 1 + while left < right { + if !S[left].isLetter { + left += 1 + continue + } + if !S[right].isLetter { + right -= 1 + continue + } + S.swapAt(left, right) + left += 1 + right -= 1 + } + return String(S) + } + + func reverseOnlyLetters10(_ S: String) -> String { + var stack = [Character](), ans = "" + for c in S { + if c.isLetter { + stack.append(c) + } + } + for c in S { + if c.isLetter { + ans.append(stack.popLast()!) + } else { + ans.append(c) + } + } + return ans + } + + func test() { + print(reverseOnlyLetters("123456789")) + } +} diff --git a/Week_09/ReverseString.swift b/Week_09/ReverseString.swift new file mode 100644 index 00000000..b62e99ca --- /dev/null +++ b/Week_09/ReverseString.swift @@ -0,0 +1,32 @@ +// +// ReverseString.swift +// LeetCodeDemo +// +// Created by Apple on 2021/1/29. +// + +import Foundation + +/* + 编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。 + + 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 + + 你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/reverse-string + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + +class ReverseString { + func reverseString(_ s: inout [Character]) { + if s.count <= 1 { return } + var left = 0, right = s.count - 1 + while left < right { + s.swapAt(left, right) + left += 1 + right -= 1 + } + } +} diff --git a/Week_09/ReverseStringII.swift b/Week_09/ReverseStringII.swift new file mode 100644 index 00000000..8632ac52 --- /dev/null +++ b/Week_09/ReverseStringII.swift @@ -0,0 +1,46 @@ +// +// ReverseStringII.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/30. +// + +import Foundation + +/* + 541. 反转字符串 II + 给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。 + + 如果剩余字符少于 k 个,则将剩余字符全部反转。 + 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。 + + 提示: + + 该字符串只包含小写英文字母。 + 给定字符串的长度和 k 在 [1, 10000] 范围内。 + + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/reverse-string-ii + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + +class ReverseStringII { + func reverseStr(_ s: String, _ k: Int) -> String { + var s = Array(s) + for i in stride(from: 0, to: s.count, by: 2 * k) { + let right = (i + k - 1 > s.count - 1) ? (s.count - 1) : (i + k - 1) + reverseString(&s, i, right) + } + return String(s) + } + + func reverseString(_ s: inout [Character], _ left: Int, _ right: Int) { + var left = left, right = right + while left < right { + s.swapAt(left, right) + left += 1 + right -= 1 + } + } +} diff --git a/Week_09/ReverseWordInString.swift b/Week_09/ReverseWordInString.swift new file mode 100644 index 00000000..c9aec269 --- /dev/null +++ b/Week_09/ReverseWordInString.swift @@ -0,0 +1,30 @@ +// +// ReverseWordInString.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/30. +// + +import Foundation + +/* + 给定一个字符串,逐个翻转字符串中的每个单词。 + + 说明: + + 无空格字符构成一个 单词 。 + 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。 + 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/reverse-words-in-a-string + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + +class ReverseWordInString { + func reverseWords(_ s: String) -> String { + var arr = s.split(separator: " ") + arr.reverse() + return arr.joined(separator: " ") + } +} diff --git a/Week_09/ReverseWordInStringIII.swift b/Week_09/ReverseWordInStringIII.swift new file mode 100644 index 00000000..78654796 --- /dev/null +++ b/Week_09/ReverseWordInStringIII.swift @@ -0,0 +1,59 @@ +// +// ReverseWordInStringIII.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/30. +// + +import Foundation + +/* + 给定一个字符串,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。 + + + + 示例: + + 输入:"Let's take LeetCode contest" + 输出:"s'teL ekat edoCteeL tsetnoc" + + + + 提示: + + 在字符串中,每个单词由单个空格分隔,并且字符串中不会有任何额外的空格。 + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/reverse-words-in-a-string-iii + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + + +class ReverseWordInStringIII { + + func reverseWords(_ s: String) -> String { + var s = Array(s) + let n = s.count + var i = 0 + while i < n { + var start = i + while i < n && s[i] != " " { + i += 1 + } + var end = i - 1 + while start < end { + s.swapAt(start, end) + start += 1 + end -= 1 + } + while i < n && s[i] == " " { + i += 1 + } + } + return String(s) + } + + func reverseWords10(_ s: String) -> String { + return String(s.split(separator: " ").map( { $0.reversed() }).joined(separator: " ")) + } +} diff --git a/Week_09/ToLowerCase.swift b/Week_09/ToLowerCase.swift new file mode 100644 index 00000000..ab9c3639 --- /dev/null +++ b/Week_09/ToLowerCase.swift @@ -0,0 +1,45 @@ +// +// ToLowerCase.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2021/1/27. +// + +import Foundation + +/* + 实现函数 ToLowerCase(),该函数接收一个字符串参数 str,并将该字符串中的大写字母转换成小写字母,之后返回新的字符串。 + */ + +class ToLowerCase { + + func toLowerCase(_ str: String) -> String { + guard str.count > 0 else { + return str + } + var res = Array(str) + for c in str { + var i = c.asciiValue! + i |= 32 + res.append(Character(UnicodeScalar(i))) + } + return String(res) + } + + func toLowerCase10(_ str: String) -> String { + return String(str.map { Character(UnicodeScalar($0.asciiValue! | 32)) }) + } + + func toLowerCase20(_ str: String) -> String { + return str.lowercased() + } + + func toLowerCase30(_ str: String) -> String { + var cArr = [Character]() + for c in str.unicodeScalars { + cArr.append(Character(UnicodeScalar(c.value | 32)!)) + } + return String(cArr) + } + +} diff --git a/Week_09/ValidAnagram.swift b/Week_09/ValidAnagram.swift new file mode 100644 index 00000000..b68db83c --- /dev/null +++ b/Week_09/ValidAnagram.swift @@ -0,0 +1,64 @@ +// +// ValidAnagram.swift +// LeetCodeDemo +// +// Created by Yangdongwu on 2020/12/12. +// + +import Foundation + +class ValidAnagram { + /// 有效异位词 + func isAnagram(_ s: String, _ t: String) -> Bool { + guard s.count == t.count else { + return false + } + if s.sorted() == t.sorted() { + return true + } else { + return false + } + } + + // 数组方式 + func isAnagram01(_ s: String, _ t: String) -> Bool { + guard s.count == t.count else { + return false + } + var arr = [Int](repeating: 0, count: 26) + let aCharUnicodeScalar = Int("a".unicodeScalars.first!.value) + for c in s.unicodeScalars { + arr[Int(c.value) - aCharUnicodeScalar] += 1 + } + for c in t.unicodeScalars { + arr[Int(c.value) - aCharUnicodeScalar] -= 1 + } + guard arr.first( where: {$0 != 0} ) == nil else { + return false + } + return true + } + + //字典方式 + func isAnagram02(_ s: String, _ t: String) -> Bool { + guard s.count == t.count else { + return false + } + var hashMap = [Character: Int]() + for c in s { + hashMap[c] = hashMap[c] ?? 0 + 1 + } + for c in t { + if hashMap[c] == nil { + return false + } + hashMap[c]! -= 1 + if hashMap[c]! < 0 { + return false + } + } + return true + } + + +} diff --git a/Week_09/ValidPalindrome.swift b/Week_09/ValidPalindrome.swift new file mode 100644 index 00000000..802e6276 --- /dev/null +++ b/Week_09/ValidPalindrome.swift @@ -0,0 +1,65 @@ +// +// ValidPalindrome.swift +// LeetCodeDemo +// +// Created by Apple on 2021/1/31. +// + +import Foundation + +/* + 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。 + + 说明:本题中,我们将空字符串定义为有效的回文串。 + + 示例 1: + + 输入: "A man, a plan, a canal: Panama" + 输出: true + + 示例 2: + + 输入: "race a car" + 输出: false + + 来源:力扣(LeetCode) + 链接:https://leetcode-cn.com/problems/valid-palindrome + 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 + */ + +class ValidPalindrome { + func isPalindrome(_ s: String) -> Bool { + let lowS = s.lowercased() + var sArr = [Character]() + for c in lowS { + if c.isLetter || c.isNumber { + sArr.append(c) + } + } + var left = 0, right = sArr.count - 1 + while left < right { + if sArr[left] != sArr[right] { + return false + } + left += 1 + right -= 1 + } + return true + } + + func isPalindrome10(_ s: String) -> Bool { + let lowS = s.lowercased() + var sArr = "" + for c in lowS { + if c.isLetter || c.isNumber { + sArr.append(c) + } + } + let reverseLowS = sArr.reversed() + return sArr == String(reverseLowS) + } + + func test() { + print(isPalindrome10("A man, a plan, a canal: Panama")) + } +} diff --git "a/Week_\346\257\225\344\270\232\346\200\273\347\273\223/README.md" "b/Week_\346\257\225\344\270\232\346\200\273\347\273\223/README.md" index 50de3041..8616b97d 100644 --- "a/Week_\346\257\225\344\270\232\346\200\273\347\273\223/README.md" +++ "b/Week_\346\257\225\344\270\232\346\200\273\347\273\223/README.md" @@ -1 +1,30 @@ -学习笔记 \ No newline at end of file +# 毕业总结 + +## 初衷 +我是一名非计算机专业毕业的开发者,深知自身基础知识的薄弱,遂开始学习数据结构和算法,身边的同事有的鼓励我,也有的说学习算法平时工作用不上,但是数据结构和算法是一门计算机基础课程,精通算法是每一名优秀开发者的基本素养,我想成为一名合格的开发者,我要学习算法。 + +## 困惑 +开始自学时买了书《大话数据结构》,也用微信读书看电子书《算法图解》,但是在学习的过程中总是很难坚持下去,最终的结果就是过了几个月依然停留在几种简单的数据结构学习,无法继续下去,自己的信心也受到了很大的打击。 +在这种情况下,我能怎么改变现状呢,一度陷入了迷茫,因为平时有用极客时间学习iOS课程,2020年11月30号的晚上,在看了超哥的直播后,又刚好赶上算法训练营开班招生,便毅然决然的报名了。 + +## 开始 +开始还有些害怕自己跟不上大家的节奏,但是经过了几周的学习后,发现自己的担心是多余的,自己在不断的学习中有了很大的进步,算法训练营的学习既系统又高效,覃超老师不光教会我们各种算法知识,还教会我们学习方法,就像指路的明灯,让我们在学习中克服眼前的困难,披荆斩棘,不断前行。 + +## 结束并不是终点 +现在算法训练营接近尾声了,我们马上也就要毕业了,算法训练营毕业了,但是在算法的学习才刚刚开始,希望在以后的工作学习中,能够不忘初心,坚持学习,坚持刷题,让做题成为一种习惯,让算法在脑海中根深蒂固。 + +## 心得体会 +自从我开始学习算法以来就不乏言之无用者,我是一名iOS开发者,现在就职于一家租车公司,负责iOS客户APP的开发,平时工作对数据结构和算法使用不多。现如今大多数人做什么事情必定是有其明确的目的,在眼前看不到收益的情况下很难坚持做一件事情,更何况学习算法并不是一件简单的事情。在这种情况下,拿到大厂offer成为了大多数人学习算法的最初驱动力,当然这无可厚非,就像高中的时候我们努力学习就是为了考上心仪的大学一样。 + +我也希望能到大厂工作,但是这并不是学习的最终目的,《论语》有言, +> 子曰:“学而时习之,不亦说乎?有朋自远方来,不亦乐乎?人不知而不愠,不亦君子乎?” + +让学习成为一种习惯,“学而时习之”,这才是学习的真谛。 + + +算法是计算机基础知识,类比于武侠小说,数据结构和算法就像是基本功法,也是后续学习高级功法的基础,一座楼的高度是由地基决定的,一个人的高度就是由基本功决定的,学习算法意义重大。 + +参加算法训练营,有良师指导,助教解惑,还有优秀的同学一起进步,更有班主任的时刻督促,这十周的学习真可谓是受益匪浅,感谢有你们的陪伴。 + + +