常见基础算法

一、排序 & 查找算法

1.1 冒泡排序

  • 相邻的数据进行比较。每次遍历找到一个最大值。

  •     public void sort(int[] nums) {
          
          
            if (nums == null) {
          
          
                return;
            }
    
            for (int i = 0; i < nums.length; i++) {
          
          
                for (int j = 0; j < nums.length - 1 - i; j++) {
          
          
                    if (nums[j] > nums[j + 1]) {
          
          
                        int temp = nums[j];
                        nums[j] = nums[j + 1];
                        nums[j + 1] = temp;
                    }
                }
            }
        }
    

1.2 二分查找

1.3 快速排序

  • 快速排序有几种写法,左右双边指针交换法、单边指针交换法

1.3.1 左右双边指针交换法

  1. 创建左右两个指针。记录左指针数值为分界值,假设为key。
  2. 首先右指针从右向左找出比key小的数据坐标,同时保证左指针小于右指针。
  3. 然后左指针从左向右找出比key大的数据坐标,同时保证左指针小于右指针。
  4. 左右指针交换,进入下一次循环。
  5. 结束一次循环的条件,必然是左右指针相等。并且结束时指针指向的数值小于等于key。
  6. 结束一次循环后,将当前指针的数据与分界值互换。
  7. 然后把分界处左右两边的数据分别快速排序。(递归)

1.3.2 leetcode

1.4 桶排序

小结

在这里插入图片描述

二、双指针

三、单调栈

  • 将数字一次入栈,同时要求栈中的元素单调递增(也可递减),如果新入栈的数字 N 小于栈顶的数字,那么就依次出栈,直到数字N大于栈顶的元素。
  • 利用单调性质作为临界点,解决问题。
  • 503. 下一个更大元素 II
  • 739. 每日温度

四、滑动窗口

  • 用于求解满足特定条件的连续子数组问题

  • 滑动窗口无法解决存在负值的问题,存在负值的问题,可以考虑使用前缀和方法进行求解。

  • 1208. 尽可能使字符串相等 这个题目中,最长子串就是要满足的条件,同时也满足连续子数组的要求。

五、前缀和

六、DFS & BFS

  • 深度遍历适合存在性问题,广度遍历适合寻找最短路径问题。
  • 深度遍历有两种实现方式:递归 和 栈。广度遍历只能用队列进行实现。
  • 在进行遍历时,必须要记录已经访问过的节点,避免造成循环。
  • 在迷宫、网格、岛屿类问题遍历时,要考虑上下左右四个方向进行遍历。可以如下定义方向数组遍历四个方向:
private static final int[][] steps = {
    
    {
    
    1, 0}, {
    
    -1, 0}, {
    
    0, 1}, {
    
    0, -1}};

for (int[] step : steps) {
    
    
    Point next = new Point(point.x + step[0], point.y + step[1]);
    //省略...
}

6.1 深度遍历

/**
 * grid 二维数组表示网格
 * current 表示当前正在遍历的节点
 * visited 表示已经遍历的节点,是set类型
 */
privte void dfs(int[][] grid, Point current, Set<Point> visited) {
    
    
    visited.add(current);
    for (int[] step : steps) {
    
     // 向四周遍历
        Point next = new Point(current.x + step[0], current.y + step[1]);
        if (visited.contains(next)) {
    
    
            continue;
        }

        // 不超出边界
        if (next.x >= 0 && next.x < grid.length && next.y >= 0 && next.y < grid[0].length) {
    
    
            if (grid[next.x][next.y] == 1) {
    
    
                number += dfs(grid, next, visited);
            }
            visited.add(next);
        }
    }
}

6.2 广度遍历

七、回溯算法

  • 回溯算法是深度优先的一种衍生算法,是一种遍历算法。
  • 回溯算法可以用来求解排列问题,存在剪枝的情况

7.1 经典题型

   // 数组全排列问题,回溯代码求解
    public List<List<Integer>> permute(int[] nums) {
    
    
        List<Integer> list = new ArrayList<>();
        for (int i : nums) {
    
    
            list.add(i);
        }

        List<List<Integer>> res = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();
        backtrack(list, temp, res);
        return res;
    }

    /**
     * 回溯方法
     *
     * @param list 原始数组
     * @param temp 一种排列结果
     * @param res 全排列结果合集
     */
    private void backtrack(List<Integer> list, List<Integer> temp, List<List<Integer>> res) {
    
    
        if (list.isEmpty()) {
    
    
            res.add(new ArrayList<>(temp));
            return;
        }
        for (int i = 0; i < list.size(); i++) {
    
    
            temp.add(list.remove(i));
            backtrack(list, temp, res);
            list.add(i, temp.remove(temp.size() - 1));
        }
    }
    public List<List<Integer>> subsets(int[] nums) {
    
    
        List<Integer> list = new ArrayList<>();
        for (int i : nums) {
    
    
            list.add(i);
        }

        List<List<Integer>> result = new ArrayList<>();
        List<Integer> temp = new ArrayList<>();

        backtrack(list, result, temp, 0);
        return result;
    }

    private void backtrack(List<Integer> list, List<List<Integer>> result, List<Integer> tmp, int n) {
    
    
        result.add(new ArrayList<>(tmp));
        for (int i = n; i < list.size(); i++) {
    
    
            tmp.add(list.get(i));
            backTree(list, result, tmp, i +1);
            tmp.remove(tmp.size() - 1);
        }
    }

八、动态规划

  • 关键是寻找:状态转移方程 和 边界条件,然后使用递归。
  • 因为递归可能会出现重复求解的情况,所以应该记录已经求解的问题,避免重复运算。
  • 空间优化。因为在计算F(n)的时候,往往只需要F(n - 1) 和 F(n - 2)的值,所以在计算时可以只保留这两个数值,优化空间复杂度。

8.1 leetcode

九、贪心算法

十、回文子串(马拉车算法)

  • 回文子串分为奇对称和偶对称。通过插入特殊字符,使得字符串变为偶对称。
  • 利用回文子串的对称性提高遍历效率。遍历时,已知最长的回文子串的右侧字符可以直接利用左侧中心对称位置字符的遍历结果。
  • #5 最长回文子串

十一、 位运算

猜你喜欢

转载自blog.csdn.net/followYouself/article/details/130676241