首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言字串刪除指定字符:高效 O(n) 原地算法實現

     編輯:關於C語言

在字串 A 中刪除所有出現在字串 B 中的字符,是經典的字串處理面試題。本文提供O(n + m) 時間、O(1) 空間的原地刪除算法,附完整代碼與關鍵技巧解析。

問題定義

  • 輸入:字串 A (可修改)、字串 B (刪除字符集)
  • 輸出:修改後的 A,移除所有 B 中出現的字符
  • 範例:A = "hello world", B = "ewd" → A = "hllo orl"

核心算法:查找表 + 雙指針原地覆蓋

void deleteWord(char *dest, char *word) {
    int len1 = strlen(dest);
    int len2 = strlen(word);

    // 1. 建立字符查找表 (ASCII 256)
    int lookup[256] = {0};
    for (int i = 0; i < len2; i++)
        lookup[(unsigned char)word[i]] = 1;  // 標記需刪除字符

    // 2. 雙指針原地覆蓋
    int write_idx = 0;
    for (int read_idx = 0; read_idx < len1; read_idx++) {
        if (!lookup[(unsigned char)dest[read_idx]]) {
            dest[write_idx++] = dest[read_idx];  // 保留字符前移
        }
    }
    dest[write_idx] = '\0';  // 新字串結束
}

關鍵技巧解析

完整可運行程式

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void deleteWord(char *dest, char *word) {
    int len1 = strlen(dest);
    int len2 = strlen(word);
    int lookup[256] = {0};
    for (int i = 0; i < len2; i++)
        lookup[(unsigned char)word[i]] = 1;
    int write_idx = 0;
    for (int read_idx = 0; read_idx < len1; read_idx++) {
        if (!lookup[(unsigned char)dest[read_idx]])
            dest[write_idx++] = dest[read_idx];
    }
    dest[write_idx] = '\0';
}

int main() {
    char a[] = "hello world";
    char b[] = "ewd";
    printf("Input A: %s\n", a);
    printf("Input B: %s\n", b);
    deleteWord(a, b);
    printf("After delete: %s\n", a);  // 輸出: hllo orl
    return 0;
}

原文代碼問題分析

原文使用後移法:刪除字符時將後續所有字符向前移一位:

// 原文做法:刪除時後移
if (lookup[dest[j]]) {
    for (int i = j; i < len1 - 1; i++)
        dest[i] = dest[i+1];
    dest[len1-1] = '\0';
    j--; len1--;  // 補償索引與長度
}

缺點:最壞情況 (全刪除) 時間複雜度 O(n²),每次刪除移動 O(n) 字符。雙指針法嚴格 O(n),且代碼更簡潔。

擴展場景

  • Unicode/多位元組字符:需改用哈希表或 Trie 存儲刪除集,按字符而非位元組處理
  • 大小寫不敏感:建表時統一轉大寫/小寫,查詢時同樣轉換
  • 刪除子串而非單字符:需 KMP/BM 算法定位子串,再用雙指針覆蓋
  • C++ string 版本:
    void deleteChars(string &s, const string &chars) {
        bool lookup[256] = {false};
        for (unsigned char c : chars) lookup[c] = true;
        size_t w = 0;
        for (size_t r = 0; r < s.size(); r++)
            if (!lookup[(unsigned char)s[r]]) s[w++] = s[r];
        s.resize(w);
    }

複雜度總結

技巧作用
unsigned char 強制轉型避免負索引 (char 有無號實現相關),安全訪問 lookup[0~255]
查找表 lookup[256]O(1) 判斷字符是否在刪除集,空間固定 256 int
雙指針 read_idx/write_idx原地覆蓋,無需額外緩衝區,單次遍歷完成
最終補 '\0'正確終止新字串,避免殘留舊字符
算法時間空間備註
後移法 (原文)O(n²)O(1)簡單但低效
雙指針 + 查找表 (本文)O(n + m)O(1) (256 int)最優解
新建字串O(n + m)O(n)簡單但額外空間

掌握查找表 + 雙指針原地覆蓋模式,可解決「過濾/刪除/保留字符」大類問題,是字串處理的核心套路。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved