算法时间复杂度和空间复杂度

时间复杂度和空间复杂度分析

时间复杂度

时间复杂度衡量的是算法执行所需时间随着输入规模(n)变化的增长速度。通常我们通过分析算法的执行步骤来确定时间复杂度。

常见时间复杂度:
  • 常数时间 O(1):不随输入规模的增大而变化。
  • 线性时间 O(n):与输入规模成正比。
  • 对数时间 O(log n):例如二分查找。
  • 平方时间 O(n^2):例如冒泡排序。
  • 立方时间 O(n^3):例如一些动态规划算法。
  • 指数时间 O(2^n):例如某些递归算法,可能会导致暴力求解。
分析步骤:
  • 基本操作:确定在算法中每一步基本操作的执行次数。
  • 循环 :分析循环结构(for, while等)。如果一个循环执行n次,那么它的时间复杂度是O(n)。如果有嵌套循环,比如一个for循环里面还有一个for循环,每个循环执行n次,那么时间复杂度就是O(n^2)
  • 递归 :递归算法的时间复杂度可以通过递推公式来计算,常用的计算方法有递推树和主定理。例如,快速排序的时间复杂度通常是O(n log n),而归并排序也是O(n log n)

空间复杂度

空间复杂度衡量的是算法在执行过程中所需的额外空间(除去输入数据占用的空间)。它通常与算法使用的辅助空间(例如数组、哈希表、栈等)有关。

常见空间复杂度:
  • 常数空间 O(1):算法只需要使用常量大小的空间
  • 线性空间 O(n):算法使用的空间与输入数据的大小成正比
  • 对数空间 O(log n):比如在递归算法中,递归深度为log n
分析步骤:
  • 输入空间:输入的大小本身会占用空间,因此有时会被忽略,特别是在考虑空间复杂度时。
  • 变量和数据结构 :查看算法中使用的所有额外数据结构。比如一个数组或链表大小为n,那么它占用的空间是O(n)
  • 递归 :递归调用通常会增加函数调用栈的空间,因此递归的空间复杂度有时会比非递归的算法更高。
    • 比如递归树的深度是n时,空间复杂度可能是O(n)

实例分析

示例 1:线性查找

java 复制代码
public class LinearSearch {
    public static int linearSearch(int[] arr, int target) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == target) {
                return i;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9};
        int target = 5;
        System.out.println(linearSearch(arr, target));  // 输出:2
    }
}
时间复杂度:
  • 时间复杂度分析
    线性查找需要遍历整个数组,最坏情况下要遍历 n 次,因此时间复杂度是 O(n)
空间复杂度:
  • 空间复杂度分析
    只使用了常数空间 itarget,因此空间复杂度是 O(1)

示例 2:二分查找

java 复制代码
public class BinarySearch {
    public static int binarySearch(int[] arr, int target) {
        int left = 0, right = arr.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9};
        int target = 5;
        System.out.println(binarySearch(arr, target));  // 输出:2
    }
}
时间复杂度:
  • 时间复杂度分析
    二分查找将问题规模每次减半,因此时间复杂度是 O(log n)
空间复杂度:
  • 空间复杂度分析
    只使用了常数空间 left, right, mid,因此空间复杂度是 O(1)

示例 3:冒泡排序

java 复制代码
public class BubbleSort {
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    // 交换位置
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] arr = {5, 2, 9, 1, 5, 6};
        bubbleSort(arr);
        for (int num : arr) {
            System.out.print(num + " ");  // 输出:1 2 5 5 6 9
        }
    }
}
时间复杂度:
  • 时间复杂度分析
    外层循环执行 n 次,内层循环执行 n-1, n-2, ..., 1 次,因此总时间复杂度是 O(n^2)
空间复杂度:
  • 空间复杂度分析
    只使用了常数空间 temp 来交换数组元素,因此空间复杂度是 O(1)

示例 4:快速排序

java 复制代码
public class QuickSort {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int pi = partition(arr, low, high);
            quickSort(arr, low, pi - 1);
            quickSort(arr, pi + 1, high);
        }
    }

    private static int partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int i = (low - 1);
        for (int j = low; j < high; j++) {
            if (arr[j] <= pivot) {
                i++;
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[high];
        arr[high] = temp;
        return i + 1;
    }

    public static void main(String[] args) {
        int[] arr = {10, 7, 8, 9, 1, 5};
        quickSort(arr, 0, arr.length - 1);
        for (int num : arr) {
            System.out.print(num + " ");  // 输出:1 5 7 8 9 10
        }
    }
}
时间复杂度:
  • 时间复杂度分析
    快速排序每次将数组分成两部分,平均情况下时间复杂度是 O(n log n)。最坏情况下(数组已经有序时)是 O(n^2)
