原地算法

百度的解释:

       在计算机科学中,一个原地算法(in-place algorithm)是一种使用小的,固定数量的额外之空间来转换资料的算法。当算法执行时,输入的资料通常会被要输出的部份覆盖掉。不是原地算法有时候称为非原地(not-in-place)或不得其所(out-of-place)。

简单来说,就是在不新建大量额外空间(就是固定空间,无论数据多大,都不改变的那种)的基础上对原数据进行操作。

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

 

示例 1:

输入:["h","e","l","l","o"]
输出:["o","l","l","e","h"]

示例 2:

输入:["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]

    public void reverseString(char[] s) {
        int len = s.length;
        for(int i =0;i<len/2;i++)
        {
            char temp = s[len-i-1];
            s[len-i-1] = s[i];
            s[i] = temp;
        }
        
    }

也就名字高大上点。

******************************************************************************************************************************

给定一组字符,使用原地算法将其压缩。

压缩后的长度必须始终小于或等于原数组长度。

数组的每个元素应该是长度为1 的字符(不是 int 整数类型)。

在完成原地修改输入数组后,返回数组的新长度。

 

进阶:
你能否仅使用O(1) 空间解决问题?

class Solution {
    public int compress(char[] chars) {
        int cur = 0,write = 0;//cur保留指针,write写指针
        for(int read = 0;read < chars.length;read++){
            //当读到最后一个字符,或者下一个字符与当前不同时,则到达连续区块的结尾。
            if(read+1==chars.length||chars[read]!=chars[read+1]){//顺序不能颠倒,否则数组越界
                chars[write++] = chars[cur];//将字符写入
                if(read>cur){//如果长度大于一,写入个数
                    for(char c :(""+(read-cur+1)).toCharArray()){
                        chars[write++] = c;
                    }
                }
                cur = read+1; //cur重新定位
            }
        }
        return write;
    }
}
保留指针 cur,指向当前读到连续字符串的起始位置。

从左到右进行读取。当读到最后一个字符,或者下一个下一个字符与当前不同时,则到达连续区块的结尾。

当我们到达连续区块的结尾时,就从 write 写入压缩的结果。chars[cur] 为字符,read - cur+ 1 (若大于 1)为长度。

复杂度分析

    时间复杂度:O(N),其中 N 是 chars 的长度。

    空间复杂度:O(1),三个指针的占用空间。

经典

### 关于线性枚举的原地算法 #### 定义与特点 线性枚举是一种简单而高效的遍历方式,通常用于访问数组中的每一个元素。当提到“原地算法”时,意味着该算法不需要额外的空间来存储中间结果,仅利用输入数据本身的内存空间完成计算[^1]。 #### 示例:移除数组中的重复项(O(n) 时间复杂度) 下面是一个经典的例子——移除非零元素并将其移到数组前端,同时保持其他元素顺序不变。此问题可以通过双指针技术在线性时间内解决,并满足原地修改的要求: ```cpp class Solution { public: void moveZeroes(vector<int>& nums) { int dest = 0; // 非零元素的目标位置 for (int cur = 0; cur < nums.size(); ++cur) { // 当前扫描的位置 if (nums[cur] != 0) { swap(nums[dest], nums[cur]); // 如果当前元素不为零,则交换到目标位置 dest++; // 更新目标位置 } } } }; ``` 上述代码展示了如何通过两个索引来实现这一功能,`dest`表示非零元素应放置的位置,而`cur`则负责逐一检查数组中的每个元素[^5]。 #### 示例:判断快乐数 另一个有趣的例子是检测一个整数是否为“快乐数”。这个问题也可以在一个循环中高效地解决,其核心在于使用慢快指针法避免无限循环的发生。以下是具体实现: ```cpp class Solution { public: int bitSum(int n) { int sum = 0; while (n) { int x = n % 10; sum += x * x; n /= 10; } return sum; } bool isHappy(int n) { int slow = n, fast = bitSum(n); while (slow != fast) { slow = bitSum(slow); fast = bitSum(bitSum(fast)); } return slow == 1; } }; ``` 这里采用了类似于链表查找环的技术,在每次迭代过程中更新两个变量直到它们相遇或者找到固定点 `1` [^3]。 #### 矩阵旋转问题 对于矩阵顺时针方向90°旋转的问题,如果希望达到 O(1) 的辅助空间需求,则需深入分析单次变换规律。一种常见做法是从外层向内逐圈处理每一层的数据置换关系[^4]。 ```python def rotate(matrix): n = len(matrix) for i in range(n // 2): for j in range(i, n - i - 1): temp = matrix[i][j] matrix[i][j] = matrix[n-j-1][i] matrix[n-j-1][i] = matrix[n-i-1][n-j-1] matrix[n-i-1][n-j-1] = matrix[j][n-i-1] matrix[j][n-i-1] = temp ``` 以上 Python 版本实现了基于四角互换原则的一次性就地转换方案。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值