需要牢记的几个算法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_32682177/article/details/98595690

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. 每一个桶代表一个区间的范围,里面可以承载一个或多个元素。
  2. 桶排序的第一步,就是创建这些桶,确定每一个桶的区间范围:
    具体建立多少个桶,如何确定桶的区间范围,有很多不同的方式。我们这里创建的桶数量等于原始数列的元素数量,除了最后一个桶只包含数列最大值,前面各个桶的区间按照比例确定。
    区间跨度 = (最大值-最小值)/ (桶的数量 - 1)
  3. 第二步,遍历原始数列,把元素对号入座放入各个桶中
  4. 第三步,每个桶内部的元素分别排序(显然,只有第一个桶需要排序)
  5. 第四步,遍历所有的桶,输出所有元素:
    0.5,0.84,2.18,3.25,4.5到此为止,排序结束。

3. 二分查找法

  1. 二分查找框架:
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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  1. 寻找一个数(基本的二分搜索)
/*
* 基本二分搜索
* 寻找一个数
* */
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;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_32682177/article/details/98595690