diff --git a/codes/dart/chapter_searching/binary_search_edge.dart b/codes/dart/chapter_searching/binary_search_edge.dart new file mode 100644 index 000000000..c98912e07 --- /dev/null +++ b/codes/dart/chapter_searching/binary_search_edge.dart @@ -0,0 +1,48 @@ +/** + * File: binary_search_edge.dart + * Created Time: 2023-08-14 + * Author: liuyuxin (gvenusleo@gmail.com) + */ + +import 'binary_search_insertion.dart'; + +/* 二分查找最左一个 target */ +int binarySearchLeftEdge(List nums, int target) { + // 等价于查找 target 的插入点 + int i = binarySearchInsertion(nums, target); + // 未找到 target ,返回 -1 + if (i == nums.length || nums[i] != target) { + return -1; + } + // 找到 target ,返回索引 i + return i; +} + +/* 二分查找最右一个 target */ +int binarySearchRightEdge(List nums, int target) { + // 转化为查找最左一个 target + 1 + int i = binarySearchInsertion(nums, target + 1); + // j 指向最右一个 target ,i 指向首个大于 target 的元素 + int j = i - 1; + // 未找到 target ,返回 -1 + if (j == -1 || nums[j] != target) { + return -1; + } + // 找到 target ,返回索引 j + return j; +} + +/* Driver Code */ +void main() { + // 包含重复元素的数组 + List nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; + print("\n数组 nums = $nums"); + + // 二分查找左边界和右边界 + for (int target in [6, 7]) { + int index = binarySearchLeftEdge(nums, target); + print("最左一个元素 $target 的索引为 $index"); + index = binarySearchRightEdge(nums, target); + print("最右一个元素 $target 的索引为 $index"); + } +} diff --git a/codes/dart/chapter_searching/binary_search_insertion.dart b/codes/dart/chapter_searching/binary_search_insertion.dart new file mode 100644 index 000000000..141c80b62 --- /dev/null +++ b/codes/dart/chapter_searching/binary_search_insertion.dart @@ -0,0 +1,60 @@ +/** + * File: binary_search_insertion.dart + * Created Time: 2023-08-14 + * Author: liuyuxin (gvenusleo@gmail.com) + */ + +/* 二分查找插入点(无重复元素) */ +int binarySearchInsertionSimple(List nums, int target) { + int i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] + while (i <= j) { + int m = i + (j - i) ~/ 2; // 计算中点索引 m + if (nums[m] < target) { + i = m + 1; // target 在区间 [m+1, j] 中 + } else if (nums[m] > target) { + j = m - 1; // target 在区间 [i, m-1] 中 + } else { + return m; // 找到 target ,返回插入点 m + } + } + // 未找到 target ,返回插入点 i + return i; +} + +/* 二分查找插入点(存在重复元素) */ +int binarySearchInsertion(List nums, int target) { + int i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1] + while (i <= j) { + int m = i + (j - i) ~/ 2; // 计算中点索引 m + if (nums[m] < target) { + i = m + 1; // target 在区间 [m+1, j] 中 + } else if (nums[m] > target) { + j = m - 1; // target 在区间 [i, m-1] 中 + } else { + j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中 + } + } + // 返回插入点 i + return i; +} + +/* Driver Code */ +void main() { + // 无重复元素的数组 + List nums = [1, 3, 6, 8, 12, 15, 23, 26, 31, 35]; + print("\n数组 nums = $nums"); + // 二分查找插入点 + for (int target in [6, 9]) { + int index = binarySearchInsertionSimple(nums, target); + print("元素 $target 的插入点的索引为 $index"); + } + + // 包含重复元素的数组 + nums = [1, 3, 6, 6, 6, 6, 6, 10, 12, 15]; + print("\n数组 nums = $nums"); + // 二分查找插入点 + for (int target in [2, 6, 20]) { + int index = binarySearchInsertion(nums, target); + print("元素 $target 的插入点的索引为 $index"); + } +}