1. 快速排序中的 partition 算法
public int partition(int[] arr, int low, int high){
int i = low;
int j = high;
int piovt = arr[low];
//向左扫描
while(i < j){
while(i < j && arr[j] > piovt) j--;
if(i < j) swap(arr, i++, j);
//向右扫描
while(i < j && arr[i] <= piovt) i++;
if(i < j) swap(arr, i, j--);
}
return i;
}
2. 桶排序
- 每一个桶代表一个区间的范围,里面可以承载一个或多个元素。
- 桶排序的第一步,就是创建这些桶,确定每一个桶的区间范围:
具体建立多少个桶,如何确定桶的区间范围,有很多不同的方式。我们这里创建的桶数量等于原始数列的元素数量,除了最后一个桶只包含数列最大值,前面各个桶的区间按照比例确定。
区间跨度 = (最大值-最小值)/ (桶的数量 - 1) - 第二步,遍历原始数列,把元素对号入座放入各个桶中
- 第三步,每个桶内部的元素分别排序(显然,只有第一个桶需要排序)
- 第四步,遍历所有的桶,输出所有元素:
0.5,0.84,2.18,3.25,4.5到此为止,排序结束。
3. 二分查找法
- 二分查找框架:
int binarySearch(int[] nums, int target) {
int left = 0;
int right = ...;
while(...) {
int mid = (right + left) / 2;
if (nums[mid] == target) {
...
} else if (nums[mid] < target) {
left = ...
} else if (nums[mid] > target) {
right = ...
}
}
return ...;
}
作者:labuladong
链接:https://leetcode-cn.com/problems/two-sum/solution/er-fen-cha-zhao-xiang-jie-by-labuladong/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 寻找一个数(基本的二分搜索)
/*
* 基本二分搜索
* 寻找一个数
* */
public class BinarySearch {
public int binarySearch(int[] nums, int target){
int l = 0;
int r = nums.length - 1;
while(l <= r){
int m = (l + r) >> 1;
if(nums[m] == target)
return m;
else if(nums[m] < target)
l = m + 1;
else if(nums[m] > target)
r = m - 1;
}
return -1;
}
}
(1)为什么 while 循环条件是 <= 而不是 < ?
答:我们这个算法中使用的是前者 [left, right] 两端都闭的区间。这个区间其实就是每次进行搜索的区间,我们不妨称为「搜索区间」。
什么时候应该停止搜索呢?当然,找到了目标值的时候可以终止:
if(nums[mid] == target)
return mid;
但如果没找到,就需要 while 循环终止,然后返回 -1。那 while 循环什么时候应该终止?搜索区间为空的时候应该终止,意味着你没得找了,就等于没找到嘛。
while(left <= right) 的终止条件是 left == right + 1,写成区间的形式就是 [right + 1, right],或者带个具体的数字进去 [3, 2],可见这时候搜索区间为空,因为没有数字既大于等于 33 又小于等于 22 的吧。所以这时候 while 循环终止是正确的,直接返回 -1即可。
while(left < right) 的终止条件是 left == right,写成区间的形式就是 [left, right],或者带个具体的数字进去 [2, 2],这时候搜索区间非空,还有一个数 2,但此时 while 循环终止了。也就是说这区间 [2, 2] 被漏掉了,索引 2 没有被搜索,如果这时候直接返回 -1−1 就是错误的。
(2) 为什么 left = mid + 1,right = mid - 1?我看有的代码是 right = mid 或者 left = mid,没有这些加加减减,到底怎么回事,怎么判断?
刚才明确了「搜索区间」这个概念,而且本算法的搜索区间是两端都闭的,即 [left, right]。那么当我们发现索引 mid 不是要找的 target 时,如何确定下一步的搜索区间呢?
当然是 [left, mid - 1] 或者 [mid + 1, right] 对不对?因为 mid 已经搜索过,应该从搜索区间中去除。
4. DFS(图的深度优先遍历)
/*
M:表示图的边集
i:表示从结点i开始深度优先遍历
hasVisited:用来标记某个结点是否访问过
*/
public void dfs(int[][] M, int i, boolean[] hasVisited){
hasVisited[i] = true;
for(int k = 0; k < n; k++){
//如果i和k之间有联系,并且k没有被访问过,则从k开始向下访问
if(M[i][k] == 1 && !hasVisited[k]){
dfs(M, k, hasVisited);
}
}
}
5. 二叉树的中序遍历【递归】
import java.util.ArrayList;
import java.util.List;
public class Main {
public static List<Integer> inorderTrversal(TreeNode root){
List<Integer> res = new ArrayList<>();
helper(root, res);
return res;
}
//二叉树的中序遍历
private static void helper(TreeNode root, List<Integer> res){
if(root != null){
if(root.left != null){
helper(root.left, res);
}
res.add(root.val);
if(root.right != null){
helper(root.right, res);
}
}
}
static class TreeNode{
int val;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val){
this.val = val;
}
}
}
6. 二叉树的中序遍历【非递归】
public class Main2 {
/*
* 思路:
* 1.从整棵二叉树的根结点开始,对于任一结点V,判断其左子结点L是否为空。
* 2.若L不为空,则将V入栈并将L置为当前结点V;
* 3.若L为空,则取出栈顶结点并访问该栈顶结点,然后将其右子结点置为当前结点V。
* 4.重复上述操作,直到当前结点V为空结点且栈为空,遍历结束。
* */
public static List<Integer> inorderTraversal(TreeNode root){
List<TreeNode> treeNodeStack = new Stack<>();
ArrayList<Integer> list = new ArrayList<>();
TreeNode node = root;
while (node != null || !treeNodeStack.isEmpty()){
//如果node不等于null,将node入栈,node指向node的左结点
while (node != null){
treeNodeStack.add(node);
node = node.left;
}
if(!treeNodeStack.isEmpty()){
node = ((Stack<TreeNode>) treeNodeStack).pop();
list.add(node.val);
node = node.right;
}
}
return null;
}
static class TreeNode{
int val;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val){
this.val = val;
}
}
}