From 7b9c552273a07fd02fe38d5e1a167e317902272e Mon Sep 17 00:00:00 2001 From: Jefferson Date: Thu, 16 Feb 2023 02:23:06 +0800 Subject: [PATCH] Add dart chapter_computational_complexity (#363) * add dart chapter_array_and_linkedlist * update my_list.dart * update chapter_array_and_linkedlist * Update my_list.dart * Update array.dart * Update file name * Add chapter_computational_complexity * Add chapter_computational_complexity * add space_complexity class and format code * remove class --------- Co-authored-by: huangjianqing Co-authored-by: Yudong Jin --- .../linked_list.dart | 11 +- .../leetcode_two_sum.dart | 47 +++++ .../space_complexity.dart | 106 ++++++++++++ .../time_complexity.dart | 163 ++++++++++++++++++ .../worst_best_time_complexity.dart | 39 +++++ codes/dart/utils/PrintUtil.dart | 21 --- .../utils/{ListNode.dart => list_node.dart} | 0 codes/dart/utils/print_util.dart | 72 ++++++++ codes/dart/utils/tree_node.dart | 69 ++++++++ 9 files changed, 502 insertions(+), 26 deletions(-) create mode 100644 codes/dart/chapter_computational_complexity/leetcode_two_sum.dart create mode 100644 codes/dart/chapter_computational_complexity/space_complexity.dart create mode 100644 codes/dart/chapter_computational_complexity/time_complexity.dart create mode 100644 codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart delete mode 100644 codes/dart/utils/PrintUtil.dart rename codes/dart/utils/{ListNode.dart => list_node.dart} (100%) create mode 100644 codes/dart/utils/print_util.dart create mode 100644 codes/dart/utils/tree_node.dart diff --git a/codes/dart/chapter_array_and_linkedlist/linked_list.dart b/codes/dart/chapter_array_and_linkedlist/linked_list.dart index 37369d101..00efdfc4d 100644 --- a/codes/dart/chapter_array_and_linkedlist/linked_list.dart +++ b/codes/dart/chapter_array_and_linkedlist/linked_list.dart @@ -4,8 +4,9 @@ * Author: Jefferson (JeffersonHuang77@gmail.com) */ -import '../utils/ListNode.dart'; -import '../utils/PrintUtil.dart'; +import '../utils/list_node.dart'; +import '../utils/print_util.dart'; + class LinkedList { /* 在链表的结点 n0 之后插入结点 P */ @@ -62,15 +63,15 @@ int main() { n3.next = n4; print('初始化的链表为'); - PrintUtil().printLinkedList(n0); + printLinkedList(n0); /* 插入结点 */ LinkedList().insert(n0, ListNode(0)); - PrintUtil().printLinkedList(n0); + printLinkedList(n0); /* 删除结点 */ LinkedList().remove(n0); - PrintUtil().printLinkedList(n0); + printLinkedList(n0); /* 访问结点 */ ListNode? node = LinkedList().access(n0, 3); diff --git a/codes/dart/chapter_computational_complexity/leetcode_two_sum.dart b/codes/dart/chapter_computational_complexity/leetcode_two_sum.dart new file mode 100644 index 000000000..410b08831 --- /dev/null +++ b/codes/dart/chapter_computational_complexity/leetcode_two_sum.dart @@ -0,0 +1,47 @@ +/** + * File: leetcode_two_sum.dart + * Created Time: 2023-2-11 + * Author: Jefferson (JeffersonHuang77@gmail.com) + */ + +import 'dart:collection'; + +/* 方法一: 暴力枚举 */ +List twoSumBruteForce(List nums, int target) { + int size = nums.length; + for (var i = 0; i < size - 1; i++) { + for (var j = i + 1; j < size; j++) { + if (nums[i] + nums[j] == target) return [i, j]; + } + } + return [0]; +} + +/* 方法二: 辅助哈希表 */ +List twoSumHashTable(List nums, int target) { + int size = nums.length; + Map dic = HashMap(); + for (var i = 0; i < size; i++) { + if (dic.containsKey(target - nums[i])) { + return [dic[target - nums[i]]!, i]; + } + dic.putIfAbsent(nums[i], () => i); + } + return [0]; +} + +/* Driver Code */ +int main() { + // ======= Test Case ======= + List nums = [2, 7, 11, 15]; + int target = 9; + + // ====== Driver Code ====== + // 方法一 + List res = twoSumBruteForce(nums, target); + print('方法一 res = $res'); + // 方法二 + res = twoSumHashTable(nums, target); + print('方法二 res = $res'); + return 0; +} diff --git a/codes/dart/chapter_computational_complexity/space_complexity.dart b/codes/dart/chapter_computational_complexity/space_complexity.dart new file mode 100644 index 000000000..8ce1e9cae --- /dev/null +++ b/codes/dart/chapter_computational_complexity/space_complexity.dart @@ -0,0 +1,106 @@ +/** + * File: space_complexity.dart + * Created Time: 2023-2-12 + * Author: Jefferson (JeffersonHuang77@gmail.com) + */ + +import 'dart:collection'; +import '../utils/list_node.dart'; +import '../utils/print_util.dart'; +import '../utils/tree_node.dart'; + +/* 函数 */ +int function() { + // do something + return 0; +} + +/* 常数阶 */ +void constant(int n) { + // 常量、变量、对象占用 O(1) 空间 + final int a = 0; + int b = 0; + + List nums = List.filled(10000, 0); + // 循环中的变量占用 O(1) 空间 + for (var i = 0; i < n; i++) { + int c = 0; + } + // 循环中的函数占用 O(1) 空间 + for (var i = 0; i < n; i++) { + function(); + } +} + +/* 线性阶 */ +void linear(int n) { + // 长度为 n 的数组占用 O(n) 空间 + List nums = List.filled(n, 0); + // 长度为 n 的列表占用 O(n) 空间 + List nodes = []; + for (var i = 0; i < n; i++) { + nodes.add(ListNode(i)); + } + // 长度为 n 的哈希表占用 O(n) 空间 + Map map = HashMap(); + for (var i = 0; i < n; i++) { + map.putIfAbsent(i, () => i.toString()); + } +} + +/* 线性阶(递归实现) */ +void linearRecur(int n) { + print('递归 n = $n'); + if (n == 1) return; + linearRecur(n - 1); +} + +/* 平方阶 */ +void quadratic(int n) { + // 矩阵占用 O(n^2) 空间 + List> numMatrix = List.generate(n, (_) => List.filled(n, 0)); + // 二维列表占用 O(n^2) 空间 + List> numList = []; + + for (var i = 0; i < n; i++) { + List tmp = []; + for (int j = 0; j < n; j++) { + tmp.add(0); + } + numList.add(tmp); + } +} + +/* 平方阶(递归实现) */ +int quadraticRecur(int n) { + if (n <= 0) return 0; + List nums = List.filled(n, 0); + print('递归 n = $n 中的长度 nums 长度 = ${nums.length}'); + return quadraticRecur(n - 1); +} + +/* 指数阶(建立满二叉树) */ +TreeNode? buildTree(int n) { + if (n == 0) return null; + TreeNode root = TreeNode(n); + root.left = buildTree(n - 1); + root.right = buildTree(n - 1); + return root; +} + +/* Driver Code */ +int main() { + int n = 5; + // 常数阶 + constant(n); + // 线性阶 + linear(n); + linearRecur(n); + // 平方阶 + quadratic(n); + quadraticRecur(n); + // 指数阶 + TreeNode? root = buildTree(n); + printTree(root); + return 0; +} diff --git a/codes/dart/chapter_computational_complexity/time_complexity.dart b/codes/dart/chapter_computational_complexity/time_complexity.dart new file mode 100644 index 000000000..b0cddf89b --- /dev/null +++ b/codes/dart/chapter_computational_complexity/time_complexity.dart @@ -0,0 +1,163 @@ +/** + * File: time_complexity + * Created Time: 2023-02-12 + * Author: Jefferson (JeffersonHuang77@gmail.com) + */ + +/* 常数阶 */ +int constant(int n) { + int count = 0; + int size = 100000; + for (var i = 0; i < size; i++) { + count++; + } + return count; +} + +/* 线性阶 */ +int linear(int n) { + int count = 0; + for (var i = 0; i < n; i++) { + count++; + } + return count; +} + +/* 线性阶(遍历数组) */ +int arrayTraversal(List nums) { + int count = 0; + // 循环次数与数组长度成正比 + for (var num in nums) { + count++; + } + return count; +} + +/* 平方阶 */ +int quadratic(int n) { + int count = 0; + // 循环次数与数组长度成平方关系 + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + count++; + } + } + return count; +} + +/* 平方阶(冒泡排序) */ +int bubbleSort(List nums) { + int count = 0; // 计数器 + // 外循环:待排序元素数量为 n-1, n-2, ..., 1 + for (var i = nums.length - 1; i > 0; i--) { + // 内循环:冒泡操作 + for (var j = 0; j < i; j++) { + if (nums[j] > nums[j + 1]) { + // 交换 nums[j] 与 nums[j + 1] + int tmp = nums[j]; + nums[j] = nums[j + 1]; + nums[j + 1] = tmp; + count += 3; // 元素交换包含 3 个单元操作 + } + } + } + return count; +} + +/* 指数阶(循环实现) */ +int exponential(int n) { + int count = 0, base = 1; + // cell 每轮一分为二,形成数列 1, 2, 4, 8, ..., 2^(n-1) + for (var i = 0; i < n; i++) { + for (var j = 0; j < base; j++) { + count++; + } + base *= 2; + } + // count = 1 + 2 + 4 + 8 + .. + 2^(n-1) = 2^n - 1 + return count; +} + +/* 指数阶(递归实现) */ +int expRecur(int n) { + if (n == 1) return 1; + return expRecur(n - 1) + expRecur(n - 1) + 1; +} + +/* 对数阶(循环实现) */ +int logarithmic(num n) { + int count = 0; + while (n > 1) { + n = n / 2; + count++; + } + return count; +} + +/* 对数阶(递归实现) */ +int logRecur(num n) { + if (n <= 1) return 0; + return logRecur(n / 2) + 1; +} + +/* 线性对数阶 */ +int linearLogRecur(num n) { + if (n <= 1) return 1; + int count = linearLogRecur(n / 2) + linearLogRecur(n / 2); + for (var i = 0; i < n; i++) { + count++; + } + return count; +} + +/* 阶乘阶(递归实现) */ +int factorialRecur(int n) { + if (n == 0) return 1; + int count = 0; + // 从 1 个分裂出 n 个 + for (var i = 0; i < n; i++) { + count += factorialRecur(n - 1); + } + return count; +} + +int main() { + // 可以修改 n 运行,体会一下各种复杂度的操作数量变化趋势 + int n = 8; + print('输入数据大小 n = $n'); + + int count = constant(n); + print('常数阶的计算操作数量 = $count'); + + count = linear(n); + print('线性阶的计算操作数量 = $count'); + + count = arrayTraversal(List.filled(n, 0)); + print('线性阶(遍历数组)的计算操作数量 = $count'); + + count = quadratic(n); + print('平方阶的计算操作数量 = $count'); + final nums = List.filled(n, 0); + for (int i = 0; i < n; i++) { + nums[i] = n - i; // [n,n-1,...,2,1] + } + count = bubbleSort(nums); + print('平方阶(冒泡排序)的计算操作数量 = $count'); + + count = exponential(n); + print('指数阶(循环实现)的计算操作数量 = $count'); + count = expRecur(n); + print('指数阶(递归实现)的计算操作数量 = $count'); + + count = logarithmic(n); + print('对数阶(循环实现)的计算操作数量 = $count'); + count = logRecur(n); + print('对数阶(递归实现)的计算操作数量 = $count'); + + count = linearLogRecur(n); + print('线性对数阶(递归实现)的计算操作数量 = $count'); + + count = factorialRecur(n); + print('阶乘阶(递归实现)的计算操作数量 = $count'); + return 0; +} diff --git a/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart b/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart new file mode 100644 index 000000000..b746dbf81 --- /dev/null +++ b/codes/dart/chapter_computational_complexity/worst_best_time_complexity.dart @@ -0,0 +1,39 @@ +/** + * File: worst_best_time_complexity + * Created Time: 2023-02-12 + * Author: Jefferson (JeffersonHuang77@gmail.com) + */ + +/* 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 */ +List randomNumbers(int n) { + final nums = List.filled(n, 0); + // 生成数组 nums = { 1, 2, 3, ..., n } + for (var i = 0; i < n; i++) { + nums[i] = i + 1; + } + // 随机打乱数组元素 + nums.shuffle(); + + return nums; +} + +/* 查找数组 nums 中数字 1 所在索引 */ +int findOne(List nums) { + for (var i = 0; i < nums.length; i++) { + // 当元素 1 在数组头部时,达到最佳时间复杂度 O(1) + // 当元素 1 在数组尾部时,达到最差时间复杂度 O(n) + if (nums[i] == 1) return i; + } + return -1; +} + +int main() { + for (var i = 0; i < 10; i++) { + int n = 100; + final nums = randomNumbers(n); + int index = findOne(nums); + print('\n数组 [ 1, 2, ..., n ] 被打乱后 = $nums'); + print('数字 1 的索引为 + $index'); + } + return 0; +} diff --git a/codes/dart/utils/PrintUtil.dart b/codes/dart/utils/PrintUtil.dart deleted file mode 100644 index f3dd05ec6..000000000 --- a/codes/dart/utils/PrintUtil.dart +++ /dev/null @@ -1,21 +0,0 @@ -/** - * File: PrintUtil - * Created Time: 2023-01-23 - * Author: Jefferson (JeffersonHuang77@gmail.com) - */ - -import 'ListNode.dart'; - -class PrintUtil { - - void printLinkedList(ListNode? head) { - List list = []; - - while (head != null) { - list.add('${head.val}'); - head = head.next; - } - - print(list.join(' -> ')); - } -} diff --git a/codes/dart/utils/ListNode.dart b/codes/dart/utils/list_node.dart similarity index 100% rename from codes/dart/utils/ListNode.dart rename to codes/dart/utils/list_node.dart diff --git a/codes/dart/utils/print_util.dart b/codes/dart/utils/print_util.dart new file mode 100644 index 000000000..499a53b9c --- /dev/null +++ b/codes/dart/utils/print_util.dart @@ -0,0 +1,72 @@ +/** + * File: PrintUtil + * Created Time: 2023-01-23 + * Author: Jefferson (JeffersonHuang77@gmail.com) + */ +import 'dart:io'; + +import 'list_node.dart'; +import 'tree_node.dart'; + +class Trunk { + Trunk? prev; + String str; + + Trunk(this.prev, this.str); +} + +void printLinkedList(ListNode? head) { + List list = []; + + while (head != null) { + list.add('${head.val}'); + head = head.next; + } + + print(list.join(' -> ')); +} +/* + * Print a binary tree + * @param root + * @param prev + * @param isLeft + */ + +void printTree(TreeNode? root, [Trunk? prev = null, bool isLeft = false]) { + if (root == null) { + return; + } + + String prev_str = ' '; + Trunk trunk = Trunk(prev, prev_str); + + printTree(root.right, trunk, true); + + if (prev == null) { + trunk.str = '---'; + } else if (isLeft) { + trunk.str = '/---'; + prev_str = ' |'; + } else { + trunk.str = '\\---'; + prev.str = prev_str; + } + showTrunks(trunk); + print(' ${root.val}'); + + if (prev != null) { + prev.str = prev_str; + } + trunk.str = ' |'; + + printTree(root.left, trunk, false); +} + +void showTrunks(Trunk? p) { + if (p == null) { + return; + } + + showTrunks(p.prev); + stdout.write(p.str); +} diff --git a/codes/dart/utils/tree_node.dart b/codes/dart/utils/tree_node.dart new file mode 100644 index 000000000..d7d13b88a --- /dev/null +++ b/codes/dart/utils/tree_node.dart @@ -0,0 +1,69 @@ +/** + * File: tree_node.dart + * Created Time: 2023-2-12 + * Author: Jefferson (JeffersonHuang77@gmail.com) + */ + +import 'dart:collection'; + +class TreeNode { + late int val; // 结点值 + late int height; // 结点高度 + late TreeNode? left; // 左子结点引用 + late TreeNode? right; // 右子结点引用 + + TreeNode(int x) { + val = x; + } +} + +/** + * Generate a binary tree given an array + * @param list + * @return + */ +TreeNode? listToTree(List list) { + int size = list.length; + if (size == 0) return null; + + TreeNode root = TreeNode(list[0]); + Queue queue = Queue(); + queue.add(root); + int i = 0; + while (!queue.isEmpty) { + TreeNode? node = queue.first; + queue.removeFirst(); + if (++i >= size) break; + node?.left = TreeNode(list[i]); + queue.add(node?.left); + if (++i >= size) break; + node?.left = TreeNode(list[i]); + queue.add(node?.right); + } + return root; +} + +/** + * Serialize a binary tree to a list + * @param root + * @return + */ +List treeToList(TreeNode? root) { + List list = []; + if (root == null) return list; + Queue queue = Queue(); + queue.add(root); + + while (!queue.isEmpty) { + TreeNode? node = queue.first; + queue.removeFirst(); + if (node != null) { + list.add(node.val); + queue.add(node.left); + queue.add(node.right); + } else { + list.add(null); + } + } + return list; +}