算法系列之原地算法(in-place algorithm)

博客介绍了原地算法,指基本无需额外辅助数据结构,允许少量辅助变量转换数据,运行时输入数据常被输出部分覆盖,在计算复杂性理论中属O(1)空间复杂度算法。还给出LeetCode题目,要求在原地删除排序数组重复元素并返回新长度,给出参考代码及思路解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、原地算法简介

    在计算机科学中,一个原地算法(in-place algorithm)基本上不需要额外辅助的数据结构,然而,允许少量额外的辅助变量来转换数据的算法。当算法运行时,输入的数据通常会被要输出的部分覆盖掉。不是原地算法有时候称为非原地(not-in-place)或不得其所(out-of-place)。–摘自维基百科。
    在计算复杂性理论中,原地算法包含使用O(1)空间复杂度的所有算法,DSPACE(1)类型。

二、例子

题目描述

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:

给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。

示例2:

给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。

参考代码1:

public int removeDuplicates(int[] nums) {

        int i = 0;
        for (int n : nums)
            if (i == 0 || n > nums[i - 1])
                nums[i++] = n;
        return i;
    }

思路解析:(以示例2为例)
在这里插入图片描述

i=0:仅限第一个元素。
因为升序排序,当nums[i]开始重复时,i++进行;直到n>nums[i-1]出现时,把nums[i++] = n进行赋值。当nums[i++] = n执行完了,去重的工作也就结束了。

参考代码2:

public int removeDuplicates(int[] nums) {

        if (nums == null || nums.length == 0) {
            return 0;
        }
        int pos = 0, count = 1;
        for (int i = 0; i < nums.length; i++) {
            if (nums[pos] == nums[i]) {
                nums[pos] = nums[i];
            } else {
                pos++;
                nums[pos] = nums[i];
                count++;
            }
        }
        return count;

    }

代码1代码2的简化版。

<think>好的,我现在需要回答用户关于C++中原地算法的概念及实现示例的问题。首先,我得先明确什么是原地算法原地算法,也称为in-place算法,指的是不需要额外的存储空间或仅使用常数级别的额外空间来转换数据的算法。这意味着算法在运行时主要利用输入数据本身的空间,减少内存使用,尤其在处理大数据时很重要。 接下来,我要确认用户的需求,他们可能希望了解原地算法的定义、特点,以及具体的C++实现例子。因此,我需要准备一个清晰的解释和一个或多个代码示例。比如,常见的原地算法有快速排序、堆排序、反转数组等。选择反转数组作为例子可能比较简单易懂,适合作为示例。 然后,我需要确保代码的正确性。比如,反转数组可以通过双指针法实现,一个指针从头开始,另一个从尾开始,逐步交换元素直到中间位置。这样只需要常数级别的额外空间(用于临时交换变量),符合原地算法的定义。 同时,我需要考虑用户可能的后续问题,比如原地算法的优缺点,应用场景,或者与其他算法的比较。比如,归并排序通常不是原地算法,因为它需要额外的空间来合并数组,而快速排序是原地的,因为它在原地进行分区操作。 在引用资料时,用户提供的引用中提到了归并排序[^1],A*算法[^2],以及插入排序[^3]。虽然这些引用中没有直接提到原地算法,但可以指出插入排序是原地的一个例子,因为它通过移动元素在数组内部排序,不需要额外空间。不过用户提供的引用[3]提到插入排序是简单排序算法,所以可以引用这一点来支持原地算法的例子。 最后,我需要确保回答结构清晰,分点解释概念、特点、示例,并提供代码。同时,生成的相关问题要引导用户进一步了解相关内容,比如优缺点、应用场景,或者与其他排序算法的比较。</think>### C++ 原地算法概念与实现示例 #### 1. 原地算法定义 **原地算法**(In-place Algorithm)指在运行时**仅使用常数级别额外存储空间**($O(1)$ 空间复杂度)对输入数据进行操作的算法。这类算法直接修改输入数据本身,避免创建新副本,特别适用于内存受限的场景[^3]。 #### 2. 核心特点 - **空间高效**:无需额外数组或数据结构 - **直接修改输入**:原数据可能被覆盖或重新排列 - **适用场景**:大数据处理、嵌入式系统等 #### 3. 实现示例:数组原地反转 **功能描述**:将数组元素顺序翻转,仅用$O(1)$额外空间。 ```cpp #include <iostream> using namespace std; void reverseArray(int arr[], int size) { int start = 0; int end = size - 1; while (start < end) { // 使用临时变量交换元素 int temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; start++; end--; } } int main() { int arr[] = {1, 2, 3, 4, 5}; int n = sizeof(arr)/sizeof(arr[0]); reverseArray(arr, n); for(int i=0; i<n; i++) cout << arr[i] << " "; // 输出:5 4 3 2 1 return 0; } ``` #### 4. 其他原地算法示例 1. **快速排序**:通过基准值分区实现原地排序 2. **堆排序**:利用堆结构原地构建有序序列 3. **插入排序**:通过元素移动实现原地排序(引用[3]提到的排序方法) #### 5. 与非原地算法对比 | 算法类型 | 空间复杂度 | 数据修改方式 | 典型示例 | |----------|------------|--------------------|----------------| | 原地算法 | $O(1)$ | 直接修改原数据 | 快速排序 | | 非原地 | $O(n)$ | 创建新数据结构存储 | 归并排序 |
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值