1047.删除字符串中的所有相邻重复项(Remove All Adjacent Duplicates In String) | LeetCode 第 1047 题

本文介绍了一种算法,用于删除字符串中的所有相邻重复项,直至无法继续删除,确保最终字符串的唯一性。通过示例和JAVA代码实现,展示了如何在字符串处理中应用这一技巧。

删除字符串中的所有相邻重复项

点击进入 LeetCode

给出由小写字母组成的字符串 S重复项删除操作会选择两个相邻且相同的字母,并删除它们。
S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例
输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"
提示
  1. 1 <= S.length <= 20000
  2. S 仅由小写英文字母组成。

解题思路

针对第 N(N > 1) 个字符的处理方式:

  • 如果 S[N] == S[N+1]
    1. S[N] 和 S[N+1] 为重复项,需要清除
    2. 判断 S[N+2] 是否等于 S[N-1] ,如果相等,重复项继续清除;如果不相等,则从第 N+2 个字符串,继续尽心判断
  • 如果 S[N] != S[N+1]
    • 从第 N+1个字符继续尽心判断

需要做好 N+2 和 N-1 是否越界的判断

题解 JAVA 实现

点击查看其他解题方法

public String removeDuplicates(String S) {

    if (S.length() <= 0) {
        return "";
    }

    Deque deque = new ArrayDeque<>();
    char[] charArray = S.toCharArray();
    deque.addLast(charArray[0]);

    for (int i = 1; i < charArray.length; i++) {
        if (!deque.isEmpty() && deque.peekLast().equals(charArray[i])) {
            deque.pollLast();
            continue;
        } else {
            deque.addLast(charArray[i]);
        }
    }

    StringBuilder result = new StringBuilder();
    while (!deque.isEmpty()) {
        result.append(deque.pollFirst());
    }

    return result.toString();
}
<think> 我们有一个需求:用C语言编写一个函数,删除数组中所有相邻重复的字符。 注意:目要求删除的是相邻重复字符。例如,输入数组 "abbaca",删除相邻重复后得到 "ca"(因为先删除"bb",得到"aaca",再删除"aa",得到"ca")。 思路: 我们可以使用一个类似于栈的方法,但这里为了简单,我们直接在原数组上进行操作。 使用两个指针:一个指针(例如`i`)遍历原始数组,另一个指针(例如`newLen`)指向当前不包含相邻重复的结果数组的末尾。 具体步骤: 1. 初始化`newLen = 0`(表示新数组的末尾位置,初始时没有元素)。 2. 遍历数组(从0到n-1): 如果`newLen`为0,说明结果数组为空,直接将当前字符加入(即`arr[newLen++] = arr[i]`)。 否则,比较当前遍历的字符`arr[i]`与结果数组的最后一个字符`arr[newLen-1]`: 如果相等,说明出现了相邻重复,那么我们需要回退(即`newLen--`,相当于把上一步添加的重复字符弹出)。 如果不相等,则将当前字符加入到结果数组中(`arr[newLen++] = arr[i]`)。 3. 最后,`newLen`就是新数组的长度,并且数组的前`newLen`个元素就是去除相邻重复后的结果。 注意:这个函数处理的是字符数组(字符串),所以我们需要在最后加上'\0'吗?但是目要求的是数组,而且目没有明确说明一定是字符串。不过根据引用[2]的上下文,应该是处理字符串的,所以我们假设输入是一个字符数组(字符串),并且我们在处理结束后需要添加字符串结束符。 但是目要求的是“删除数组中所有相邻重复字符的函数”,所以我们可以返回新的长度,并修改数组内容。 函数原型:`int remove_adjacent_duplicates(char arr[], int len)` 其中,`arr`是字符数组,`len`是数组长度(不包括字符串结束符,如果作为字符串使用,数组应该有足够的空间存放结束符)。 返回值:去除相邻重复后数组的长度。 例如:输入"abbaca",处理过程: i=0: arr[0]='a' -> 加入,newLen=1 -> ['a'] i=1: arr[1]='b' -> 与'a'不同,加入,newLen=2 -> ['a','b'] i=2: arr[2]='b' -> 与上一个('b')相同,所以回退(newLen=1) -> ['a'] i=3: arr[3]='a' -> 与上一个('a')相同,回退(newLen=0) -> [] i=4: arr[4]='c' -> 加入,newLen=1 -> ['c'] i=5: arr[5]='a' -> 加入,newLen=2 -> ['c','a'] 得到数组长度为2,内容为"ca"。 但是注意:上面的例子中,我们并没有处理字符串结束符。如果我们希望结果作为字符串使用,那么在函数最后应该加上结束符。 然而,目并没有明确说是字符串还是普通字符数组。不过,引用[2]是处理字符串的,所以我们按照字符串来设计,即函数执行后,结果数组是一个有效的字符串(以'\0'结尾)。 但是注意原数组可能并不是以'\0'结尾(因为目给的是数组,并且给了长度)。所以我们可以这样: 在函数内部,我们只处理长度为len的数组,然后我们在新长度的位置添加一个'\0',这样如果调用者希望作为字符串使用,就可以直接使用。 不过,目要求的是“删除数组中所有相邻重复字符”,所以如果我们处理的不是字符串,而是普通的字符数组(比如可能中间有0字符),那么添加'\0'就不合适。但是目没有明确,我们按照字符串处理。 所以,我们的函数将: 1. 处理字符数组(假设为字符串,但输入数组可能没有结束符,我们根据长度len来处理) 2. 返回新数组的长度(不包括最后添加的结束符,但是我们在新长度位置添加了结束符) 这样,调用者既可以得到新长度,也可以将结果作为字符串使用。 实现: 注意:我们直接在原数组上操作,所以不需要额外的空间(除了几个变量)。 代码: ```c #include <stdio.h> // 函数:删除相邻重复字符 // 参数:字符数组arr,数组长度len(注意:数组长度不包括结束符,即这个数组实际大小至少为len+1,因为我们要添加结束符) // 返回值:新字符串的长度(不包括结束符) int remove_adjacent_duplicates(char arr[], int len) { int newLen = 0; // 新数组的当前长度 for (int i = 0; i < len; i++) { // 如果当前新数组非空,并且当前字符等于新数组的最后一个字符,则回退(删除重复) if (newLen > 0 && arr[i] == arr[newLen - 1]) { newLen--; } else { arr[newLen] = arr[i]; newLen++; } } // 添加字符串结束符,这样arr可以作为字符串使用 arr[newLen] = '\0'; return newLen; } int main() { char arr[100]; // 假设足够大 int n; // 输入字符串 printf("请输入字符串(无空格):"); scanf("%s", arr); // 计算字符串长度 for (n = 0; arr[n] != '\0'; n++); // 调用函数 int newLen = remove_adjacent_duplicates(arr, n); printf("处理后的字符串:%s\n", arr); printf("新长度:%d\n", newLen); return 0; } ``` 注意:上面的例子中,我们假设输入没有空格,所以用`scanf("%s")`读入。实际使用时可能需要根据情况调整。 但是,目要求的是“最简单的C语言实现”,所以我们给出一个直接操作的函数,并在主函数中测试。 另外,我们注意到引用[1]中有数组输入的函数,但这里我们直接读入字符串。 这个函数的时间复杂度是O(n),空间复杂度是O(1)(除了原数组外,只用了几个变量)。 如果要求处理的是整数数组而不是字符数组,那么我们可以用同样的思想,只是比较的是整数并且不需要加结束符。但目要求的是字符数组(因为引用[2]是关于字符串的)。 所以,我们按照字符数组实现。 相关问: 1. 如果要求删除相邻重复元素直到无法删除为止(如上述算法所做),但用非栈的方式如何实现? 2. 如果数组很大,如何优化上述算法?(其实已经优化了,空间复杂度为O(1)) 3. 如果不允许修改原数组,如何实现? 我们根据要求,生成相关问: §§相关问§§ 1. 如何处理非字符数组(例如整数数组)的相邻重复元素删除? 2. 如果要求重复元素超过两次才删除(例如保留至多两次重复),如何修改函数? 3. 删除相邻重复元素算法的时间复杂度是多少?能否进一步优化? </think> ### 最简单的C语言实现:删除数组中相邻重复字符的函数 以下是一个简洁高效的C语言函数实现,用于删除字符数组中所有**相邻重复**的字符: ```c #include <stdio.h> // 删除相邻重复字符的函数 int removeAdjacentDuplicates(char arr[], int len) { if (len <= 1) return len; // 长度≤1时无需处理 int newLen = 0; // 新数组的当前位置 for (int i = 1; i < len; i++) { // 当前字符与前一个字符比较 if (arr[newLen] != arr[i]) { newLen++; // 移动新数组指针 arr[newLen] = arr[i]; // 保留非重复字符 } } arr[newLen + 1] = '\0'; // 添加字符串结束符 return newLen + 1; // 返回新长度 } int main() { char str[] = "aabbccddeeff"; // 测试字符串 int len = sizeof(str) - 1; // 计算长度(排除'\0') printf("原始: %s\n", str); int newLen = removeAdjacentDuplicates(str, len); printf("结果: %s (长度: %d)\n", str, newLen); return 0; } ``` #### 算法说明: 1. **双指针原地操作** 使用`newLen`作为新数组的指针,`i`遍历原数组。时间复杂度 $O(n)$,空间复杂度 $O(1)$ [^1] 2. **核心逻辑** - 当 `arr[newLen] == arr[i]` 时跳过(相邻重复) - 当字符不同时,将 `arr[i]` 复制到 `newLen+1` 位置 3. **边界处理** - 长度 ≤1 时直接返回 - 结果末尾添加 `\0` 保证字符串有效性 #### 测试示例: 输入 | 输出 | 新长度 -----|------|------- `"aabbcc"` | `"abc"` | 3 `"112233"` | `"123"` | 3 `"AABBA"` | `"ABA"` | 3 > 注意:此函数直接修改原始数组,并通过返回值给出新长度。若需要保留原数组,可先创建副本再处理 [^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值