空间复杂度:
  • 空间复杂度分析
    快速排序需要递归调用,因此空间复杂度与递归深度成正比,最坏情况下是 O(n),平均情况下是 O(log n)

示例 5:合并排序

java 复制代码
public class MergeSort {
    public static void mergeSort(int[] arr) {
        if (arr.length < 2) return;
        int mid = arr.length / 2;
        int[] left = new int[mid];
        int[] right = new int[arr.length - mid];

        System.arraycopy(arr, 0, left, 0, mid);
        System.arraycopy(arr, mid, right, 0, arr.length - mid);

        mergeSort(left);
        mergeSort(right);

        merge(arr, left, right);
    }

    private static void merge(int[] arr, int[] left, int[] right) {
        int i = 0, j = 0, k = 0;
        while (i < left.length && j < right.length) {
            if (left[i] <= right[j]) {
                arr[k++] = left[i++];
            } else {
                arr[k++] = right[j++];
            }
        }
        while (i < left.length) arr[k++] = left[i++];
        while (j < right.length) arr[k++] = right[j++];
    }

    public static void main(String[] args) {
        int[] arr = {12, 11, 13, 5, 6, 7};
        mergeSort(arr);
        for (int num : arr) {
            System.out.print(num + " ");  // 输出:5 6 7 11 12 13
        }
    }
}
时间复杂度:
  • 时间复杂度分析
    合并排序每次将数组分成两半,并进行合并,时间复杂度是 O(n log n)
空间复杂度:
  • 空间复杂度分析
    合并排序需要额外的数组存储 leftright,因此空间复杂度是 O(n)

示例 6:矩阵乘法

java 复制代码
public class MatrixMultiplication {
    public static int[][] matrixMultiply(int[][] A, int[][] B) {
        int n = A.length;
        int m = B[0].length;
        int p = A[0].length;
        int[][] result = new int[n][m];

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                for (int k = 0; k < p; k++) {
                    result[i][j] += A[i][k] * B[k][j];
                }
            }
        }
        return result;
    }

    public static void main(String[] args) {
        int[][] A = {{1, 2}, {3, 4}};
        int[][] B = {{5, 6}, {7, 8}};
        int[][] result = matrixMultiply(A, B);

        for (int[] row : result) {
            for (int val : row) {
                System.out.print(val + " ");  // 输出:19 22 43 50
            }
            System.out.println();
        }
    }
}
时间复杂度:
  • 时间复杂度分析
    矩阵乘法需要三重循环,时间复杂度是 O(n * m * p),如果矩阵是 n x n 的话,时间复杂度是 O(n^3)
空间复杂度:
  • 空间复杂度分析
    需要一个 n x m 的结果矩阵,因此空间复杂度是 O(n * m)

总结:

每个算法的时间复杂度和空间复杂度都依赖于其结构和操作方式,Java 示例中的复杂度分析与之前的解释是相同的。你可以根据这些示例来分析不同算法的性能特点。

相关推荐
HarmonLTS3 小时前
Python人工智能深度开发:技术体系、核心实践与工程化落地
开发语言·人工智能·python·算法
a程序小傲4 小时前
京东Java面试被问:RPC调用的熔断降级和自适应限流
java·开发语言·算法·面试·职场和发展·rpc·边缘计算
一分之二~4 小时前
二叉树--层序遍历(迭代和递归)
数据结构·c++·算法·leetcode
zl_vslam4 小时前
SLAM中的非线性优-3D图优化之绝对位姿SE3约束右扰动(十七)
人工智能·算法·计算机视觉·3d
Cestb0n4 小时前
某果app 加密校验算法逆向分析
python·算法·逆向安全
机器学习之心4 小时前
MATLAB基于近红外光谱检测的菠萝含水率预测(多种预处理+PLS)
人工智能·算法·matlab·近红外光谱检测
程序员-King.5 小时前
day166—递归—多边形三角剖分的最低得分(LeetCode-1039)
算法·leetcode·深度优先·动态规划·递归
夏鹏今天学习了吗5 小时前
【LeetCode热题100(94/100)】下一个排列
算法·leetcode·职场和发展
AI科技星5 小时前
光的几何起源:从螺旋时空到量子现象的完全统一
开发语言·人工智能·线性代数·算法·机器学习